Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
4.6 KiB
audit-trail Specification
Purpose
Все действия из enum audit_action пишутся в audit_event одним способом — через сервис аудита; журнал только
дополняется, записи неизменяемы (ТЗ 8.2).
Requirements
Requirement: Единая точка записи
Сервис аудита SHALL предоставлять метод записи события с полями action (из enum audit_action), section
(из audit_section), object_type, object_id, user_id (NULL для системных действий), consolidation_version_id,
description, before_value, after_value (jsonb), comment, result, changed_field, ip_address, user_agent;
occurred_at SHALL проставляться сервером (UTC). Запись SHALL выполняться в той же транзакции, что и изменение данных.
NOTE: В Срезе 0 обмен через recognition_job аудит не пишет (рулинг R-7, design #20); сервис готов к использованию Срезом 2+.
Scenario: Системное событие
- WHEN системный процесс (без пользователя) вызывает сервис аудита
- THEN в
audit_eventпоявляется строка сuser_id = NULL,before_value/after_valueсодержат старый и новый статус
Scenario: Откат транзакции
- WHEN изменение данных и запись аудита выполняются в одной транзакции, и она откатывается
- THEN строка
audit_eventне сохраняется
Requirement: Журнал только дополняется
ORM-модель audit_event MUST NOT использоваться для UPDATE или DELETE в коде ядра; тест SHALL проверять, что в
src/ нет обращений, изменяющих или удаляющих audit_event, а сервис аудита не имеет методов изменения.
Scenario: Попытка изменить запись
- WHEN код вызывает обновление строки
audit_eventчерез сервис аудита - THEN такого метода нет (ошибка на этапе типизации/теста), запись остаётся прежней
Requirement: События справочников, импорта и администрирования
Каждая мутация справочников, импорт и каждое действие администратора SHALL писать audit_event через сервис аудита в
той же транзакции с user_id инициатора, ip_address и user_agent запроса:
| Действие | action |
section |
object_type |
|---|---|---|---|
| создание/изменение/архив ГК | GROUP_CHANGE |
DIRECTORIES |
company_group |
| смена филиала ГК | ASSIGNMENT_CHANGE |
DIRECTORIES |
company_group |
| создание/изменение/перевод/закрытие ЮЛ, алиасы | LEGAL_ENTITY_CHANGE |
DIRECTORIES |
legal_entity / legal_entity_alias |
| ГСК/ГСЗ и их состав | MEMBERSHIP_CHANGE |
DIRECTORIES |
related_group / related_group_member |
| импорт выгрузки | DIRECTORY_IMPORT |
DIRECTORIES |
directory_import |
| пользователь создан/изменён/деактивирован | USER_CHANGE |
USERS |
app_user |
| роли пользователя | USER_ROLE_CHANGE |
USERS |
app_user |
| права роли | ROLE_PERMISSION_CHANGE |
ACCESS |
role |
before_value/after_value SHALL содержать изменённые поля (для списков — весь набор до и после); changed_field —
имя поля при изменении одного поля.
Scenario: Изменение имени ГК
- WHEN имя ГК меняется с «А» на «Б»
- THEN в
audit_eventстрокаGROUP_CHANGEсchanged_field = "name",before_value = {"name": "А"},after_value = {"name": "Б"},user_idинициатора
Scenario: Откат мутации справочника
- WHEN транзакция перевода ЮЛ откатывается
- THEN строки
LEGAL_ENTITY_CHANGEиMEMBERSHIP_CHANGEвaudit_eventотсутствуют