feat(tradein/team): team-management API — employees CRUD, quotas, stats (#2554) #2563

Merged
lekss361 merged 2 commits from feat/tradein-team-api into main 2026-07-30 18:38:26 +00:00

2 commits

Author SHA1 Message Date
bot-backend
4ac3971061 fix(tradein/team): revoke сессий при смене пароля + Origin-check + батч-квоты (#2554)
All checks were successful
CI Trade-In / changes (pull_request) Successful in 10s
CI / changes (pull_request) Successful in 11s
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 1m56s
Deep-review PR #2563:
- HIGH: PATCH new_password не ревокал старые сессии сотрудника — sliding-refresh
  продлевал скомпрометированную/чужую сессию бесконечно. Теперь revoke_user_sessions
  вызывается при is_active=False ИЛИ new_password (self-lockout невозможен —
  _fetch_employee_row фильтрует role='employee').
- Medium1: Origin/Referer-check (защита CSRF) на POST/PATCH team-роутах против
  settings.cors_origins; оба заголовка отсутствуют (curl-смоук внутри контейнера) —
  пропускаем, не ломаем прод-смоук.
- Medium2: батч-квота для GET /employees (_batch_quota_status) — было 2N+3 SQL-запросов
  на N сотрудников, стало 5 плоско (замерено: N=10 -> 5 запросов). Добавлена пагинация
  limit(default 50, max 200)/offset.
- Заодно: статические WHERE-ветки вместо f-string-сборки в list_employees;
  monthly_limit теперь сбрасывает account_quota_overrides.unlimited=false и не
  затирает существующий note.
2026-07-30 21:23:32 +03:00
bot-backend
712c56f456 feat(tradein/team): team-management API — employees CRUD, quotas, stats (#2554)
All checks were successful
CI Trade-In / changes (pull_request) Successful in 10s
CI / changes (pull_request) Successful in 8s
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 1m47s
Session-only identity (current_team_actor, admin|manager) поверх tradein_users/
tradein_sessions (#2552 foundation). Org-изоляция manager <-> employee через
manager_id: чужой/несуществующий employee_id -> 404 (не 403 — не палим
существование), POST с чужим manager_id в теле от manager игнорируется
(принудительно свой id). Квота — upsert в account_quota_overrides (существующий
паттерн, без правки account_quota.py). История оценок — user_events LEFT JOIN
trade_in_estimates. Team-события (employee_created/blocked/unblocked/
password_reset/quota_changed) без пароля в payload.
2026-07-30 20:51:31 +03:00