# План Разработки (Execution Plan)

## Назначение
Этот файл фиксирует последовательность работ до завершения проекта.
Используется ИИ-агентом как рабочий чеклист реализации.

## Правило статусов
- `сделано` — реализовано в коде, покрыто тестами или подтверждено рабочим сценарием.
- `к разработке` — еще не реализовано полностью или реализовано как заглушка.

## Порядок выполнения
Работы выполняются строго сверху вниз по `ID`.
Переход к следующему пункту возможен только после:
1. Обновления кода.
2. Обновления/добавления тестов.
3. Проверки `unittest` и миграций.
4. Обновления контекста (`context/*.md`) при изменении требований.

## Дорожная карта
| ID | Статус | Блок | Задача для ИИ-агента                                                                                                                                                                           | Критерий готовности |
|---|---|---|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---|
| P01 | сделано | База проекта | Поднять базовую архитектуру FastAPI + PostgreSQL + Redis + Celery + админку и лендинг                                                                                                          | API запускается, миграции применяются, базовые страницы доступны |
| P02 | сделано | Модели и миграции | Создать основные таблицы (`requests`, `topics`, `statuses`, `form_fields`, `messages`, `attachments`, `status_history`, `audit_log`, `admin_users`, `otp_sessions`, `quotes`) + системные поля | Миграции `0001-0003` проходят, тесты миграций зеленые |
| P03 | сделано | Универсальный CRUD | Реализовать универсальный CRUD + RBAC по таблицам + аудит изменений                                                                                                                            | CRUD работает для справочников и пользователей, аудит пишется |
| P04 | сделано | Пользователи и роли | CRUD пользователей, хеширование паролей, роль `ADMIN/LAWYER`, профильная тема (`primary_topic_code`)                                                                                           | Тесты на CRUD пользователей и пароли проходят |
| P05 | сделано | Базовый auto-assign | Реализовать автоназначение через 24 часа по профильной теме и активной нагрузке                                                                                                                | `auto_assign_unclaimed` назначает корректно, тесты проходят |
| P06 | сделано | Базовая админ-панель | Перевод `admin.html` -> `admin.jsx`, универсальные таблицы/модалки/фильтры                                                                                                                     | Работа с сущностями через единый UI доступна |
| P07 | сделано | Темы юриста (расширение) | Добавить связующую таблицу `admin_user_topics` для дополнительных тем юриста; обновить CRUD/UI/фильтры                                                                                         | У юриста: 1 основная + N дополнительных тем; выбор тем в UI и в API |
| P08 | сделано | Назначение заявок (ручное) | Добавить endpoint «Взять в работу» для юриста с атомарной блокировкой (без гонок), только если заявка не назначена                                                                             | Два юриста не могут одновременно взять одну заявку; takeover запрещен |
| P09 | сделано | Переназначение | Добавить ADMIN-only ручное переназначение уже назначенной заявки                                                                                                                               | Юрист не может перехватывать назначенные заявки, админ может переназначить |
| P10 | сделано | Алгоритм auto-assign v2 | Доработать автоназначение: приоритет `primary_topic` -> `admin_user_topics` -> минимальная активная нагрузка (`is_terminal=false`)                                                             | Воркеры и тесты покрывают новый приоритет и edge-cases |
| P11 | сделано | OTP create/view | Внедрить полноценный OTP-поток: OTP обязателен для создания заявки и просмотра по `track_number`, cookie JWT 7 дней                                                                            | Без OTP нельзя создать/смотреть заявку; повторный OTP не нужен при валидной cookie |
| P12 | сделано | Публичный кабинет клиента | Реализовать публичные endpoints и UI: просмотр статуса, чат, файлы, история изменений по `track_number`                                                                                        | Клиент может вести диалог и видеть прогресс заявки в одном контуре |
| P13 | сделано | Read/unread маркеры | Добавить request-level маркеры «есть обновления» для клиента/юриста; открытие заявки сбрасывает маркер; одноразовая зеленая точка типа события                                                 | В списке заявок корректно отображаются непрочитанные обновления |
| P14 | сделано | Статусные флоу по темам | Добавить настройку линейных флоу с допустимыми вариациями переходов (Jira-like), валидировать переходы                                                                                         | Нельзя выполнить переход вне разрешенной цепочки |
| P15 | сделано | Иммутабельность по статусам | На смене статуса «замораживать» сообщения и вложения предыдущих статусов + писать `status_history`                                                                                             | Попытка изменения старых сообщений/файлов отклоняется API |
| P16 | сделано | Шаблоны данных | Разделить шаблоны: (1) обязательные поля создания по теме; (2) шаблон дозапроса документов в работе, расширяемый юристом только для текущей заявки                                             | Админ настраивает базу, юрист расширяет только в рамках конкретной заявки |
| P17 | сделано | Файловый контур | Довести загрузку/скачивание файлов: лимиты 25MB/файл и 250MB/заявка, хранение метаданных, контроль суммарного объема                                                                           | Лимиты enforced сервером, загрузки и скачивание стабильны |
| P18 | сделано | SLA-конфиг | Настройка SLA на каждый переход статуса для каждой темы                                                                                                                                        | SLA-конфиг хранится в БД, валидируется в админке |
| P19 | сделано | SLA-check и overdue | Реализовать `sla_check`: контроль просрочек по переходам, расчет FRT/времени в статусе                                                                                                         | Метрики и флаги просрочек обновляются по расписанию |
| P20 | сделано | Уведомления | Уведомления в Telegram (если подключен) + внутренние уведомления сайта по изменениям                                                                                                           | При событиях (сообщения/файлы/статусы/SLA) уведомления доставляются |
| P21 | сделано | Dashboard LAWYER/ADMIN | Расширить дашборды: назначенные/неназначенные, активные по статусам, непрочитанные, SLA, по каждому юристу: активная загрузка, сумма активных заявок, вал оплаченных за месяц, зарплата за месяц | Дашборды соответствуют ролям и данным из БД |
| P22 | сделано | Hardening/release | Полировка безопасности, логирования, лимитов, отказоустойчивости, документации API/UI и runbook                                                                                                | Проект готов к стабилизации и приемке |
| P23 | сделано | Mobile UX | Мобильная адаптация лендинга и клиентских форм (заявка, OTP, кабинет клиента: чат, файлы, история)                                                                                               | UI корректно работает на 320-768px, элементы доступны и читаемы без горизонтального скролла |
| P24 | сделано | Тарифы юристов | Добавить ставку и процент юриста (по умолчанию в профиле), а также фиксируемые в заявке поля ставки/суммы (override админом)                                                                      | Финансовые поля заявки фиксируются и не зависят от последующих правок профиля; клиенту не показываются |
| P25 | сделано | Биллинг-статус | Добавить тип статуса «выставление счета»: генерация счета из шаблона, отправка клиенту и фиксация события оплаты по смене статуса администратором на `Оплачено`                                 | Для темы можно включить billing-этап, счет формируется и доставляется; факт оплаты фиксируется по событиям `Оплачено` (возможны множественные события в одной заявке) |
| P26 | сделано | Security Audit | Внедрить аудит безопасности и защиту ПДн для S3/файлов по требованиям РФ и кибербезопасности                                                                                                    | Реализован журнал доступа, шифрование, RBAC/least-privilege, политика хранения и контроль инцидентов |
| P27 | сделано | Итоговое тестирование E2E | Покрыть ключевые бизнес-сценарии: OTP, claim, auto-assign v2, чат, файлы, SLA, уведомления, read markers и выполнить финальный регрессионный прогон                                             | Набор автотестов фиксирует регрессии критичных сценариев и подтверждает готовность перед приемкой |
| P28 | сделано | Справочники: все таблицы БД | Обеспечить отображение в «Справочниках» всех таблиц БД (кроме выделенных разделов «Заявки» и «Счета»), включая `clients` при наличии отдельной таблицы клиентов                                    | Создана таблица `clients` через миграцию, добавлены ссылки в `requests`/`invoices`, справочник `clients` доступен через universal meta |
| P29 | сделано | Модальная форма заявки | Оставить создание заявки только в модальном окне; убрать дублирующие/вводящие в заблуждение блоки с формы и лендинга, вернуть явный выбор темы обращения                                           | На лендинге модалка создания заявки содержит выбор темы; блок и поле рекомендаций удалены |
| P30 | сделано | Отдельная страница клиента | Вынести работу с заявкой клиента (статус, чат, файлы, счета, таймлайн) на отдельную страницу, а не в нижний блок лендинга                                                                          | Реализована отдельная страница `client.html` с полным рабочим контуром заявки |
| P31 | сделано | Вход клиента через OTP-модалку | Добавить на лендинг кнопку перехода в страницу работы с заявкой через модалку авторизации: телефон + OTP (если нет валидной 7-дневной cookie/JWT)                                                   | На лендинге добавлена OTP-модалка входа по телефону; при валидной сессии переход в клиентскую страницу выполняется сразу |
| P32 | сделано | Переключение между заявками клиента | Спроектировать и реализовать переключение между несколькими заявками авторизованного клиента на странице работы с заявкой                                                                             | На странице клиента добавлен селектор «Мои заявки» и серверный endpoint `/api/public/requests/my` |
| P33 | сделано | Выделенный сервис чата | Выделить чат (клиент↔юрист) в отдельный сервис/контур с API-границей, сохранив текущие бизнес-правила, RBAC и read/unread поведение                                                                  | Добавлен отдельный сервисный слой `chat_service` и отдельные API-контуры `/api/public/chat/*`, `/api/admin/chat/*`; UI и тесты переведены и проходят |
| P34 | сделано | UX цитат в «Первая консультация» | Перенести цитаты в ненавязчивый формат внутри блока «Первая консультация», убрать визуальный шум и конкуренцию с основным CTA                                                                         | Цитаты перенесены в блок «Первая консультация» в hero-панели как компактный элемент без конкуренции с CTA |
| P35 | сделано | Предпросмотр документов | Добавить предпросмотр загруженных документов (pdf/jpg/mp4) в модальном окне или выделенной зоне страницы заявки, не ломая текущую загрузку/скачивание                                                   | Предпросмотр реализован в `client.html` и в рабочей вкладке заявки `admin.jsx` (`/admin.html?view=request&requestId=...`); сохранено действие «Открыть / скачать», добавлен backend тест inline-preview |
| P36 | сделано | Навигация в админ-панель | Убрать кнопку «Админ-панель» с лендинга, исправить редиректы/роутинг (`/admin`, `/admin.html`) чтобы не было перехода на неверный host/port                                                             | Кнопка админки удалена с лендинга; `/admin` корректно переводит на `/admin.html`; добавлен e2e smoke `admin_entry_flow` |
| P37 | сделано | Админ-авторизация и креды | Привести к единому правилу bootstrap-креды администратора (`admin@example.com` + согласованный пароль), обновить документацию/контекст и smoke-проверки логина                                          | Реализован bootstrap-login с автосозданием администратора `admin@example.com` / `admin123`; добавлены автотесты `tests/test_admin_auth.py` |
| P38 | сделано | Конструктор маршрутов статусов | Реализовать для администратора визуальный конструктор маршрутов статусов по каждой теме: вариативные переходы (в т.ч. возврат на предыдущий статус, переход в завершение и альтернативные ветки), SLA на переход, список обязательных документов/данных для закрытия шага | Добавлен UI-конструктор в справочнике переходов статусов (выбор темы, визуальные карточки статусов и исходящих переходов), расширены поля перехода (`required_data_keys`, `required_mime_types`), переходы валидируются API по требованиям шага (данные заявки + MIME вложений), добавлены backend/e2e тесты |
| P39 | сделано | Канбан по заявкам (LAWYER/ADMIN) | Реализовать канбан-доску заявок с унификацией разных статусных флоу через группы колонок (например: `Новые`, `В работе`, `Ожидание`, `Завершены`) + карточки заявок с ключевыми данными (дата создания, клиент, описание, новые сообщения/файлы, SLA deadline/дедлайн дела) | Добавлен backend endpoint `/api/admin/requests/kanban` (role-scope, группы статусов, SLA/case deadline, допустимые переходы); в `admin.jsx` добавлена секция `Канбан` с карточками, claim для юриста, drag&drop/быстрый перевод по допустимым переходам, open-in-place; покрыто unittest и e2e (`kanban_role_flow`) |
| P40 | сделано | Декомпозиция: подготовка сборки фронта | Подготовить модульную декомпозицию фронта: перевести entrypoint `admin.jsx` -> `admin/index.jsx`, включить `esbuild --bundle` в `frontend/Dockerfile`, зафиксировать совместимость `admin.html` и Docker Compose | Реализовано: добавлен `app/web/admin/index.jsx`, сборка переведена на `esbuild admin/index.jsx --bundle`, smoke e2e входа/навигации (`admin_entry_flow`) и сборка в контейнере проходят |
| P41 | сделано | Декомпозиция `admin.jsx`: shared-слой | Вынести из `admin.jsx` константы/маппинги/табличные конфиги и pure-utils (`format`, `filters`, `route`, `reference`) в отдельные модули | Реализовано: добавлены `app/web/admin/shared/constants.js`, `app/web/admin/shared/utils.js`, `app/web/admin/shared/state.js`; `admin.jsx` сокращен до ~4800 строк и использует shared-импорты; e2e smoke `admin_entry_flow`, `admin_role_flow`, `kanban_role_flow` зеленые |
| P42 | сделано | Декомпозиция `admin.jsx`: feature-слой | Разделить UI и логику на feature-модули (`kanban`, `request-workspace`, `config-dictionaries`, `invoices`, `dashboard`) + вынести кастомные hooks/services (`useAdminApi`, `useTablesState`, `useRequestWorkspace`, `useKanban`) | Корневой `App` выполняет orchestration/layout, feature-код изолирован по папкам, сценарии ADMIN/LAWYER/CLIENT не деградировали |
| P43 | сделано | Декомпозиция backend CRUD | Разбить `app/api/admin/crud.py` на модули: `router`, `access`, `meta`, `payloads`, `service`, `audit` без изменения API-контракта и RBAC | Реализован пакет `app/api/admin/crud_modules/*`, `app/api/admin/crud.py` оставлен как compatibility shim; CRUD/meta контракты и RBAC сохранены |
| P44 | сделано | Декомпозиция backend Requests | Разбить `app/api/admin/requests.py` на модули: `router`, `kanban`, `status_flow`, `data_templates`, `permissions`, `service` с сохранением текущего поведения | Реализован пакет `app/api/admin/requests_modules/*` и compatibility shim `app/api/admin/requests.py`; ключевые role-scope и CRUD/claim/reassign/data-template сценарии покрыты регресс-тестами |
| P45 | сделано | Декомпозиция тестового слоя | Разделить `tests/test_admin_universal_crud.py` на тематические пакеты (`tests/admin/*`) + вынести общие фикстуры/фабрики | Создан пакет `tests/admin/*` с общей базой `tests/admin/base.py`; сценарии запускаются по подмодулям (`test_crud_meta`, `test_lawyer_chat`, `test_status_flow_kanban`, `test_assignment_users`, `test_metrics_templates`) |
| P46 | сделано | Финализация декомпозиции | Обновить runbook/контекст по новым путям модулей и тестов, выполнить полный регрессионный прогон (unittest + e2e) и закрыть технический долг по монолитам | `context/11_test_runbook.md` актуализирован под `tests/admin/*`; выполнены прогоны: backend `133 passed`, e2e `6 passed, 1 skipped`, сборка `admin/index.jsx` успешна |
| P47 | сделано | Запросы клиента по заявке (модель/миграции) | Добавить отдельную таблицу клиентских обращений по заявке (рабочее имя таблицы: `request_service_requests`, чтобы не конфликтовать с `requests`): тип `enum` (`CURATOR_CONTACT`, `LAWYER_CHANGE_REQUEST`), статус обработки, текст обращения, ссылки на заявку/клиента/назначенного юриста, read/unread флаги для ADMIN/LAWYER/CURATOR, аудит | Реализованы модель/API/аудит, добавлены миграции `0025` + `0026` (нормализация типов link-полей в Postgres), таблица работает в runtime и тестах |
| P48 | сделано | RBAC и видимость запросов (куратор/смена юриста) | Реализовать правила видимости и доступа: запрос к куратору видят ADMIN (и будущий `CURATOR`) + назначенный юрист; запрос о смене юриста не видит назначенный юрист, видит ADMIN (и будущий `CURATOR` при включении роли); предусмотреть доступ к чату заявки для куратора и отправку сообщений от его имени | Серверно обеспечена изоляция типов для LAWYER, добавлена роль `CURATOR` в relevant endpoints (`requests/chat/metrics`) и CRUD-scope |
| P49 | сделано | Клиентский UI: запрос к куратору / смена юриста | Добавить в клиентском контуре действия: (1) запрос консультации к администратору/куратору по делу; (2) запрос о смене юриста; показывать статус обработки и связанные уведомления по заявке, не раскрывая служебные поля | В `client.html` добавлены кнопки и модалка отправки двух типов обращений, список обращений и статусов в кабинете клиента |
| P50 | сделано | Админ-панель: вкладка «Запросы» + индикатор в topbar | Добавить отдельную вкладку `Запросы` наравне с `Заявки` и `Счета`; таблица в общем стиле (фильтры/сортировка/пагинация), а также отдельную topbar-иконку (левее `!` и конверта), которая подсвечивается красным при непрочитанных запросах и открывает таблицу с фильтром по непрочитанным | Добавлены секция `Запросы`, topbar-иконка unread, quick-filter, read action и подсветка запросов в таблице `Заявки` |
| P51 | сделано | Тесты: запросы к куратору / смена юриста | Добавить backend + e2e покрытия: создание запросов клиентом, RBAC-изоляция по типам, подсветка заявок/иконки в админке, видимость для юриста/админа/куратора, доступ к чату от куратора | Добавлены backend тесты (`tests/admin/test_service_requests.py`, `tests/admin/test_metrics_templates.py`, `tests/test_public_requests.py`) и e2e-сценарий `e2e/tests/service_requests_flow.spec.js` |
| P52 | сделано | Лендинг: карусель выдающихся юристов | Добавить на лендинг карусель сотрудников (выдающиеся юристы) с фотографиями; в выдачу попадают только пользователи ролей `LAWYER`/`ADMIN`, у которых заполнен `avatar_url` (фото в профиле) | На лендинге отображается карусель карточек сотрудников с фото, именем и подписью; без фото сотрудник в карусель не попадает |
| P53 | сделано | Справочник карусели сотрудников | Добавить отдельную таблицу/справочник для управления каруселью на лендинге: ссылка на сотрудника, порядок, активность, подпись, признак закрепления (`pinned`) и CRUD в админке | Администратор может добавлять/убирать сотрудников, менять порядок, задавать подпись и `pinned`; лендинг использует этот справочник для выдачи карусели |

