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 локализации (Без системного трейса)
Архитектура распределенного мониторинга и сквозного контроля системных состояний
Политика сквозного (E2E) маппинга ошибок, обработки сбоев и извлечения бизнес-метрик
1 Введение
В распределенных асинхронных системах фиксации активности (где мобильный клиент взаимодействует с бэкендом через REST API, а обработка тяжелых данных идет через сервисы распознавания и Apache Kafka) обработка ошибок определяет стабильность платформы. Если сотрудник (пример для AgroLaborApp) находится в зоне со слабым покрытием сети, любая необработанная ошибка может привести к потере данных о выполненной работе.
Для обеспечения сквозного контроля системных состояний (Observability) на проекте внедряется единая политика обработки и маппинга ошибок:
- Сбор метрик и мониторинг: Все типы исключений агрегируются в централизованных хранилищах логов (например, ELK Stack или Grafana Loki).
- Визуализация: На основе логов строятся дашборды (Grafana / Kibana), отражающие бизнес-метрики и технические метрики (количество 5xx ошибок, задержки в очередях Kafka и.т.д.).
- Маппинг ошибок: Процесс преобразования “сырых” системных исключений (базы данных, таймауты, ошибки в сервисах и пр.) в понятные бизнес-коды для фронтенда, детализированные структуры для логов бэкенда и понятные модальные окна для пользователей.
Механизм логирования — инструмент для отладки кода инженерами и ключевой источник данных для продуктовых аналитиков (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)
На мобильном клиенте ключевая задача — изолировать пользователя от сетевых сбоев при передаче тяжелых голосовых записей (отчетов). При фиксации активности логика работает по следующему алгоритму:
- Локальное кэширование (Watermarking)1: Приложение не пытается отправить аудиофайл напрямую в API, если сеть нестабильна. Файл сохраняется во внутреннее зашифрованное хранилище устройства, а записи присваивается временный локальный ID.
- Перехватчик (Retry Interceptor): Реализуется механизм экспоненциальной задержки (Exponential Backoff2). При получении сетевой ошибки клиент повторяет попытку через 2, 4, 8 секунд.
- Очередь синхронизации (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.
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;
Инженерная ветка (Диагностика дефектов) Сырой лог, содержащий внутреннее сообщение об ошибке драйвера базы данных и трассировку стека (StackTrace), без изменений пересылается в Grafana Loki. Доступ к этим логам имеют только инженеры поддержки и разработчики. Их ключевая метрика здесь — MTTR (Mean Time to Resolution): скорость нахождения конкретной строки кода по
correlation_id.Бизнес-ветка (Извлечение продуктовых метрик)Агент сбора логов парсит 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и инициирует HTTP500.
4.3 Сервис 2: Управление списком продуктов и рецептами (Inventory & Recipe Service)
Контролирует ресурсы, необходимые для выполнения процесса.
- ERR-801: Missing raw ingredients in inventory.
Причина: В таблицеfact_inventoryотсутствуют необходимые компоненты для запуска процесса.
Обработка: Система возвращаетFALSE/ HTTP422 Unprocessable Entity. - ERR-802: Recipe mapping failure.
Причина: Сбой маппинга технологической карты или рецепта (несоответствие версий структуры данных).
4.4 Сервис 3: Симулятор и Координация процессов (Simulator & State Engine)
Асинхронный движок, проверяющий бизнес-логику и работающий в связке с Kafka.
- ERR-901: State conflict (Item already consumed).
Причина: Конфликт данных. Запись или сущность уже имеет финальный статус «Использовано/Завершено» (Consumed). Повторная модификация запрещена.
Обработка: Маппинг в HTTP409 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 Архитектурная ценность телеметрии:
- Поля
battery_level(14%) иis_charging(false) сразу подсвечивают аналитикам риск того, что устройство могло уйти в режим энергосбережения и принудительно «убить» фоновый процесс отправки аудиофайла. - Поля
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: Баннер: «Действие заблокировано. Недостаточно прав для управления списаниями».
- Модуль распознавания и ИИ (AI & Media Processing)
- ERR-701 — Сбой типов данных при парсинге текста (/fridge/add-by-text). Для UI: Модалка: «Неверный формат ввода. Проверьте текстовое описание продуктов».
- ERR-702 — Поврежден файл или пустой поток при загрузке фото чека (/product-photo). Для UI: Модалка: «Файл поврежден. Пожалуйста, сделайте снимок чека еще раз».
- ERR-801 — Таймаут или падение сервиса Whisper (/voice-note). Для UI: Тоаст: «Голосовой сервис временно недоступен. Попробуйте продиктовать позже».
- Складской движок (Fridge Stock & State Engine)
- ERR-901 — Конфликт состояния данных (/fridge/consume). Попытка списать продукт, которого уже нет в холодильнике. Для UI: Модалка: «Продукт уже удален из холодильника другим пользователем».
- ERR-902 — Таймаут транзакции базы данных при тяжелой операции (/fridge/shadow-cook). Для UI: Модалка: «Сервер перегружен. Мы сохранили черновик процесса, повторите попытку через минуту».
- Интеграции и Вебхуки (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 |