docs(orders): зафиксирован версионный приём заказов

- Зачем:
  - отменённая подмена партиции snapshot_date противоречила порционному чтению Kafka и могла обучать потере ранее принятых версий.
- Что:
  - добавлены спецификация приёма заказов и ADR о версионном ODS с ods.order_v.
  - согласованы мастер-спека, дока хранилища, ADR 0008 и исследование формата.
  - зафиксированы граница приёма, координаты загрузки, диагностические повторы и отложенное проектирование DDS.
- Проверка:
  - git diff --cached --check.
  - горячее ревью по правилам репозитория и принятому решению.
  - два прохода холодного ревью.
This commit is contained in:
2026-08-16 21:42:11 +03:00
parent 8d54a3caba
commit ede1df765c
6 changed files with 311 additions and 65 deletions
+14 -4
View File
@@ -1,6 +1,13 @@
# ADR 0008. Приём заказов: пакетный забор слепка, инициируемый Airflow
Дата: 12 августа 2026 года. Статус: принято. Реализация — отдельным тикетом.
Дата: 12 августа 2026 года. Статус: частично заменено
[ADR 0010](0010-order-versions-in-ods.md). Реализация — отдельным тикетом.
Сохраняются пакетный забор, `RawBLOB`, один чтец на `clickhouse-01`, одна
партиция топика и отсутствие матвью. Отменены граница «одно чтение — полный
слепок», замена партиции `snapshot_date`, ODS без дедупликации и готовая схема
`dds.order` с `argMax`. Действующая форма STG → ODS описана в
[спецификации приёма заказов](../specs/2026-08-16-order-ingestion.md).
## Решение
@@ -128,7 +135,9 @@
## Что проверено
По документации ClickHouse через MCP Context7, 12 августа 2026 года.
Документация ClickHouse проверена через MCP Context7 12 августа 2026 года.
Предел порции одного опроса Kafka дополнительно снят 16 августа на локальном
ClickHouse `26.3.17.56`.
- Прямое чтение из движков-очередей (Kafka, RabbitMQ, FileLog) запрещено
начиная с версии 21.12 и открывается настройкой
@@ -138,8 +147,9 @@
- Прямое чтение офсеты по умолчанию **не** коммитит; коммит включается
настройкой `kafka_commit_on_select` на самой таблице. Это тот подводный
камень, который молчит на первом прогоне и вылезает на втором.
- Сколько строк отдаёт одно чтение, задаёт `kafka_max_block_size`. При слепке
порядка полутора тысяч строк это один блок с запасом.
- Прямое чтение возвращает одну порцию, полученную одним опросом Kafka. При
настройках стенда её предел — 65 409 сообщений, поэтому слепок порядка
полутора тысяч строк помещается с запасом.
- Про `Distributed` поверх Kafka документация не говорит ничего — ни
поддержки, ни запрета.
+37
View File
@@ -0,0 +1,37 @@
# ADR 0010. Заказы в ODS: версии сущности вместо подмены слепка
Дата: 16 августа 2026 года. Статус: принято. Частично заменяет
[ADR 0008](0008-order-ingestion.md).
## Решение
Пакетный забор заказов остаётся прямым чтением байтового Kafka-чтеца по
команде Airflow, но порция чтения больше не считается полным слепком и не
публикуется заменой партиции `snapshot_date`. Прочитанные строки получают
`_load_id` запуска, разбираются из одного среза STG в годные строки и ошибки,
а `ods.order_snapshot` хранит принятые версии заказа в
`ReplacingMergeTree(updated_at)`. Ключ сущности — `order_id`, партиция строится
от неизменного `created_at`, все версии ключа направляются на один шард.
`snapshot_date` остаётся датой наблюдения источника, `_load_id` — координатой
запуска приёма, `_load_ts` — временем прибытия строки. Ни одна из них не
заменяет бизнес-версию `updated_at`. Физическая таблица может показывать
несколько версий; точное текущее состояние ODS открывает `ods.order_v`, которое
скрывает `FINAL` или равносильный способ выбора последней версии.
Модель заказа в DDS этим решением не задаётся. DDS получает устойчивую
типизированную поверхность ODS и отдельно решает зерно, связи и способ
материализации своей модели.
## Почему отменена подмена партиции
Прямой `SELECT` Kafka Engine заканчивается после одной полученной порции, а
протокол не несёт признака конца слепка. Поэтому `snapshot_date` не доказывает,
что в STG собрана полная партиция, и её подмена могла бы удалить уже принятые
версии прошлого дня. Маркер конца, опись или фиксация конечных офсетов сделали
бы границу настоящей, но добавили бы новый протокол без нужного стенду урока.
Малый объём позволяет оставить одно чтение на запуск как проверяемое
эксплуатационное допущение, а не границу полноты. Полный контракт разбора,
граница брака и поведение повторов заданы в
[спецификации приёма заказов](../specs/2026-08-16-order-ingestion.md).