## Критический маршрут (обязательный порядок)
1. `P07 -> P08 -> P09 -> P10` (полный контур назначения).
2. `P11 -> P12 -> P13` (публичный клиентский контур).
3. `P14 -> P15 -> P16` (процесс работы по заявке).
4. `P17 -> P18 -> P24 -> P25 -> P19 -> P20 -> P21` (файлы, SLA, тарифы/биллинг, аналитика).
5. `P22 -> P23 -> P26 -> P27` (стабилизация, mobile UX, security-аудит, итоговые тесты в конце).
6. `P28 -> P29 -> P30 -> P31 -> P32 -> P33 -> P35 -> P34 -> P36 -> P37` (итерация UX/клиентского входа/чат-сервиса/навигации/доступов).
7. `P38 -> P39` (конструктор маршрутов и канбан-представление заявок для ролей).
8. `P40 -> P41 -> P42 -> P43 -> P44 -> P45 -> P46` (декомпозиция фронта/бэка/тестов и финальная стабилизация).
9. `P47 -> P48 -> P49 -> P50 -> P51` (контур клиентских запросов к куратору/админу и запросов на смену юриста).
10. `P52 -> P53` (карусель сотрудников на лендинге и админское управление составом/порядком).

## Детализация P38-P39 (новый контур)
### P38. Конструктор маршрутов статусов
1. Граф переходов по теме:
   хранение `from_status -> to_status`, признак `enabled`, `sort_order`, `sla_hours`.
