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:
- Kafka — Catalog публикует события, Warehouse слушает и создаёт копии. Проблема: задержка + рассинхрон при падении Kafka.
- Синхронные API — Warehouse ходит в Catalog за данными. Проблема: runtime зависимость, если Catalog лежит — Warehouse не работает.
- Гибрид (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для ингредиентов (не отдельный справочник)