Перейти к основному содержимому

Аудит действий пользователей

В admin-gui-backend аудит пользовательских действий отправляется через пакет ensi/action-audit-event-producer в центральный сервис action-audit по Kafka.

Когда добавлять аудит

Добавляйте аудит для любого запроса, который меняет состояние данных:

  • создание, обновление, удаление, замена;
  • смена статусов и других значимых признаков;
  • прикрепление и удаление файлов или связей;
  • массовые операции;
  • авторизационные действия, если они важны для трассировки, например вход и выход;
  • изменение настроек.

Не добавляйте аудит для чтения данных:

  • поиск, списки, получение записи, meta-эндпоинты;
  • запросы на получение enum-значений;
  • вспомогательные эндпоинты, которые не меняют состояние.

В текущем сервисе аудит вызывается в HTTP-контроллерах, а не в доменных actions.

Как работает пакет

  • AuditEvent::log() добавляет событие во внутреннюю очередь в памяти.
  • Очередь автоматически отправляется в фазе Laravel terminating.
  • Отправка происходит после того, как ответ уже возвращён клиенту.
  • Если AUDIT_EVENTS_ENABLED=false, вызов AuditEvent::log() ничего не делает.

Не вызывайте flush() вручную в коде сервиса.

Что уже настроено в сервисе

Пакет уже подключён и настроен:

  • в AppServiceProvider AuditResolversInterface привязан к App\Domain\Audit\AuditResolver;
  • config/audit-event-producer.php читает переменные:
    • AUDIT_EVENTS_ENABLED
    • AUDIT_EVENTS_SYSTEM_CODE
    • AUDIT_EVENTS_KAFKA_TOPIC
    • AUDIT_EVENTS_CACHE_STORE
  • в config/kafka.php ключ audit-events сопоставлен с Kafka topic сервиса action-audit.

Если вы добавляете новый environment или deployment profile, проверьте, что эти настройки там тоже присутствуют.

Как вызывать аудит

Используйте facade:

use Ensi\ActionAuditEventProducer\AuditEvent;
use Ensi\ActionAuditEventProducer\DTOs\PerformerDto;

AuditEvent::log(
actionType: AuditActions::ORDERS_PATCH->value,
entityType: AuditEntityType::ORDER->value,
entityId: (string) $id,
entityTitle: fn () => $order->order->getNumber(),
context: fn () => $request->validated(),
);

Правила по параметрам:

  • actionType обязателен, значение берём из App\Domain\Audit\Enums\AuditActions;
  • entityType необязателен, значение берём из App\Domain\Audit\Enums\AuditEntityType;
  • entityId передаём строкой;
  • entityTitle необязателен, должен возвращать короткий человекочитаемый заголовок;
  • context необязателен, должен возвращать небольшой массив с важными деталями изменения;
  • performer необязателен и нужен только тогда, когда стандартный authenticated user не является реальным исполнителем действия.

entityTitle и context передаются как Closure. Они вычисляются только в момент flush, поэтому внутри них не должно быть побочных эффектов и тяжёлой логики.

Когда передавать performer явно

Для обычных authenticated requests performer не передаём. По умолчанию пакет берёт исполнителя через App\Domain\Audit\AuditResolver.

Явный PerformerDto используйте только тогда, когда действие совершает не пользователь из текущего запроса. Текущий пример в сервисе - логин:

AuditEvent::log(
AuditActions::AUTH_LOGIN->value,
context: fn () => [
'ip' => $request->ip(),
'user-agent' => $request->userAgent(),
],
performer: new PerformerDto($request->getLogin()),
);

Как заводить новые action и entity

Если вы добавляете новое аудитируемое действие или новый тип сущности:

  1. Добавьте новый case в App\Domain\Audit\Enums\AuditActions или AuditEntityType.
  2. Добавьте переводы в:
    • resources/lang/en/audit-actions.php
    • resources/lang/ru/audit-actions.php
    • resources/lang/en/audit-entities.php
    • resources/lang/ru/audit-entities.php
  3. Используйте новый enum value в контроллере.

AuditResolver читает эти файлы переводов и отправляет локализованные имена в аудит.

Где размещать вызов

Ставьте AuditEvent::log() рядом с изменяющим состояние действием в контроллере. Общий порядок такой:

  1. выполнить domain action;
  2. записать аудит по данным из запроса или по результату действия;
  3. вернуть response.

Типичные примеры в сервисе:

  • создание, изменение и удаление покупателей;
  • patch заказов и операции с позициями или файлами заказа;
  • изменения в CMS и каталоге;
  • изменения в управлении пользователями и ролями;
  • изменение настроек аудита.

Что класть в payload

Payload должен быть компактным и полезным:

  • включайте только то, что помогает понять что именно изменилось;
  • предпочитайте ID, коды, номера и короткие заголовки;
  • не передавайте пароли, токены, секреты и слишком большие структуры.