Files
state-corp-backend/docs/employee-deletion-api-ru.md
Aleksandr Meshchryakov e99616ed6d
All checks were successful
State Corp Backend CI/CD / Quality gate (push) Successful in 2m42s
State Corp Backend CI/CD / Build linux/amd64 images once (push) Successful in 5m29s
State Corp Backend CI/CD / Refresh and release internal main (push) Has been skipped
State Corp Backend CI/CD / Release customer main (push) Has been skipped
State Corp Backend CI/CD / Release dev (push) Successful in 36s
feat(users): add transactional employee deletion and token revocation
2026-09-13 22:55:31 +02:00

99 lines
7.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Полное удаление сотрудника
Администратор может полностью удалить аккаунт сотрудника через существующий
маршрут управления пользователями:
```http
DELETE /api/v1/users/admin/users/{user_id}/
Authorization: Bearer <access-token>
```
Тело запроса не требуется. Успех — `204 No Content` без JSON-тела. Сотрудник
исчезает из списка, поиска и карточки; повторный DELETE возвращает 404.
Деактивация и обратная активация остаются отдельными операциями.
## Права и ошибки
Право удаления имеет существующий активный пользователь с `is_staff=True`,
как и для остальных административных endpoint'ов. Проверка повторяется внутри
транзакции после получения блокировок: ранее аутентифицированный, но уже удалённый
или лишённый прав администратор не может завершить изменение.
| HTTP | Код ошибки | Значение |
|---|---|---|
| 400 | `self_delete_forbidden` | Нельзя удалить самого себя |
| 401 | Стандартная ошибка аутентификации | Нет действующего access token |
| 403 | Стандартная ошибка прав / `permission_denied` | Требуется активный администратор |
| 404 | `not_found` | Сотрудник отсутствует, в том числе после удаления |
| 409 | `last_active_admin` | Нельзя оставить систему без активного администратора |
| 409 | `user_delete_conflict` | Защищённая связь препятствует удалению |
Ошибки используют стандартный envelope проекта: `success: false`, `data: null`,
`errors: [{code, message}]`, `meta`. Запрет удаления себя имеет приоритет над
проверкой последнего администратора. Существующие связи не блокируют удаление;
409 для защищённой связи сохраняет безопасное поведение при расширении модели.
DELETE, создание аккаунта администратором, смена роли/активности и соответствующие
операции Django admin используют одни блокировки пользователей. Пакетное действие
Django admin атомарно: если
выбран сам исполнитель, вся операция отклоняется.
Сохранение собственных учётных данных и смена пароля также блокируют актуальную
строку User, чтобы начавшийся до DELETE запрос не создал аккаунт заново.
## Данные после удаления
- Физически удаляются User, Profile, связи с группами/permissions, записи
OutstandingToken и связанные BlacklistedToken. Сами справочники прав остаются.
- Отчёты ReportUpload, загрузки реестров RegisterUpload, ExchangePackageImport
сохраняются; их ссылки на автора обнуляются штатным SET_NULL. Сохраняются
загруженные файлы, предметные данные и цепочки импортов.
- BackgroundJob сохраняются, `user_id` очищается явно, поскольку это integer,
а не внешний ключ. Выполняющиеся задачи не отменяются.
- Аватар удаляется из storage после commit, если его не использует другой
профиль. При ошибке storage удаление аккаунта остаётся успешным, ошибка
регистрируется в серверном журнале для последующей очистки файла.
- Технический Django admin LogEntry сохраняет штатный CASCADE для записей,
исполнителем которых был удалённый пользователь; предметные журналы выше
не удаляются. Содержимое исторических документов не переписывается.
- Старый access перестаёт проходить JWTAuthentication. Refresh endpoint
дополнительно проверяет существование и активность пользователя и возвращает
401 для удалённого/неактивного аккаунта. Повторный refresh активного пользователя
поддерживается как раньше. Записей восстановления пароля в текущей модели нет.
Изменений схемы БД и миграций не требуется. Откат версии приложения не
восстанавливает уже удалённые аккаунты.
## Передача frontend-разработчику (Глебу)
1. Добавить отдельное действие «Удалить» в меню сотрудника; для текущего
пользователя скрыть или отключить его.
2. Перед запросом показать имя выбранного сотрудника и подтверждение полного
необратимого удаления аккаунта. Сообщить, что отчёты и история импортов останутся.
3. Вызвать DELETE; на время запроса блокировать повторное действие. После 204
закрыть диалог и обновить список/счётчик; если последняя строка страницы удалена,
перейти на предыдущую существующую страницу.
4. Обработать стандартный error envelope, включая 400/403/404/409. При 404 обновить
список. Не пытаться читать JSON из успешного ответа 204.
5. Обновить клиент из OpenAPI и проверить удаление обычного, неактивного и другого
административного аккаунта, запрет удаления себя и потерю прав во время запроса.
## Проверка backend
```bash
PYTHONPATH=src uv run --no-sync pytest tests/apps/user
```
Восемь тестов `test_management_concurrency.py` пропускаются SQLite и требуют
PostgreSQL. Для них использовать отдельную пустую тестовую БД и явно задавать все
`TEST_POSTGRES_HOST`, `TEST_POSTGRES_PORT`, `TEST_POSTGRES_USER`,
`TEST_POSTGRES_PASSWORD`, `TEST_POSTGRES_DB`, чтобы исключить fallback к рабочей БД:
```bash
scripts/run-tests-prod.sh ../tests/apps/user
```
Регрессии обмена и подготовленных выгрузок находятся в
`tests/apps/exchange/test_api.py`, `tests/apps/external_data/test_source_record_export.py`
и `tests/apps/external_data/test_export_tasks.py`. Изменений upload/export API эта
доработка не вносит.