2. Вариативные переходы:
   поддержать переходы назад, терминальные выходы и параллельные ветки.
3. Требования на шаг:
   для каждого целевого статуса хранить список обязательных документов/данных для закрытия этапа.
4. Валидация:
   серверно проверять допустимость перехода и наличие обязательных данных перед сменой статуса.
5. UI конструктора:
   визуальный редактор узлов/связей + форма параметров шага (SLA, требования, terminal).

### P39. Канбан заявок
1. Унификация статусов:
   ввести группировку статусов в канбан-колонки (`НОВЫЕ`, `В РАБОТЕ`, `ОЖИДАНИЕ`, `ЗАВЕРШЕНЫ`).
2. Маппинг:
   каждый статус темы привязать к одной канбан-группе (конфигурируемо администратором).
3. Ролевой scope:
   `LAWYER` видит свои + неназначенные заявки, `ADMIN` — все заявки всех юристов.
4. Карточка канбана:
   `track_number`, дата создания, клиент, краткое описание, индикаторы новых сообщений/файлов, SLA-дедлайн/дата дела.
5. Действия:
   перевод карточки между колонками только по допустимым серверным переходам.

## Детализация P40-P46 (декомпозиция монолитов)
### P40-P42. Фронтенд (admin)
1. Инфраструктурный шаг:
   сначала подготовить сборку под модули (`index.jsx`, `--bundle`), затем приступать к разбиению.
