ADR-009: Ингредиенты — единый каталог с флагом, не отдельный справочник

Статус

proposed — ожидает подтверждения

Контекст

Для техкарт (BR 1.9) нужны ингредиенты — мука, сыр, томаты, дрожжи. Вопрос: где они живут?

У нас два сервиса:

  • Catalog Service (:3004) — товары: пицца, бургер, бутылка воды
  • Warehouse Service (:3008) — склад: остатки, списание, техкарты

Ингредиент (мука) — это не то что продаётся клиенту. Но бутылка воды — и продаётся, и учитывается на складе. Они пересекаются.

Как в iiko (монолит)

В iiko всё в одной номенклатуре. Нет отдельного справочника ингредиентов:

ПозицияТип в iikoПродаётсяНа складеТехкарта
Пицца МаргаритаDishДа (меню)Нет (списывается по рецепту)Да
Бутылка водыGoodДа (меню)Да (1:1)Нет
МукаGoodНетДаНет
Тесто (п/ф)DishНетДа (полуфабрикат)Да

Мука и бутылка воды — одинаковый тип (Good). Разница только в том что мука не попадает в меню. Но обе — складские позиции с остатками и закупочными ценами.

Рассмотренные варианты

Вариант A: Всё в Catalog Service (как iiko)

Мука, дрожжи, соус — товары в Catalog Service с type=good. Не включаются в меню. Warehouse ссылается на product_id.

ПлюсМинус
Один справочник, нет дублированияКаталог “засоряется” — 50 блюд + 200 ингредиентов в одном списке
Как в iiko — проверенная модельФраншиза видит муку рядом с пиццей
Бутылка воды — одна сущность

Вариант B: Ингредиенты отдельно в Warehouse Service

Warehouse имеет свой справочник ingredients. Catalog не знает об ингредиентах. Техкарта ссылается на ingredient_id.

ПлюсМинус
Чистое разделение доменовБутылка воды дублируется: в каталоге (продажа) + на складе (учёт)
Каталог — только то что продаёмНужна синхронизация: Kafka-события или API-вызовы
Eventual consistency / runtime зависимость
Reconciliation при рассинхроне

Синхронизация для варианта B:

  1. Kafka — Catalog публикует события, Warehouse слушает и создаёт копии. Проблема: задержка + рассинхрон при падении Kafka.
  2. Синхронные API — Warehouse ходит в Catalog за данными. Проблема: runtime зависимость, если Catalog лежит — Warehouse не работает.
  3. Гибрид (Kafka + fallback API) — сложнее, но надёжнее. Всё равно дополнительная инфраструктура.

Вариант C: Catalog Service + флаг is_ingredient (рекомендация)

Все позиции в Catalog Service. Расширяем тип товара: dish / good / ingredient. Или добавляем is_ingredient: boolean. Ингредиенты видны в каталоге в отдельной вкладке/фильтре. Не попадают в меню. Warehouse ссылается на product_id.

ПлюсМинус
Один справочник — нет дублирования, нет синхронизацииКаталог чуть сложнее (но решается фильтром в UI)
Как в iiko по сути
Бутылка воды — одна сущность (good, не ингредиент)
Мука — отдельный тип, не мешается с блюдами
Warehouse просто ссылается на product_id
Полуфабрикат (тесто) — dish с техкартой, не в меню

Как это выглядит в UI (Вариант C)

Каталог (Админка Франшизы)
├── Товары           ← блюда и продукты для продажи (dish, good)
│     ├── Пицца Маргарита (dish)
│     ├── Бургер Классический (dish)
│     └── Бутылка воды (good)
├── Ингредиенты      ← отдельная вкладка / раздел
│     ├── Мука (ingredient)
│     ├── Моцарелла (ingredient)
│     ├── Томаты (ingredient)
│     └── Дрожжи (ingredient)
└── Полуфабрикаты    ← dish без привязки к меню
      ├── Тесто для пиццы (dish)
      └── Соус томатный (dish)

Ингредиенты не попадают в меню (нет в allowlist). Полуфабрикаты — dish со своей техкартой, но тоже не в меню.

Решение

Рекомендуется Вариант C — единый каталог с расширенным типом товара. Ингредиенты в Catalog Service, с отдельной вкладкой в UI. Warehouse ссылается на product_id, без дублирования и синхронизации.

Расширение enum типа товара:

  • dish — блюдо (готовится, техкарта, продаётся)
  • good — продукт (продаётся как есть, 1:1 списание)
  • ingredient — ингредиент (не продаётся, используется в техкартах)

Полуфабрикат = dish с техкартой, но не включённый в меню.

Последствия

Положительные

  • Один справочник — нет дублирования, нет синхронизации между сервисами
  • Модель как в iiko — проверена индустрией
  • Бутылка воды — одна сущность с одним ID
  • Warehouse просто ссылается на product_id из Catalog

Отрицательные

  • Catalog Service становится больше (товары + ингредиенты)
  • Нужен фильтр/вкладка в UI чтобы разделить

Риски

  • Если ингредиентов будет очень много (1000+) — нагрузка на Catalog Service. Маловероятно для франшизы общепита.

Что меняется

  • BR 1.7 — добавить тип ingredient, описать вкладку “Ингредиенты” в UI
  • BR 1.9 — техкарта ссылается на product_id для ингредиентов (не отдельный справочник)

Ссылки