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

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

В 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, коды, номера и короткие заголовки;
  • не передавайте пароли, токены, секреты и слишком большие структуры.