Qadam Roadmap
проектdocs/architecture/analytics-observability.md

Аналитика и observability

Обновлён 14 апр. 2026 г., 17:16 · 0 комментариев

Аналитика и observability

Паспорт документа

  • Статус документа: working reference
  • Актуально на: 28 марта 2026 года
  • Владелец: backend/platform-команда
  • Пересмотр: при изменении архитектурных решений, data layer или frontend data patterns
  • Область применения: архитектурные и интеграционные справочные документы проекта
  • Связанные документы:

Цель документа

Этот документ фиксирует текущее состояние аналитического и observability-контура Qadam: как устроены структурные логи, как работает интеграция с Axiom, как пишутся продуктовые события и где проходят границы текущей реализации.

1. Краткий вывод

В проекте уже есть рабочая база для observability и продуктовой аналитики:

  • API использует структурные JSON-логи через nestjs-pino;
  • в production поддерживается дополнительный @axiomhq/pino transport при наличии credentials;
  • HTTP-трафик и application logs проходят через единый root logger;
  • продуктовые события пишутся в append-only таблицу EventLog через Prisma;
  • есть публичный endpoint POST /api/v1/track и server-side tracking через @TrackEvent.

При этом полноценной аналитической платформы пока нет:

  • нет готового BI/dashboard-контура;
  • нет documented retention/архивации для EventLog;
  • нет выделенного consumer/job-слоя для аналитических пайплайнов;
  • нет отдельного визуального monitoring/error-tracking слоя уровня Grafana/Sentry;
  • Prometheus-compatible backend metrics baseline уже есть, но внешний uptime/TLS monitoring и alerting ещё не доведены до полного operational контура.

2. Источники данных

2.1 Структурные application и HTTP-логи

Источник: apps/api/src/app.module.ts, apps/api/src/main.ts.

Сейчас backend использует:

  • nestjs-pino;
  • pino-http;
  • pino-pretty для non-production;
  • @axiomhq/pino как optional production transport.

Логирование покрывает:

  • HTTP request/response уровень;
  • application logs из сервисов и фильтров;
  • bootstrap/runtime warnings;
  • ошибки записи событий в EventLog.

2.2 Продуктовые события