2. Shared-слой:
   вынести константы, конфиги таблиц/лейблов и pure-utils в `app/web/admin/*`.
3. Feature-слой:
   выделить отдельные модули и hooks для Kanban, Workspace заявки, Справочников, Счетов, Dashboard.
4. Ограничение:
   декомпозиция без изменения пользовательского поведения и API-контрактов.
5. Итог `P42`:
   вынесены feature-секции (`kanban`, `request-workspace`, `dashboard`, `requests`, `invoices`, `config-dictionaries`, `quotes`, `availableTables`, `meta`) и hooks/services (`useAdminApi`, `useKanban`, `useRequestWorkspace`, `useTablesState`, `useTableActions`, `useTableFilterActions`, `useAdminCatalogLoaders`); `admin.jsx` сокращен до orchestration/layout уровня, role e2e-регресс подтвержден.

### P43-P44. Backend (admin API)
1. Разделение `crud.py`:
   разнести права, метаданные, нормализацию payload, сервис CRUD и аудит по отдельным файлам.
2. Разделение `requests.py`:
   выделить канбан, workflow статусов, шаблоны данных, проверки прав и сервисный слой.
3. Ограничение:
   сохранить текущие URL/контракты эндпоинтов и существующую RBAC/SLA-логику.

### P45-P46. Тесты и контекст
1. Разделение тестов:
   разнести большой `test_admin_universal_crud.py` по тематическим модулям и общим helper/fixture.
