Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
70 lines
6.3 KiB
Markdown
70 lines
6.3 KiB
Markdown
# 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/*`
|