Архитектура распределенного мониторинга и сквозного контроля системных состояний

Политика сквозного (E2E) маппинга ошибок, обработки сбоев и извлечения бизнес-метрик

Автор

Core Infrastructure & Simulation Framework Documentation

Дата публикации

11 июня 2026 г.

1 Введение

В распределенных асинхронных системах фиксации активности (где мобильный клиент взаимодействует с бэкендом через REST API, а обработка тяжелых данных идет через сервисы распознавания и Apache Kafka) обработка ошибок определяет стабильность платформы. Если сотрудник (пример для AgroLaborApp) находится в зоне со слабым покрытием сети, любая необработанная ошибка может привести к потере данных о выполненной работе.

Для обеспечения сквозного контроля системных состояний (Observability) на проекте внедряется единая политика обработки и маппинга ошибок:

  1. Сбор метрик и мониторинг: Все типы исключений агрегируются в централизованных хранилищах логов (например, ELK Stack или Grafana Loki).
  2. Визуализация: На основе логов строятся дашборды (Grafana / Kibana), отражающие бизнес-метрики и технические метрики (количество 5xx ошибок, задержки в очередях Kafka и.т.д.).
  3. Маппинг ошибок: Процесс преобразования “сырых” системных исключений (базы данных, таймауты, ошибки в сервисах и пр.) в понятные бизнес-коды для фронтенда, детализированные структуры для логов бэкенда и понятные модальные окна для пользователей.

Механизм логирования — инструмент для отладки кода инженерами и ключевой источник данных для продуктовых аналитиков (Product Owners). Анализируя агрегированные коды ошибок, бизнес-заказчики отслеживают следующие критические показатели:

  • Конверсия отчетов (Report Success Rate): Процент успешно завершенных бизнес-процессов от общего числа инициализированных сотрудниками. Падение метрики из-за частых ошибок валидации (ERR-701) или конфликтов состояний (ERR-901) может сигнализировать о неудобном UI приложения.
  • Качество распознавания речи (VTT Accuracy / Dropout Rate): Доля успешных транскрипций аудиоотчетов. Высокая частота ошибок маппинга (ERR-802) со стороны VTT-сервиса (Whisper) указывает на проблему с внешними шумами в рабочих условиях (например для AgroLaborApp это может быть открытое поле), что требует доработки аудиофильтров на клиенте.
  • Индекс падения пользовательской активности (User Friction Index): Точки интерфейса, на которых пользователи чаще всего сталкиваются со сбоями и закрывают приложение. Выявляется через группировку HTTP-ошибок 401 и 404 по экранам мобильного приложения.
  • Бизнес-потери от простоя расчетного ядра ИИ (AI Downtime Cost): Количество бизнес-сценариев, которые не смогли рассчитаться вовремя из-за недоступности системы распознавания (ошибки HTTP 503). Помогает оценить финансовый ущерб от задержек в принятии управленческих решений.

2 Общие типы ошибок

Все системные и бизнес-исключения делятся на три макро-категории:

  • Сбои транспорта и авторизации (HTTP/Network Layer): Ошибки сети, истекшие сессии, невалидные токены доступа.
  • Бизнес-конфликты (Domain Layer): Нарушение бизнес-логики (попытка использовать уже заблокированный ресурс, отсутствие продутокв на складе (FoodLifeCycleApp для предприятия)).
  • Инфраструктурные сбои (Infrastructure Layer): Таймауты базы данных, недоступность микросервисов, сбои при публикации сообщений в брокер.

2.1 Примеры обработки сбоев: Клиентский и Транспортный уровни

2.1.1 Обработка ошибок при потере сети на клиенте (Offline Mitigation)

На мобильном клиенте ключевая задача — изолировать пользователя от сетевых сбоев при передаче тяжелых голосовых записей (отчетов). При фиксации активности логика работает по следующему алгоритму:

  1. Локальное кэширование (Watermarking)1: Приложение не пытается отправить аудиофайл напрямую в API, если сеть нестабильна. Файл сохраняется во внутреннее зашифрованное хранилище устройства, а записи присваивается временный локальный ID.
  2. Перехватчик (Retry Interceptor): Реализуется механизм экспоненциальной задержки (Exponential Backoff2). При получении сетевой ошибки клиент повторяет попытку через 2, 4, 8 секунд.
  3. Очередь синхронизации (Sync Queue): Если попытки исчерпаны, транзакция замораживается в статусе Pending_Sync. Фоновый воркер мониторит состояние сети через NetInfo и автоматически отправляет пакет данных, как только устройство возвращается в онлайн.

2.1.2 Логика работы очередей мертвых сообщений (Kafka Dead Letter Queue / DLQ)