2. Финальная верификация:
   обновить runbook, затем выполнить полный прогон backend + e2e перед переводом блока в `сделано`.

## Детализация P47-P51 (запросы к куратору / смена юриста)
### P47. Таблица клиентских запросов по заявке
1. Новая сущность:
   добавить отдельную таблицу (рабочее имя `request_service_requests`, чтобы не конфликтовать с `requests`).
2. Поля:
   `request_id`, `client_id`, `type(enum)`, `status(enum)`, `body`, `created_by_client`, `assigned_lawyer_id`, `resolved_by_admin_id`, `read/unread` маркеры по ролям, системные поля.
3. Типы запросов:
   `CURATOR_CONTACT`, `LAWYER_CHANGE_REQUEST`.
4. Аудит:
   создание/изменение статуса/прочтение логировать в `audit_log`.

### P48. Видимость и RBAC
1. `CURATOR_CONTACT`:
   видят ADMIN (и будущий `CURATOR`) + назначенный юрист; подсветка заявки для администратора/куратора и ведущего юриста.
2. `LAWYER_CHANGE_REQUEST`:
   не видит назначенный юрист; видит ADMIN (и будущий `CURATOR`, если роль будет добавлена).
3. Куратор:
   предусмотреть серверные точки расширения под роль `CURATOR` (даже если пока используется ADMIN как куратор).
