# users-admin Specification ## Purpose Администрирование доступа: пользователи, назначение ролей и матрица «роль × право» как данные (`role_permission`), с аудитом; минимальный экран администратора во фронте. ## Requirements ### Requirement: Пользователи — список, создание, изменение, деактивация Маршруты `/api/v1/admin/users` (право `USERS_ADMIN`): `GET` — список с ролями и филиалом (поиск по email/ФИО, фильтр `is_active`, пагинация); `POST` — создание с обязательными `email` (уникален без учёта регистра → 409 `EMAIL_EXISTS`), `full_name`, `regional_office_id`, необязательными `employee_no`, `business_segment`, `roles` (коды); `PATCH …/{id}` — `full_name`, `employee_no`, `regional_office_id`, `business_segment`, `is_active`. Удаление MUST NOT предоставляться. `external_id` через API не задаётся. Каждая мутация пишет `audit_event(USER_CHANGE, section = USERS)`. #### Scenario: Создание с ролью - **WHEN** администратор создаёт пользователя с `roles = ["KA_RF"]` - **THEN** появляются `app_user` и `user_role`, `GET /me` от его имени (dev-токен) возвращает права `KA_RF` #### Scenario: Email в другом регистре - **WHEN** создаётся пользователь с email, отличающимся от существующего только регистром - **THEN** ответ 409 `EMAIL_EXISTS` ### Requirement: Назначение ролей `PUT /api/v1/admin/users/{id}/roles` (тело: список кодов) SHALL заменять набор ролей пользователя: отсутствующие в наборе назначения удаляются, новые добавляются; неизвестный или неактивный код роли → 422; пишется `audit_event(USER_ROLE_CHANGE, before_value = прежний набор, after_value = новый)`. Замена набора ролей MUST NOT оставить систему без активного пользователя с `USERS_ADMIN` (409 `LAST_ADMIN`): администратор не может снять с себя последнюю роль, дающую `USERS_ADMIN`, если он — единственный активный обладатель этого права; при наличии другого активного администратора снятие у себя разрешено (решение №34). #### Scenario: Замена набора ролей - **WHEN** у пользователя роли `[KA_RF]`, администратор ставит `[KA_GO, EXPERT]` - **THEN** `user_role` содержит ровно две новые строки, в аудите `before_value = ["KA_RF"]`, `after_value = ["KA_GO","EXPERT"]` #### Scenario: Последний администратор - **WHEN** единственный активный пользователь с `USERS_ADMIN` снимает с себя роль `ADMIN` - **THEN** ответ 409 `LAST_ADMIN`, роли не изменены ### Requirement: Матрица прав `GET /api/v1/admin/roles` SHALL отдавать роли с их правами; `GET /api/v1/admin/permissions` — справочник прав (16 кодов, только чтение; создание прав MUST NOT предоставляться); `PUT /api/v1/admin/roles/{code}/permissions` (тело: список кодов прав) SHALL заменять набор прав роли и писать `audit_event(ROLE_PERMISSION_CHANGE)` с before/after. Системные роли (`is_system`) нельзя деактивировать или переименовать; нельзя снять `USERS_ADMIN` с роли, если после этого ни у одного активного пользователя не останется этого права (409 `LAST_ADMIN`). #### Scenario: Изменение матрицы - **WHEN** у роли `EXPERT` добавляется право `EXPORT` - **THEN** `role_permission` содержит новую строку, пользователь с ролью `EXPERT` при следующем запросе `/me` видит `EXPORT`, в аудите `ROLE_PERMISSION_CHANGE` #### Scenario: Снятие USERS_ADMIN с единственной роли - **WHEN** у роли `ADMIN` (единственной с `USERS_ADMIN` у активных пользователей) убирают `USERS_ADMIN` - **THEN** ответ 409 `LAST_ADMIN` ### Requirement: Минимальный экран администратора SPA SHALL содержать маршрут `/admin` (пункт «Система → Пользователи и роли» в боковом меню), доступный при наличии `USERS_ADMIN` в ответе `/api/v1/me`: таблица пользователей с выбором ролей и формой создания, таблица «роль × право» с чекбоксами и кнопкой сохранения; запросы идут через общий API-клиент с заголовком `Authorization: Bearer`. В режиме разработки SHALL быть доступен ввод email для получения dev-токена (`POST /api/v1/dev/token`); в сборке для прода этот ввод отсутствует. #### Scenario: Назначение роли через экран - **WHEN** администратор на `/admin` выбирает пользователю роль `KA_GO` и сохраняет - **THEN** вызывается `PUT /admin/users/{id}/roles`, таблица показывает новую роль, ошибка API показывается уведомлением #### Scenario: Нет права - **WHEN** пользователь без `USERS_ADMIN` открывает `/admin` - **THEN** страница показывает сообщение об отсутствии доступа и не делает запросов к `/admin/*` ### Requirement: Краткий справочник пользователей `GET /api/v1/users/brief?ids=,…` SHALL быть доступен любому аутентифицированному пользователю без отдельного права и отдавать `[{id, full_name, is_active}]` для найденных id, включая неактивных; неизвестные id MUST NOT возвращаться и MUST NOT давать ошибку; больше 200 id — 422 `TOO_MANY_IDS`; некорректный UUID — 422. Админский список пользователей не меняется. #### Scenario: Имя загрузившего - **WHEN** аналитик без права `USERS_ADMIN` запрашивает `ids` из `uploaded_by` двух файлов и неизвестный UUID - **THEN** 200, два элемента с ФИО, неизвестный UUID отсутствует #### Scenario: Слишком много id - **WHEN** передан 201 id - **THEN** 422 `TOO_MANY_IDS`