Источник: apps/api/src/modules/tracking/*, packages/shared/src/schemas/track-event.ts, packages/prisma/schema.prisma.

В проекте есть два канала продуктового трекинга:

  1. POST /api/v1/track
  2. @TrackEvent(...) + EventLogInterceptor

Оба сходятся в один write-path:

  • EventLogWriter
  • Prisma write в таблицу EventLog

Это важное архитектурное решение: независимо от того, пришло событие с клиента или было сгенерировано на сервере после успешного handler-response, запись делается через одну сервисную точку.

3. Логирование API

3.1 Pino-конфигурация

LoggerModule.forRoot(...) регистрируется в AppModule.

Режимы работы:

СредаУсловияПоведение
development/testлюбые envpino-pretty
productionAXIOM_TOKEN и AXIOM_DATASET заполненыstdout JSON + Axiom transport
productioncredentials отсутствуютstdout JSON + bootstrap warning

3.2 Что уходит в request log

Через serializers.req и customProps в лог попадают:

  • method
  • url
  • ip
  • userAgent
  • browser
  • platform
  • mobile
  • referer
  • accountId
  • accountType

accountId и accountType вытаскиваются из bearer token без верификации только для enrichment логов. Безопасность на этом не строится: верификация остаётся в guard.

3.3 Prisma и Redis в observability-контуре

PrismaService и RedisService логируют lifecycle-события через PinoLogger:

  • подключение primary DB;
  • подключение replica при наличии;
  • пропуск внешних соединений в export/openapi режиме;
  • ошибки инфраструктурного уровня.

Это означает, что data layer уже встроен в общий observability-контур, а не живёт как «немая» библиотека.

3.4 Monitoring baseline API

Источник: apps/api/src/modules/monitoring/*.

На backend теперь есть минимальный operational monitoring contour:

  • GET /api/v1/health и GET /api/v1/health/live для быстрого liveness-check;
  • GET /api/v1/health/ready для readiness-check с реальной проверкой PostgreSQL и Redis;
  • GET /api/v1/metrics для Prometheus-compatible метрик.

Важно:

  • GET /metrics сознательно доступен только с loopback-адресов сервера;
  • readiness публикует machine-readable status и latency по database и redis;
  • backend дополнительно пишет HTTP/runtime metrics через prom-client (http_requests_total, http_request_duration_seconds и default process metrics).

Это ещё не полный monitoring stack. Сейчас это именно baseline observability слоя, на который позже можно вешать uptime monitoring, scrape, dashboards и alerting.

4. EventLog и продуктовая аналитика

4.1 Таблица EventLog

Источник истины: packages/prisma/schema.prisma.

EventLog устроен как append-only таблица:

  • id
  • source
  • actorId
  • sessionId
  • action
  • entityType
  • entityId
  • payload
  • metadata
  • createdAt

Индексы уже есть по:

  • source, createdAt
  • actorId, createdAt
  • entityType, entityId
  • createdAt
  • action, createdAt

Этого достаточно для базового аудита действий, ручной аналитики и будущей выгрузки в отдельный аналитический контур.

4.2 Клиентский tracking endpoint

POST /api/v1/track публичен и принимает body по TrackEventSchema:

  • action
  • sessionId
  • url
  • entityType
  • entityId
  • payload
  • metadata

При записи дополнительно обогащаются:

  • userAgent
  • referer
  • cookieId
  • request IP
  • source (guest, buyer, seller, admin и т.д.)

4.3 Server-side tracking

@TrackEvent('verb_noun') навешивается на controller methods.

EventLogInterceptor после успешного ответа пишет событие в EventLog. Это даёт два важных свойства:

  • tracking не размазан по контроллерам вручную;
  • ошибки handler-а не создают ложных «успешных» событий.

5. Env и эксплуатация

Ключевые переменные:

  • AXIOM_TOKEN
  • AXIOM_DATASET
  • DATABASE_URL
  • DATABASE_REPLICA_URL
  • REDIS_URL

Поведение сейчас такое:

  • если AXIOM_TOKEN / AXIOM_DATASET пустые, backend не падает;
  • в production остаётся stdout JSON logging;
  • warning печатается один раз на bootstrap.

Это правильно для graceful degradation, но не заменяет осознанного мониторинга наличия реальной отгрузки логов.

6. Что уже хорошо

  • observability-контур унифицирован вокруг Pino;
  • data layer и tracking уже пишут в один инженерный стек, а не в разрозненные логеры;
  • EventLog уже лежит в основной схеме данных и доступен через Prisma;
  • текущий контур не блокирует запросы из-за аналитики: запись событий fire-and-forget;
  • наличие Axiom уже предусмотрено кодом и env-моделью.

7. Чего пока не хватает

  • Нет documented event taxonomy для product/business analytics.
  • Нет списка обязательных событий по buyer/seller/admin critical flows.
  • Нет retention policy и архивации EventLog.
  • Нет dashboards/queries/runbook для Axiom.
  • Нет alerting на деградацию логирования и runtime probes.
  • Нет отдельной аналитической витрины, materialized views или ETL-слоя.
  • Нет автоматических тестов именно на observability-конфигурацию и tracking semantics.
  • Нет внешнего uptime/TLS monitoring, несмотря на появившийся backend metrics/readiness baseline.

8. Рекомендуемые следующие шаги

  1. Зафиксировать канонический словарь событий: action, source, entityType.
  2. Выделить P0-события для buyer/seller/admin критичных потоков.
  3. Добавить documented runbook по проверке Axiom ingestion.
  4. Определить retention/архивацию для EventLog.
  5. Подготовить отдельный analytics backlog поверх уже существующего EventLog, а не строить новую параллельную систему.

9. Правило идентификаторов для downstream analytics

Для аналитического отдела действует единое обязательное правило:

  • продуктовые идентификаторы из backend и operational PostgreSQL приходят в аналитический контур как внешние *_id_ext;
  • raw/staging слой не нормализует их в bigint “на лету”, а сохраняет как внешний технический ключ;
  • внутри warehouse/analytics DB каждая сущность получает собственный внутренний surrogate key bigint (*_id);
  • соответствие между внешним и внутренним идентификатором ведётся через отдельный mapping-слой 1:1;
  • все факты, витрины и тяжёлые join внутри аналитики строятся только по внутренним bigint, а *_id_ext используется для загрузки, сверки и трассировки обратно в продуктовый контур.

Это правило должно применяться автоматически ко всем аналитически значимым сущностям, а не оговариваться вручную по одной таблице за раз.