Архитектурные решения (ADR)
ADR (Architecture Decision Record) — короткий документ об одном значимом архитектурном решении: контекст, рассмотренные варианты, принятое решение и его последствия. Формат — MADR. ADR объясняют, почему система устроена именно так, и не дают переоткрывать уже принятые решения.
- Канонические тексты лежат в репозитории:
backend/docs/adr/(GitHub). - В портал они копируются скриптом
npm run sync:adr(каталогdocs-site/); этот реестр генерируется тем же скриптом — правьте исходные ADR, а не копии. - Новый ADR: скопировать
backend/docs/adr/0000-template.mdсо следующим номером, заполнить разделы, указать статус и связанные задачи Jira, затем выполнитьnpm run sync:adrи добавить однострочное резюме вdocs-site/scripts/adr-summaries.json. - Нумерация: номера 0008, 0012 исторически заняты двумя решениями; номера 0058, 0060, 0064 не использованы.
Всего решений: 65.
| № | Решение | Статус | Дата | Суть |
|---|---|---|---|---|
| 0001 | Выбор ORM и системы миграций | Принято | 2026-05-29 | TypeORM + @nestjs/typeorm; миграции встроенным механизмом TypeORM через data-source.ts. |
| 0002 | Модульный монолит: разделение src/core и src/modules | Принято | 2026-05-28 | Модульный монолит: горизонтальные сервисы в src/core (Global), фичи 5.1–5.15 в src/modules. |
| 0003 | Хеш пароля и стратегия refresh-токенов | Принято | 2026-05-29 | Пароли — argon2id (параметры OWASP); refresh-токены ротируются с отзывом в PostgreSQL. |
| 0004 | Модель RBAC: хранение роли и доставка её в guard | Принято | 2026-06-01 | Роль — enum-колонка users.role, доставляется в guard через claim JWT. |
| 0005 | Шифрование секретов at-rest: алгоритм, формат и ротация | Принято | 2026-06-01 | Секреты (API-ключи WB) шифруются AES-256-GCM с key-ring и версионируемым форматом записи. |
| 0006 | Rate-limit и retry для WB API | Принято, частично заменено | 2026-06-01 | Локальный rate-limit WB API в Redis на кабинет и retry с backoff; алгоритм лимитера позже заменён ADR-0041. |
| 0007 | Инфраструктура очередей: BullMQ + выделенное Redis-соединение | Принято | 2026-06-04 | Очереди на BullMQ (@nestjs/bullmq) с выделенным Redis-соединением; воркеры — @Processor в фичевых модулях. |
| 0008 | Frontend stack для Оптимы | Принято | 2026-06-11 | Фронтенд: Next.js (App Router) + React + TypeScript + Tailwind + shadcn/ui + TanStack Query; e2e — Playwright. |
| 0008 | Хранение временных рядов: PostgreSQL 16 + native range-partitioning, без TimescaleDB | Принято | 2026-06-09 | Временные ряды — PostgreSQL 16 с нативным range-партиционированием, без TimescaleDB. |
| 0009 | Реестр периодических задач: @nestjs/schedule + anti-overlap через детерминированный jobId | Принято | 2026-06-05 | Единый реестр периодических задач на @nestjs/schedule, защита от наложения через детерминированный jobId. |
| 0010 | Observability очередей: Bull Board UI + Prometheus exposition | Принято | 2026-06-09 | Наблюдаемость очередей: Bull Board под /admin/queues и метрики очередей в формате Prometheus. |
| 0011 | Структурное логирование и correlation-id | Принято | 2026-06-09 | Структурные JSON-логи и сквозной correlation-id через AsyncLocalStorage. |
| 0012 | Журнал аудита действий пользователей и AI-агентов | Принято | 2026-06-22 | Неизменяемый журнал аудита действий пользователей, системы и ИИ-агентов (audit_logs, JSONB before/after). |
| 0012 | Frontend: App Shell, маршрутизация и navigation registry | Принято | 2026-06-11 | App shell фронтенда: route groups, URL с кабинетом /app/wb/:accountId, navigation registry, глобальный фильтр бренда. |
| 0013 | Базовые метрики приложения (/metrics) на едином реестре prom-client | Принято | 2026-06-23 | Базовые метрики приложения на едином реестре prom-client, эндпоинт /metrics. |
| 0014 | Абстракция LLM-провайдера через OpenAI-совместимый адаптер | Принято | 2026-06-24 | Интерфейс LlmProvider и OpenAI-совместимый адаптер на fetch; провайдер задаётся конфигурацией. |
| 0015 | RAG-минимум: контекст из базы знаний на pgvector | Принято | 2026-06-24 | RAG-минимум: эмбеддинги фрагментов базы знаний в pgvector, top-k поиск по косинусной близости. |
| 0016 | Импорт данных WB (продажи/заказы/возвраты): модуль digitization | Принято | 2026-06-24 | Импорт заказов, продаж и возвратов из WB Statistics API в модуль digitization с идемпотентной записью. |
| 0017 | Учёт комиссий/логистики/штрафов из отчёта реализации WB | Принято | 2026-06-24 | Комиссии, логистика, штрафы, эквайринг, хранение и удержания — из строк отчёта о реализации WB. |
| 0018 | Расчёт прибыли (P&L) по товару и периоду | Принято | 2026-06-24 | Расчёт прибыли по артикулу и периоду чистой функцией поверх строк отчёта о реализации. |
| 0019 | API отчётов оцифровки + brand-scope (cabinet live, brand_id dormant) | Принято | 2026-06-25 | API отчётов оцифровки: граница доступа по кабинету, brand_id — подготовленная инфраструктура. |
| 0020 | API изменения цен и скидок (одиночное и массовое) | Принято | 2026-06-25 | Изменение цен и скидок: одиночное — синхронно, массовое — фоновой джобой pricing-bulk. |
| 0021 | История изменений цен/скидок | Принято | 2026-06-25 | История цен и скидок — append-only таблица price_changes, одна строка на изменённое поле. |
| 0022 | Модель правил репрайсера с ограничениями по цене | Принято | 2026-06-25 | Правила репрайсера — одна таблица с типизированными условиями, действием, границами min/max и областью действия. |
| 0023 | Движок пересчёта цен репрайсера | Принято | 2026-06-25 | Движок репрайсера: показатели передаются в запросе, при конфликте правил побеждает самое раннее. |
| 0024 | Периодический пересчёт репрайсера | Принято | 2026-06-25 | Периодический пересчёт репрайсера через реестр расписаний; системный запуск от имени System. |
| 0025 | Алгоритм движка управления ставками автобиддера | Принято | 2026-06-25 | Движок ставок автобиддера: стратегия cpc с ограничением шага ±50% за цикл, drr/position — удержание ставки. |
| 0026 | Стратегия доступа к личному кабинету WB (где нет официального API) | Принято | 2026-06-26 | Только официальный Seller API; операции без API (жалоба на отзыв, бронь слота) — ассистируемый ручной шаг. |
| 0027 | Единая модель отзывов и вопросов (autoreply) | Принято | 2026-06-26 | Отзывы и вопросы — одна таблица autoreply_feedbacks с полем kind и идемпотентным ключом. |
| 0028 | Отправка ответов автоответчика (статусы, авто-режим, идемпотентность) | Принято | 2026-06-26 | Отправка ответов: статусы черновика draft → pending → sent/error, авто-режим, идемпотентность. |
| 0029 | Высокочастотный сбор заказов/продаж РНП поверх оцифровки | Принято | 2026-06-29 | Сбор заказов и продаж для РНП переиспользует импорт оцифровки; отдельный модуль rnp с расписанием. |
| 0030 | Правила объединения данных РНП и модель витрины по артикулу | Принято | 2026-06-29 | Витрина РНП: ключ (кабинет, артикул, день по МСК), дневные роллапы, агрегация периодов на лету. |
| 0031 | Метод учёта товарных остатков и интеграция со складом селлера | Принято | 2026-07-07 | Товарный учёт: журнал операций + сверка с остатками WB; собственный склад — через адаптер импорта. |
| 0032 | Обработка видео/записей для базы знаний (транскрипция → RAG) | Принято | 2026-07-07 | Видео для базы знаний: транскрипция (faster-whisper, облачный ASR за флагом) и индексация в RAG. |
| 0033 | Провайдер генерации изображений для карточек товара | Принято | 2026-07-07 | Генерация изображений через сменного провайдера за абстракцией; выбор провайдера — пилотом. |
| 0034 | Мониторинг и бронирование слотов поставок FBW | Принято | 2026-07-07 | Бронировщик: мониторинг коэффициентов приёмки на кабинет, бронь слота — ассистируемый ручной шаг. |
| 0035 | Ассистируемая подача жалоб на отзывы (без хранения сессий ЛК) | Принято | 2026-07-06 | Жалобы на отзывы готовятся в «Оптиме», подаются продавцом в ЛК WB по ссылке; сессии ЛК не хранятся. |
| 0036 | Модель движения товара: журнал событий по звеньям + агрегация реестра партиций | Принято | 2026-07-09 | Движение товара — append-only журнал знаковых изменений по звеньям цепочки; остаток — проекция. |
| 0037 | Формат экспорта досудебной претензии: DOCX (Unicode-native), а не PDF | Принято | 2026-07-09 | Досудебная претензия экспортируется в DOCX (редактируемый формат, корректная кириллица), а не в PDF. |
| 0038 | Анализ A/B-теста: двухдолевой z-тест и снимок результата на ab_tests | Принято | 2026-07-09 | Победитель A/B-теста — двухдолевой z-тест по CTR с порогом p < 0.05, снимок результата сохраняется на тесте. |
| 0039 | Учёт доходов и расходов: derive-on-read поверх оцифровки | Принято | 2026-07-11 | Бухгалтерия — derive-on-read: доходы и расходы выводятся из данных оцифровки без отдельного хранилища. |
| 0040 | Явная concurrency воркеров sync-очередей WB | Принято | 2026-07-27 | Явная concurrency воркеров sync-очередей WB (env SYNC_QUEUE_CONCURRENCY, по умолчанию 5). |
| 0041 | WB rate-limiter: token-bucket со всплеском вместо fixed-window | Принято | 2026-07-27 | Лимитер WB API — token-bucket со всплеском в Redis (Lua) вместо fixed-window. |
| 0042 | Единый ярусный пайплайн синка фидов оцифровки | Принято | 2026-07-28 | Единый ярусный пайплайн синхронизации фидов (очередь digitization-sync): инкремент и ночной backfill. |
| 0043 | Модель сессий: reuse-detection refresh-токенов, отзыв семьи и локаут учётной записи | Принято | 2026-08-05 | Семьи refresh-токенов, обнаружение повторного использования с отзывом семьи, блокировка после неудачных входов. |
| 0044 | Минимизация раскрытия в production и fail-fast на небоевых секретах | Принято | 2026-08-05 | В production — минимум деталей в /health и ошибках; приложение не стартует с небоевыми секретами. |
| 0045 | Защита автоответов от косвенной prompt injection | Принято | 2026-08-05 | Защита автоответов от prompt injection: санитизация входа, разделители и детерминированная проверка ответа. |
| 0046 | Потолок периода отчётов и агрегация на стороне БД | Принято | 2026-08-05 | Потолок периода отчётов (REPORT_MAX_PERIOD_DAYS, по умолчанию 366 дней) и агрегация на стороне SQL. |
| 0047 | Лимиты расхода LLM и контроль доступа в RAG-поиске | Принято | 2026-08-05 | Лимиты расхода LLM и фильтрация доступа к материалам базы знаний прямо в SQL RAG-поиска. |
| 0048 | 429 от WB как обратная связь: штраф бакета и минутная лестница ретраев | Принято | 2026-08-20 | Ответ 429 от WB штрафует бакет; пауза не меньше времени восполнения токена, ретраи по минутной лестнице. |
| 0049 | Таймаут чтения отчёта реализации и проекция полей WB | Принято | 2026-08-21 | Отчёт о реализации: отдельный таймаут чтения 120 с и запрос только нужных полей. |
| 0050 | Счётчики продаж в P&L и непагинированный агрегат продаж за период | Принято | 2026-08-25 | Счётчики продаж и возвратов в ответе P&L и непагинированный агрегат продаж за период. |
| 0051 | Перенос джобы в delayed вместо блокирующего ожидания лимита WB | Принято | 2026-09-08 | При долгом ожидании лимита WB джоба переносится в delayed, а не блокирует воркер. |
| 0052 | Единый каталог номенклатуры для цен и репрайсера | Принято | 2026-09-08 | Единый каталог номенклатуры (products) со снимком цены — общий для цен и репрайсера. |
| 0053 | Единый формат KPI-эндпоинтов GET /<module>/summary | Принято | 2026-09-18 | Единый формат KPI-эндпоинтов GET / |
| 0054 | Управление кампанией per-РК и журнал изменений ставок | Принято | 2026-09-18 | Управление отдельной рекламной кампанией и журнал изменений ставок автобиддера. |
| 0055 | Реестр шаблонов ответов продавца и режим без LLM | Принято | 2026-09-18 | Реестр шаблонов ответов продавца и режим автоответов без LLM. |
| 0056 | Ручные операции в бухгалтерии и их место в сверке | Принято | 2026-09-18 | Ручные операции в бухгалтерии — своя таблица accounting_transactions, отдельно от данных WB при сверке. |
| 0057 | Единый per-account gate WB-тяжёлых джоб, alreadyRunning и прогресс в status poll | Принято | 2026-09-28 | Не более одного тяжёлого WB-процесса на кабинет (gate в Redis), ответ alreadyRunning и прогресс в опросе статуса. |
| 0059 | Синк каталога по требованию и онбординг-хук подключения кабинета | Принято | 2026-09-28 | Синхронизация каталога по запросу (POST /catalog/sync) и автоматически при подключении кабинета. |
| 0061 | Персистентная очередь подтверждений планов ИИ-агента | Принято | 2026-09-28 | Планы ИИ-агента сохраняются и выполняются только после подтверждения пользователем. |
| 0062 | Фото варианта A/B-теста: хранение и выкладка на карточку WB (Content API) | Принято | 2026-09-28 | Фото вариантов A/B-теста хранятся в БД и выкладываются на карточку WB через Content API. |
| 0063 | Аналитика кампаний автобиддера: join с ad_campaigns и кампании без статистики | Принято | 2026-09-28 | Аналитика автобиддера объединяет кампании кабинета и статистику, включая кампании без показов. |
| 0065 | Периоды активности вариантов A/B-теста и сбор CTR по окнам | Принято | 2026-09-28 | Периоды активности вариантов A/B-теста и сбор CTR отдельно по каждому окну. |
| 0066 | Сверка token-bucket со счётчиком WB по заголовкам X-Ratelimit-* | Принято | 2026-10-01 | Сверка локального лимитера с заголовками X-Ratelimit-* ответов WB (только в сторону сужения). |