ADR-008: Аудит-лог изменений каталога и прейскурантов
Статус
accepted
Контекст
Каталог и прейскуранты — мутабельные сущности без версионности. Франшиза может в любой момент изменить цену, название, категорию товара. Заказы защищены снапшотами (цена/название копируются в строку заказа при создании). Но аналитика и отчёты работают с текущим состоянием каталога.
Проблема
При изменении каталога теряется информация о том, что было раньше:
| Что изменилось | Проблема для аналитики |
|---|---|
| Цена 690₽ → 750₽ | Нельзя узнать когда именно поменялась цена. Отчёт за период не может разделить продажи по старой и новой цене |
| Название “Пицца Маргарита” → “Маргарита Классическая” | В отчёте по товару — два визуально разных названия для одного product_id |
| Категория “Пицца” → “Итальянская кухня” | Отчёт “Продажи по категориям” за прошлый месяц — товар “переезжает” в новую категорию, искажая данные |
| Тип dish → good | В Phase 2 влияет на складское списание. Историческая аналитика по типу товара искажается |
Почему не версионность
Полная версионность каталога (снапшоты каждого изменения, откат) — избыточна:
- Заказы уже защищены снапшотами
- Меню франчайзи версионируется отдельно (BR 1.11)
- Версионность каталога добавляет сложность без явной бизнес-потребности
Нужен не откат, а журнал: когда, кто, что поменял.
Решение
Аудит-лог изменений — лёгкая таблица catalog_changelog:
CREATE TABLE catalog_changelog (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
entity_type VARCHAR(50) NOT NULL, -- 'product', 'category', 'price_list_item', 'modifier'
entity_id UUID NOT NULL,
field VARCHAR(100) NOT NULL, -- 'price', 'name', 'category_id', 'status'
old_value TEXT,
new_value TEXT,
changed_by UUID NOT NULL, -- user_id
changed_at TIMESTAMP NOT NULL DEFAULT now()
);Примеры записей:
entity_type: product, entity_id: uuid, field: price, old: 690, new: 750, changed_by: user, changed_at: 2026-04-15
entity_type: product, entity_id: uuid, field: name, old: Пицца Маргарита, new: Маргарита Классическая
entity_type: price_list_item, entity_id: uuid, field: price, old: 690, new: 750
Когда реализовать
На MVP — не реализуем. Заказы защищены, аналитики ещё нет. Аудит-лог добавляется при появлении Report Service (Phase 2).
Как реализовать (Phase 2)
- Middleware / interceptor в Catalog Service: при каждом UPDATE записывает diff в
catalog_changelog - Не блокирует основную операцию (async или after-commit)
- Report Service читает changelog для корректной привязки данных к периодам
Последствия
Положительные
- Аналитика может строить отчёты с учётом исторических изменений
- Нет рефакторинга — одна таблица + middleware, добавляется аддитивно
- Не усложняет MVP
Отрицательные
- До Phase 2 аналитика работает с текущим состоянием (некорректные отчёты по категориям/ценам при изменениях)
Риски
- Если отчёты понадобятся раньше Phase 2 — changelog придётся добавить раньше