Если бэкенд-служба успешно считала событие из топика Kafka, но произошел инфраструктурный сбой (например, ERR-702: Database timeout), система не должна зацикливать обработку (избегая Poison Pill3).

  • Смещение указателя (Commit Offset): Сообщение признается дефектным, и указатель (offset) сдвигается вперед, чтобы не блокировать конвейер.
  • Маршрутизация в DLQ: Исходный raw_payload оборачивается в технический конверт (содержащий X-Exception-Message и X-Original-Topic) и отправляется в изолированный топик voice-activity-dlq.
  • Стратегия восстановления: Администрирующий воркер раз в час вычитывает сообщения из DLQ и пробует отправить их повторно (Re-drive) в основной конвейер, если цель база данных восстановила работоспособность.

3 Cквозное логирование (Global Error Logging)

Диаграмма последовательности иллюстрирует жизненный цикл распределенного запроса в архитектуре. Процесс разделен на две логические фазы: предварительная контрактная синхронизация фронтенда при холодном старте и последующая изоляция инфраструктурного сбоя СУБД в контейнере food_fastapi.

sequenceDiagram
    autonumber
    participant Client as Клиент (Фронтенд)
    participant API as Бэкенд (food_fastapi)
    participant DB as База данных (PostgreSQL)
    participant Log as Процессор логов (Loki)
    participant Biz as OLAP Слой (Grafana)

    Note over Client, API: Фаза 1: Контрактная синхронизация (Холодный старт)
    Client->>+API: GET /api/v1/auth/error-directory
    API-->>-Client: HTTP 200 + Динамический справочник (ERR-702, ERR-801...)
    Note over Client: Локальное кэширование политик UI в стейт

    Note over Client, DB: Фаза 2: Выполнение изолированной бизнес-транзакции
    Client->>+API: POST /api/v1/fridge/add-by-text
    Note over API: Генерирование / Проброс UUIDv4 (Correlation ID)
    API->>+DB: Выполнение подготовленного запроса (Prepared Stmt)
    DB-->>-API: Исключение asyncpg.exceptions.DataError (expected str, got list)
    
    Note over API: Перехват Catch(Exception). Маппинг по регистру -> ERR-702 (HTTP 400)
    API->>DB: Откат активной транзакции (ROLLBACK)
    
    %% Отправка логов и метрик
    API->>Log: Дегидрированный JSON-лог (error_code: ERR-702, X-Correlation-ID, raw_payload)
    Note over Log, Biz: Векторное разделение телеметрии
    Log->>Biz: Инкремент метрики User Friction Index (Домен 7)
    
    %% Ответ и рендеринг UI
    API-->>-Client: HTTP 400 Bad Request + { \"error_code\": \"ERR-702\", \"correlation_id\": \"UUIDv4\" }
    Note over Client: Интерцептор: Матчинг ERR-702 по локальному кэшу
    Client->>Client: Монтирование ModalAlert локализации (Без системного трейса)
Рисунок 1: Жизненный цикл: Синхронизация справочника, маппинг ошибки и извлечение бизнес-телеметрии

3.1 Принцип Fail-Safe

  • Изоляция транзакции: Любое доменное или инфраструктурное исключение перехватывается блоком Catch (Exception), инициируя немедленный откат состояния базы данных (ROLLBACK).

  • Дегидратация лога(Log Dehydration4): Исходное состояние запроса (raw_payload) изолируется в системную таблицу логов (fact_error_logs) вместе со сквозным идентификатором транзакции (Correlation ID).

  • Типизация интерфейса: Сырая ошибка СУБД или сервиса ИИ инкапсулируется в буквенно-цифровой код вида ERR-XYZ, который возвращается клиенту.

  • Динамическая деградация UI: Фронтенд-интерцептор перехватывает код ошибки, сопоставляет его с динамическим справочником локализации и монтирует безопасный компонент интерфейса (Modal/Toast), полностью скрывая технический трейс от пользователя.

3.2 Иерархическая структура классификатора ERR-XYZ

Зачем нужно трехзначное число?

Первая цифра трехзначного числа определяет макро-модуль (домен), а следующие две цифры — конкретный тип сбоя и контекст внутри этого модуля.

Это позволяет фронтенду мгновенно группировать ошибки (например, красить все ошибки ИИ в один цвет или автоматически перезапрашивать сеть для всех сетевых сбоев), а инженерам — сразу понимать, какая команда отвечает за баг.

Разрядность кодирования закладывается для реализации механизмов маскирования и фильтрации на стороне фронтенда и векторных процессоров логов (Loki/Vector). Код ошибки представляет собой жесткую структуру:

\[ \mathbf{ERR\_CODE} = \underbrace{X}_{\text{Домен}}\quad \underbrace{Y}_{\text{Слой отказа}}\quad \underbrace{Z}_{\text{Идентификатор}} \]

  • Разряд X: Доменная вертикаль (Бизнес-контур)

    7 (Ingestion & Integration): Контур ручного ввода, импорта чеков, парсинга текста и интеграции внешних вебхуков магазинов.

    8 (AI & Media Inference): Контур нейросетевых моделей, систем транскрипции речи (Whisper) и компьютерного зрения (Computer Vision).

    9 (State Engine & Core): Расчетное ядро, координация бизнес-процессов, движок умного приготовления и складской учет.

  • Разряд Y: Архитектурный слой отказа

    • 0 (Validation / DTO): Ошибки верхнего уровня, несоответствие контрактов, пустые payloads, нарушение типов на стороне API-шлюза.

    • 1 (Transport / Message Broker): Сбои асинхронного конвейера, недоступность Apache Kafka, таймауты сетевых сокетов.

    • 2 (Persistence / СУБД): Ошибки уровня хранения, таймауты пула соединений, блокировки транзакций (Deadlocks), нарушение констреинтов PostgreSQL.

    • 3 (Integration Integration / Webhook): Сбои авторизации внешних API, невалидные сигнатуры партнерских сервисов, дрейф контрактов интеграции.

  • Разряд Z: Порядковый номер исключения

Уникальный идентификатор сбоя (от 0 до 9) внутри пересечения домена и слоя, позволяющий точечно локализовать конкретное исключение в исходном коде бэкенда.

3.3 Контракт динамического маппинга ошибок (Error Directory API)

Для исключения рассинхронизации кодов ошибок между независимыми командами разработки бэкенда и фронтенда, в контур авторизации (Authentication) внедряется выделенный системный эндпоинт:

GET /api/v1/auth/error-directory

Мобильный клиент выполняет запрос к данному эндпоинту при каждом холодном старте или обновлении сессии. Полученный реестр кэшируется в локальный стейт-менеджер приложения. Это позволяет добавлять новые типы обработчиков на стороне СУБД или ИИ-контура без необходимости принудительного выпуска релизов мобильного приложения в App Store или Google Play.

ПредупреждениеВажное примечание

В настоящей публичной документации отображены не все шаги и сценарии для приложения в частности и для системы цифровых симуляторов бизнес-процессов в общем.

Спецификация структуры ответа API:

{
  "version": "1.5.0",
  "synced_at": "2026-06-22T12:00:00.000Z",
  "errors": {
    "ERR-702": {
      "ui_component": "ModalAlert",
      "title": "Ошибка формата данных",
      "message": "Не удалось распарсить текстовую позицию продукта. Проверьте корректность ввода параметров.",
      "allow_retry": true
    },
    "ERR-801": {
      "ui_component": "ToastNotification",
      "title": "Сбой голосового контура",
      "message": "Внешние шумы превышают допустимый порог. Мы сохранили черновик, повторите диктовку.",
      "allow_retry": true
    },
    "ERR-922": {
      "ui_component": "ModalWarning",
      "title": "Конфликт модификации",
      "message": "Данный продукт уже задействован или списан в рамках параллельной сессии. Обновите экран.",
      "allow_retry": false
    }
  }
}

3.4 Механизм сквозной трассировки (Correlation ID Pipeline)

В распределенной среде, где запрос проходит через API-шлюз (food_fastapi), брокеры сообщений (Apache Kafka) и изолированные сервисы инференса ИИ, локализация скрытых дефектов невозможна без сквозного идентификатора транзакции (Correlation ID).

Система обеспечивает неизменяемость и передачу контекста по следующему алгоритму:

[Клиент] 
   │  (Запрос без заголовка)
   ▼
[API Gateway / food_fastapi] ──► Генерирует X-Correlation-ID (UUIDv4)
   │
   ├──► HTTP Header [X-Correlation-ID] ──► [Внешние ИИ-сервисы / СУБД]
   │
   └──► Kafka Metadata Envelope ───────► [Топики очередей сообщений]

graph TD
    classDef client fill:#f8f9fa,stroke:#b8daff,stroke-width:1px;
    classDef gateway fill:#d1ecf1,stroke:#0c5460,stroke-width:1px;
    classDef service fill:#dae8fc,stroke:#6c8ebf,stroke-width:1px;
    classDef kafka fill:#fff3e0,stroke:#e65100,stroke-width:1px;

    Client["📱 Клиент"]:::client
    Gateway["🌐 API Gateway / food_fastapi"]:::gateway
    ExtServices["🗄️ Внешние ИИ-сервисы / СУБД"]:::service
    Kafka["📥 Топики очередей сообщений"]:::kafka

    Client -->|Запрос без заголовка| Gateway
    
    %% Отображение внутренней логики генерации
    Gateway -.->|Генерирует X-Correlation-ID UUIDv4| Gateway
    
    Gateway -->|HTTP Header X-Correlation-ID| ExtServices
    Gateway -->|Kafka Metadata Envelope| Kafka

    linkStyle 0,2,3 stroke:#777777,stroke-width:1.5px;
    linkStyle 1 stroke:#28a745,stroke-width:1.5px,stroke-dasharray: 5 5;


Инициация на шлюзе: При поступлении любого входящего HTTP-запроса от мобильного клиента, инверсный прокси или API-шлюз проверяет наличие заголовка X-Correlation-ID. Если заголовок отсутствует (типичный сценарий для первичного запроса клиента), система принудительно генерирует уникальный идентификатор в формате UUIDv4.

Проброс в синхронном контексте (HTTP/gRPC): Шлюз внедряет сгенерированный X-Correlation-ID в контекст выполнения запроса (ThreadLocal / AsyncLocalStorage) и передает его как обязательный HTTP-заголовок во все нижележащие микросервисы.

Конвертирование в асинхронном контексте (Kafka Envelope): При публикации события в брокер сообщений Apache Kafka, бэкенд оборачивает исходный бизнес-пакет в технический конверт, помещая Correlation ID в метаданные (Headers) сообщения Kafka. Консьюмер, вычитывающий топик, обязан первым шагом извлечь этот ID и инициализировать им собственный локальный контекст логирования.Любой системный лог, записанный на любом этапе прохождения запроса, обязан содержать этот маркер в качестве корневого ключа индексации.

3.5 Стратегия логирования Raw Payload и структура fact_error_logs

При возникновении критических инфраструктурных сбоев (таких как падение драйвера asyncpg из-за несовместимости типов в подготовленном выражении базы данных) включается стратегия изоляции “сырых” данных запроса (Raw Payload), система обязана сохранить исходное состояние запроса (raw_payload) в системную таблицу логов (например fact_error_logs). Это необходимо для предотвращения полной потери пользовательских данных и обеспечения возможности проведения ручной или автоматизированной повторной обработки (Retry) после устранения аварии на бэкенде.

Спецификация структуры дегидрированного JSON-лога в СУБД:

При фиксации сбоя бэкенд выполняет атомарную запись в системную таблицу fact_error_logs, изолированную от основной бизнес-логики:

{
  "timestamp": "2026-06-22T14:32:01.892Z",
  "correlation_id": "8b9f71c4-72bf-4632-9dae-2144d8812f8e",
  "service_name": "food_fastapi",
  "error_code": "ERR-702",
  "exception_class": "asyncpg.exceptions.DataError",
  "message": "invalid input for query argument $3: 'КОФЕ РАСТВОРИМЫЙ' (expected str, got list)",
  "request_context": {
    "user_id": "usr_bupar_9912",
    "endpoint": "/api/v1/fridge/add-by-text",
    "method": "POST"
  },
  "raw_payload": {
    "registry_id": "reg_109283",
    "input_type": "text_stream",
    "products": ["КОФЕ РАСТВОРИМЫЙ"],
    "device_timestamp": 1778682720
  }
}

correlation_id: Ключ для сквозного поиска в Grafana Loki. Позволяет сопоставить этот серверный сбой с логом сетевого тайм-аута, зафиксированным на мобильном устройстве пользователя.

raw_payload: Точный снимок данных, которые отправил пользователь. Если сбой произошел из-за ошибки в коде бэкенда (как на скриншоте логов Docker — передача списка вместо строки), администратор системы может запустить скрипт миграции данных, исправить баг и повторно накатить этот payload без участия пользователя.

Пример структуры JSON-лога в fact_error_logs:

{
  "timestamp": "2026-05-13T14:32:01.892Z",
  "correlation_id": "err-902-coord-8812x",
  "service_name": "backend-api-service",
  "error_code": "ERR-702",
  "exception_class": "org.postgresql.util.PSQLException",
  "message": "Database timeout during state write",
  "request_context": {
    "user_id": "usr_field_441",
    "endpoint": "/api/v1/field-activity/save",
    "method": "POST"
  },
  "raw_payload": {
    "registry_id": "reg_109283",
    "activity_type": "voice_report",
    "seeds": ["seed_alpha", "seed_beta"],
    "timestamp": 1778682720
  }
}

Сохранение raw_payload позволяет администраторам системы вручную или автоматически повторно отправить (Retry) упавшую операцию после устранения сбоя в БД.

3.6 Разделение телеметрии лога на инженерный и бизнес-слои

Мониторинг распределенных систем на базе одного источника данных (сырого лога) реализуется через механизм векторного разветвления на уровне агентов сбора данных (например, Vector или FluentBit). Как только в контейнере food_fastapi фиксируется запись с кодом ERR-702, процессор логов дублирует и трансформирует её для разных целевых потребителей:

               ┌──► Grafana Loki ──► Инженерный дашборд (Фикс бага)
               │    (Полный StackTrace + UUID)
[Сырой лог] ───┤
               │
               └──► VictoriaMetrics ──► Бизнес-дашборд (Grafana OLAP)
                    (Агрегированная метрика User Friction Index +1)

graph LR
    classDef raw fill:#f8f9fa,stroke:#b8daff,stroke-width:1px;
    classDef dest fill:#dae8fc,stroke:#6c8ebf,stroke-width:1px;
    classDef dash fill:#fff3e0,stroke:#e65100,stroke-width:1px;

    Log["📝 Сырой лог"]:::raw
    Loki["🔥 Grafana Loki"]:::dest
    VM["📊 VictoriaMetrics"]:::dest
    EngDash["🛠️ Инженерный дашборд<br>(Фикс бага)"]:::dash
    BizDash["📈 Бизнес-дашборд<br>(Grafana OLAP)"]:::dash

    Log -->|Полный StackTrace + UUID| Loki
    Log -->|Агрегированная метрика| VM
    
    Loki --> EngDash
    VM -->|User Friction Index +1| BizDash

    linkStyle 0,1,2,3 stroke:#777777,stroke-width:1.5px;

  1. Инженерная ветка (Диагностика дефектов) Сырой лог, содержащий внутреннее сообщение об ошибке драйвера базы данных и трассировку стека (StackTrace), без изменений пересылается в Grafana Loki. Доступ к этим логам имеют только инженеры поддержки и разработчики. Их ключевая метрика здесь — MTTR (Mean Time to Resolution): скорость нахождения конкретной строки кода по correlation_id.

  2. Бизнес-ветка (Извлечение продуктовых метрик)Агент сбора логов парсит JSON-строку, отбрасывает тяжелый StackTrace и преобразует факт наличия кода ERR-702 в числовую метрику временного ряда (Time Series Metric). Данные отправляются в VictoriaMetrics / Prometheus в виде инкремента счетчика:

В качестве примера рассмотрим структуру метрики сбоя при парсинге ингредиентов:

error_events_total{domain="7", layer="2", error_code="ERR-702", endpoint="/fridge/add-by-text"}

Согласно нашей спецификации, данный инцидент дешифруется следующим образом:

Метка (Label) Значение Компонент формулы Расшифровка
domain "7" \(X\) (Домен) Продуктовый контур (например, Fridge/Food)
layer "2" \(Y\) (Слой отказа) Уровень приложения / FastAPI Backend
error_code "ERR-702" \(Z\) (Идентификатор) Конкретный тип ошибки (ошибка валидации ИИ-ответа)
endpoint "/fridge/add-by-text" Точка отказа (ручка инференса MobileNetV2)

Бизнес-заказчики и продуктовые аналитики видят на своих OLAP-дашбордах в Grafana очищенный график User Friction Index (индекс пользовательского сопротивления). Рост этого графика сигнализирует о том, что интерфейс или ИИ-парсинг работает некорректно, вынуждая пользователей сталкиваться с отказами системы.

4 Кодирование ошибок (Coded Errors) сервисов, Архитектурные, Практические примеры и телеметрия.

Для того чтобы пользователь мобильного приложения получал осмысленные уведомления, а не системный “Crash”, сырые ошибки сервисов маппятся на HTTP-статусы и внутренние буквенно-цифровые коды (Coded Errors).

4.1 Маппинг транспортного уровня (HTTP Status Codes)

Исходный сбой HTTP Статус Бизнес-смысл для клиента / Причина
Сбой сессии / Токена 401 Unauthorized Ошибка авторизации доступа к базе данных или истек таймаут сессии сотрудника.
Отсутствие сущности 404 Not Found ID реестра отсутствует или не найден (сбой инициализации процесса на бэкенде).
Конфликт состояния 409 Conflict Конфликт ресурсов (например, ингредиент или позиция уже задействованы в другом процессе).
Падение сервиса 503 Service Unavailable VTT-сервис недоступен (таймаут ответа или падение пода).

Каждый модуль системы изолирует исключения через блок Catch (Exception), записывает детальный лог и возвращает вызывающему компоненту FALSE или стандартизированный объект ошибки.

ПредупреждениеВажное примечание

В настоящей публичной документации отображены не все шаги и сценарии для приложения в частности и для системы цифровых симуляторов бизнес-процессов в общем.

4.2 Сервис 1: Управление авторизацией (Auth & Registry Service)

Отвечает за регистрацию и авторизацию и обновление доступов.

  • ERR-701: Habit list malformed or missing seeds.
    Причина: Структура данных со списком активностей повреждена на фронтенде или переданы пустые маркеры (seeds).
    Действие: Блокировка запроса на уровне валидации DTO, возврат 400 Bad Request.
  • ERR-702: Database timeout during state write.
    Причина: Таймаут базы данных при попытке записать текущий статус.
    Обработка: Catch (Exception) перехватывает сбой пула соединений, логирует raw_payload, возвращает FALSE и инициирует HTTP 500.

4.3 Сервис 2: Управление списком продуктов и рецептами (Inventory & Recipe Service)

Контролирует ресурсы, необходимые для выполнения процесса.

  • ERR-801: Missing raw ingredients in inventory.
    Причина: В таблице fact_inventory отсутствуют необходимые компоненты для запуска процесса.
    Обработка: Система возвращает FALSE / HTTP 422 Unprocessable Entity.
  • ERR-802: Recipe mapping failure.
    Причина: Сбой маппинга технологической карты или рецепта (несоответствие версий структуры данных).

4.4 Сервис 3: Симулятор и Координация процессов (Simulator & State Engine)

Асинхронный движок, проверяющий бизнес-логику и работающий в связке с Kafka.

  • ERR-901: State conflict (Item already consumed).
    Причина: Конфликт данных. Запись или сущность уже имеет финальный статус «Использовано/Завершено» (Consumed). Повторная модификация запрещена.
    Обработка: Маппинг в HTTP 409 Conflict.
  • ERR-902: Correlation ID generation failure.
    Причина: Сбой генерации сквозного идентификатора транзакции (Correlation ID), из-за чего невозможно отправить сообщение в топик Apache Kafka.

4.5 Стандартизация фронтенд-логов (Context Logging)

Для минимизации времени на расследование инцидентов (MTTR — Mean Time to Resolution), мобильное приложение при возникновении любой ошибки генерирует и отправляет на бэкенд (или в шлюз логирования) расширенный контекст устройства. Это позволяет отделить программные баги от аппаратных ограничений и условий окружающей среды.

Пример структуры JSON-лога, отправляемого с мобильного клиента:

{
  "timestamp": "2026-05-13T14:32:01.412Z",
  "correlation_id": "err-902-coord-8812x",
  "client_application": {
    "name": "FieldActivityApp",
    "version": "2.4.1",
    "build_number": 142,
    "environment": "production"
  },
  "device_telemetry": {
    "platform": "android",
    "os_version": "14.0.0",
    "device_model": "Samsung Galaxy XCover 6 Pro",
    "battery_level": 0.14,
    "is_charging": false,
    "storage_available_mb": 1240
  },
  "network_state": {
    "connection_type": "cellular",
    "cellular_generation": "3G",
    "signal_strength_dbm": -105,
    "is_internet_reachable": false
  },
  "error_details": {
    "component": "VoiceReportUploader",
    "action": "UPLOAD_AUDIO_STREAM",
    "local_error_code": "RN-NET-04",
    "system_message": "timeout of 15000ms exceeded"
  }
}

4.6 Архитектурная ценность телеметрии:

  1. Поля battery_level (14%) и is_charging (false) сразу подсвечивают аналитикам риск того, что устройство могло уйти в режим энергосбережения и принудительно «убить» фоновый процесс отправки аудиофайла.
  2. Поля cellular_generation (3G) и is_internet_reachable (false) доказывают, что сбой произошел на стороне оператора связи, автоматически активируя логику Offline Mitigation (локальное кэширование транзакции на устройстве) без создания ложной тревоги для команды поддержки бэкенда.

5 Заключение

Внедрение иерархического классификатора ERR-XYZ и вынос маппинга ошибок на уровень динамического контракта (/auth/error-directory) решает три задачи распределенной системы:

Целостность данных и атомарность (Persistence Layer): Использование паттерна безопасного отказа гарантирует, что любое непредвиденное исключение (такое как дрейф типов данных в PostgreSQL) принудительно вызывает ROLLBACK доменного состояния.

Изоляция сырого тела запроса (raw_payload) в обособленной таблице fact_error_logs защищает данные от безвозвратной потери и позволяет инженерам проводить повторные транзакции (Retry Pipeline) после устранения дефекта в коде.

Минимизация технического шума (Frontend Layer): Мобильное приложение полностью изолируется от логики бэкенда. Ему не требуется знание о внутренних технологиях сервера (asyncpg, FastAPI, SQLAlchemy). Фронтенд оперирует исключительно кодом ошибки и динамическими инструкциями рендеринга, полученными от API, что исключает появление аварийных системных оверлеев на экранах пользователей.

Конвертация сбоев в бизнес-ценность (OLAP/Observability Layer): Благодаря жесткой разрядности кодирования, технические аварии перестают быть просто “мусором в консоли”.

Механизм векторного разделения логов превращает единичный сбой в понятную бизнесу метрику временного ряда. Это позволяет менеджменту продукта превентивно оценивать финансовые потери например от простоя ИИ-ядра (AI Downtime Cost) или выявлять дефекты интерфейса (User Friction Index) до того, как пользователи массово покинут приложение.


6 Приложение А. Пример справочника бэкенда и продуктовых метрик

Cправочник кодов. 1. Модуль авторизации и сессий (Authentication & Security)

  • ERR-401 — Истек или невалиден JWT-токен. Для UI: Автоматический редирект на экран логина с уведомлением: «Сессия истекла. Пожалуйста, войдите заново».
  • ERR-403 — Недостаточно прав доступа (например, попытка вызвать админский /fridge/waste-control обычным пользователем). Для UI: Баннер: «Действие заблокировано. Недостаточно прав для управления списаниями».
  1. Модуль распознавания и ИИ (AI & Media Processing)
  • ERR-701 — Сбой типов данных при парсинге текста (/fridge/add-by-text). Для UI: Модалка: «Неверный формат ввода. Проверьте текстовое описание продуктов».
  • ERR-702 — Поврежден файл или пустой поток при загрузке фото чека (/product-photo). Для UI: Модалка: «Файл поврежден. Пожалуйста, сделайте снимок чека еще раз».
  • ERR-801 — Таймаут или падение сервиса Whisper (/voice-note). Для UI: Тоаст: «Голосовой сервис временно недоступен. Попробуйте продиктовать позже».
  1. Складской движок (Fridge Stock & State Engine)
  • ERR-901 — Конфликт состояния данных (/fridge/consume). Попытка списать продукт, которого уже нет в холодильнике. Для UI: Модалка: «Продукт уже удален из холодильника другим пользователем».
  • ERR-902 — Таймаут транзакции базы данных при тяжелой операции (/fridge/shadow-cook). Для UI: Модалка: «Сервер перегружен. Мы сохранили черновик процесса, повторите попытку через минуту».
  1. Интеграции и Вебхуки (External Integrations & Webhooks)
  • ERR-601 — Невалидная сигнатура или сбой формата данных от внешнего магазина (/fridge/integration/shop-mock/webhook). Бизнес-метрика: Integration Dropout Rate. Сигнализирует о том, что партнерский магазин изменил свой API контракта.
Код ошибки Точка отказа (Swagger) Первопричина (Исключение) Бизнес-метрика в Grafana
ERR-401 /api/v1/auth/* ExpiredSignatureError / JWT Expired Session Drop Rate (Проблемы с удержанием сессии)
ERR-403 /api/v1/auth/* ExpiredSignatureError / JWT Expired Session Drop Rate Недостаточно прав доступа (например, попытка вызвать админский /fridge/waste-control обычным пользователем)
ERR-406 /api/v1/auth/register* ExpiredSignatureError / JWT Expired Session Drop Rate Недостаточно прав доступа (например, попытка вызвать админский /fridge/waste-control обычным пользователем)
ERR-407 /api/v1/auth/login* ExpiredSignatureError / JWT Expired Session Drop Rate Недостаточно прав доступа (например, попытка вызвать админский /fridge/waste-control обычным пользователем)
ERR-408 /api/v1/auth/refresh* ExpiredSignatureError / JWT Expired Session Drop Rate Недостаточно прав доступа (например, попытка вызвать админский /fridge/waste-control обычным пользователем)
ERR-409 /api/v1/auth/logout* ExpiredSignatureError / JWT Expired Session Drop Rate Недостаточно прав доступа (например, попытка вызвать админский /fridge/waste-control обычным пользователем)
ERR-601 /shop-mock/webhook WebhookSignatureVerificationFailed Partner API Integration Drift (Сбои контракта магазина)
ERR-701 /fridge/add-by-text asyncpg.exceptions.DataError User Friction Index (Ошибки ручного ввода)
ERR-702 /product-photo PIL.UnidentifiedImageError Photo Upload Failure Rate (Сбои загрузки медиа)
ERR-703 /product-photo PIL.UnidentifiedImageError Photo Upload Failure Rate (Нарушение бизнес-лимитов (Payload Too Large). Попытка добавить более 100 наименований продуктов за один запрос.)
ERR-704 /product-photo PIL.UnidentifiedImageError Photo Upload Failure Rate (Ошибка кодировки (Encoding Error). Битый текстовый стрим, который бэкенд не смог распарсить.)
ERR-801 /voice-note WhisperVTTException / Timeout VTT Dropout Rate (Ошибки ИИ-транскрипции)
ERR-802 /voice-note WhisperVTTException / Timeout Низкий порог уверенности модели (Low Confidence Score). Нейросеть распознала объект на фото чека с уверенностью менее 40%.
ERR-803 /voice-note WhisperVTTException / Timeout Сбой аллокации памяти ИИ (Out of VRAM). Сервис упал из-за нехватки видеопамяти при обработке тяжелого изображения.
ERR-901 /fridge/consume PSQLException: SerializationFailure Double Consume Rate (Конфликты одновременного списания)
ERR-902 /fridge/shadow-cook DatabaseTimeoutException Core Downtime Cost (Бизнес-потери от зависания СУБД)
ERR-903 /fridge/shadow-cook DatabaseTimeoutException Core Downtime Cost (Бизнес-потери от зависания СУБД)
ERR-904 /fridge/shadow-cook DatabaseTimeoutException Core Downtime Cost (Бизнес-потери от зависания СУБД)

Вот расширенный иерархический справочник, который показывает, как трехзначный код раскрывается внутри каждой категории вашего проекта:

Домен 7xx — Модуль импорта данных и валидации

ERR-701 — Ошибка формата данных (Data Type Mismatch). Передан неверный тип (list вместо str в названии продукта).

ERR-702 — Пустое тело запроса (Empty Payload). Отправлен пустой текстовый запрос в /fridge/add-by-text.

ERR-703 — Нарушение бизнес-лимитов (Payload Too Large). Попытка добавить более 100 наименований продуктов за один запрос.

ERR-704 — Ошибка кодировки (Encoding Error). Битый текстовый стрим, который бэкенд не смог распарсить.

Домен 8xx — Контур ИИ-моделей (Whisper, Computer Vision)

ERR-801 — Таймаут инференса модели (Inference Timeout). Сервис распознавания аудио (voice-note) не ответил за 15 секунд.

ERR-802 — Низкий порог уверенности модели (Low Confidence Score). Нейросеть распознала объект на фото чека с уверенностью менее 40%.

ERR-803 — Сбой аллокации памяти ИИ (Out of VRAM). Сервис упал из-за нехватки видеопамяти при обработке тяжелого изображения.

Домен 9xx — Складское ядро и логика состояний (Fridge Stock Core)

ERR-901 — Сущность не найдена (Entity Not Found). Попытка списать ID продукта, которого никогда не было в базе умного холодильника.

ERR-902 — Конфликт конкурентного доступа (Optimistic Locking Failure). Два пользователя одновременно пытаются нажать «списать» на один и тот же йогурт.

ERR-903 — Нарушение целостности связей (ForeignKey Violation). Попытка привязать продукт к несуществующей категории рецепта.

ERR-904 — Таймаут пула транзакций СУБД (Connection Pool Timeout). База данных перегружена и не успела зафиксировать списание.


ERR - [X: Доменная зона] [Y: Слой отказа] [Z: Идентификатор]
├── 7: Ingestion / Валидация     ├── 0: Валидация DTO         └── 0-9: Номер сбоя
├── 8: AI / Inference Core       ├── 1: Асинхронный транспорт
└── 9: State Engine (Ядро)       ├── 2: СУБД / Persistence
└── 3: External API / Webhook

При инициализации сессии через эндпоинт GET /api/v1/auth/error-directory фронтенд синхронизирует локальный стейт со следующим подмножеством системного справочника бэкенда:

Системный код Точка отказа (API) Системный тип исключения Стратегия деградации UI (Фронтенд) Целевая OLAP-метрика (Бизнес)
ERR-702 /fridge/add-by-text asyncpg.exceptions.DataError ModalAlert (Блокирующий ввод) User Friction Index
ERR-721 /receipt-draft/confirm NatsNoResolversException ToastNotification (Retry фоном) Ingestion Pipeline Delay
ERR-801 /voice-note WhisperVTTException: Timeout ToastNotification (Смена на текст) VTT Dropout Rate
ERR-832 /product-photo S3UploadConnectionError ModalConfirmation (Повтор кадра) Media Processing Loss
ERR-922 /fridge/consume PSQLException: Deadlock ModalWarning (Синхронизация стейта) Double Consume Rate
ERR-924 /fridge/shadow-cook DatabaseTimeoutException ModalAlert (Сервер перегружен) AI Downtime Cost

Сноски

  1. TBD↩︎

  2. TBD↩︎

  3. TBD↩︎

  4. TBD↩︎