4. Чат:
   куратор получает доступ к чтению/записи в чат заявки от своего имени по RBAC.

### P49. Клиентский UI
1. Кнопки в карточке заявки:
   «Обратиться к куратору/администратору» и «Запросить смену юриста».
2. Формы:
   модальные окна с текстом обращения, валидацией длины и подтверждением отправки.
3. Отображение:
   клиент видит только свои запросы и их статус обработки.

### P50. Админский UI
1. Новая вкладка `Запросы`:
   таблица в стиле `Заявки/Счета` (фильтр, сортировка, пагинация, server-side).
2. Topbar-иконка:
   отдельный индикатор (левее `!` и конверта), красный `unread` + переход в `Запросы` с фильтром по непрочитанным.
3. Подсветка заявок:
   заявка с открытыми клиентскими запросами должна визуально отмечаться в списке `Заявки` и/или карточке.

### P51. Тестирование
1. Backend:
   позитивные/негативные тесты по типам запросов и RBAC.
2. E2E:
   клиент создает оба типа запросов; админ видит их в новой вкладке и через topbar-иконку; назначенный юрист видит только `CURATOR_CONTACT`.
3. Corner cases:
   unread/read reset, повторные запросы, пустой/слишком длинный текст, доступ к чужой заявке.

## Детализация P52-P53 (карусель сотрудников на лендинге)
### P52. Лендинг-карусель
1. Отображение:
   карусель карточек сотрудников в блоке лендинга (UI/UX в стиле проекта, адаптивная для mobile/desktop).
