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

Архитектурные решения (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-29TypeORM + @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 и версионируемым форматом записи.
0006Rate-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 в фичевых модулях.
0008Frontend 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.
0010Observability очередей: 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).
0012Frontend: App Shell, маршрутизация и navigation registryПринято2026-06-11App 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; провайдер задаётся конфигурацией.
0015RAG-минимум: контекст из базы знаний на pgvectorПринято2026-06-24RAG-минимум: эмбеддинги фрагментов базы знаний в 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Расчёт прибыли по артикулу и периоду чистой функцией поверх строк отчёта о реализации.
0019API отчётов оцифровки + brand-scope (cabinet live, brand_id dormant)Принято2026-06-25API отчётов оцифровки: граница доступа по кабинету, brand_id — подготовленная инфраструктура.
0020API изменения цен и скидок (одиночное и массовое)Принято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).
0041WB 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-поиска.
0048429 от 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 //summary с периодом 7d/30d и дельтами.
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 (только в сторону сужения).