2. Ограничение выборки:
   в выдачу попадают только `LAWYER`/`ADMIN` с заполненным `avatar_url`.
3. Контент карточки:
   фото, имя, подпись (из справочника карусели), при необходимости роль.
4. Сортировка:
   сначала `pinned`, затем `sort_order`.

### P53. Справочник управления каруселью
1. Новая таблица:
   отдельный справочник (например, `landing_featured_staff`) с полями: `admin_user_id`, `caption`, `sort_order`, `enabled`, `pinned` + системные поля.
2. Админский CRUD:
   универсальная таблица/форма в справочниках для добавления, удаления, редактирования и сортировки.
3. Валидация:
   серверно разрешать только сотрудников ролей `LAWYER`/`ADMIN`; при отсутствии фото элемент не попадет в публичную выдачу.
4. Публичный endpoint/выдача:
   лендинг получает отдельную публичную выборку по активным элементам карусели.

## Правила выполнения для ИИ-агента
1. Не менять бизнес-правила без обновления `context/*.md`.
2. Любую новую таблицу добавлять только через миграции + тест миграций.
3. На каждый новый endpoint добавлять позитивный и негативный автотест.
4. Для RBAC: сначала ограничить доступ, затем открывать минимально необходимое.
5. Для операций назначения использовать транзакционную защиту от гонок.
6. Для статусов и SLA использовать только серверную валидацию (не доверять фронту).
7. Перед переводом пункта в `сделано` выполнять проверки из `context/11_test_runbook.md`.
8. UI e2e запускать через фиксированный compose-сервис `e2e` (образ `law-e2e-playwright:1.58.2`) для стабильного повторяемого прогона без повторной загрузки браузеров.
