feat(dds): добавлен публичный контракт события
Зачем: - Показать слой DDS как договор данных, которому не нужна физическая копия. - Сохранить простой учебный стенд без отдельного маршрута ради узких прав. Что: - Добавлено кластерное представление dds.event_v с явными 44 колонками. - Роли bi_reader разрешено чтение ODS, DDS и DM при договоре чтения через _v. - Согласованы мастер-спека, ADR, справочники архитектуры и живые тикеты этапа. - Зафиксировано исследование поведения DEFINER поверх Distributed. Проверка: - make config-test - make smoke - make check-clickhouse - Приёмочные запросы: равенство ODS/DDS, состав колонок, коды устройств и права bi.
This commit is contained in:
1 parent
4ea9591a16
commit
9ea361d199
11 files changed
+288
-76
No files matched your search
@@ -45,9 +45,8 @@
|
||||
- DDS обслуживает человека с дашбордом: время лежит в поясе счётчика,
|
||||
пересчёт — один раз при наполнении слоя ([дока хранилища](../storage.md),
|
||||
«Часовые пояса»).
|
||||
- Публичный договор каждой сущности — `_v`; роли объектов и проверяемая
|
||||
граница доступа заданы [конвенциями хранилища](../storage.md), «Имена
|
||||
объектов».
|
||||
- Публичный договор каждой сущности — `_v`; роли объектов и конвенция чтения
|
||||
заданы [докой хранилища](../storage.md), «Имена объектов».
|
||||
- Служебные колонки — координаты собственной загрузки слоя; чужие ярлыки не
|
||||
переносятся, а спрашиваются у их слоя по ключу сущности. Вывод правила и
|
||||
цепочка расследования — [модель заказа](order.md).
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
автоматический `PREWHERE` — свойство ODS, представление её не усугубляет.
|
||||
|
||||
Как публичный договор DDS, представление перечисляет колонки явно и следует
|
||||
общей [границе доступа](../storage.md), «Имена объектов».
|
||||
общей [конвенции чтения](../storage.md), «Имена объектов».
|
||||
|
||||
## Язык модели
|
||||
|
||||
@@ -71,8 +71,8 @@ issue #143.
|
||||
- **`ecommerce`** — сырой JSON: сырьё, а не атрибут. Разобранные массивы
|
||||
`purchase_*` и `product_*` в контракте есть; лаба про разбор JSON внутри
|
||||
колонки читает ODS.
|
||||
- **`_load_id`, `_load_ts`** — у представления нет собственной загрузки, а
|
||||
чужие координаты слой не переносит (правило слоя — [модель
|
||||
- **`_load_ts`** — у представления нет собственной загрузки, а чужие
|
||||
координаты слой не переносит (правило слоя — [модель
|
||||
заказа](order.md), «Служебные колонки»); расследование спрашивает ODS по
|
||||
ключу события.
|
||||
|
||||
@@ -96,8 +96,6 @@ issue #143.
|
||||
|
||||
## Не входит
|
||||
|
||||
- DDL представления и его раскатка на кластер — исполнение этапа 4,
|
||||
нарезка #136.
|
||||
- Форма витрин DM — #135.
|
||||
- Лаба со справочником регионов — issue #143, проектирование лаб.
|
||||
|
||||
|
||||
@@ -153,7 +153,7 @@ Airflow. Партиция — день данных; прогон звена DQ
|
||||
состав колонок витрин и классы сверки.
|
||||
- [Дневной конвейер](etl.md) — запуск `dm_transform`, объём прогона,
|
||||
замена партиций на кластере.
|
||||
- [Дока хранилища](storage.md) — имена объектов, граница доступа через
|
||||
`_v`, партиция-донор.
|
||||
- [Дока хранилища](storage.md) — имена объектов, конвенция чтения через `_v`,
|
||||
партиция-донор.
|
||||
- [Карта модели DDS](dds/README.md) — источники витрин.
|
||||
- Резолюция — тикет #135 карты #127.
|
||||
@@ -6,7 +6,7 @@
|
||||
раздел «Что проверено» — чему в этом тексте верить и на каком основании.
|
||||
|
||||
**Что здесь описано и чего ещё нет.** Собран этап 1: кластер из двух шардов,
|
||||
keeper, Kafka, каркас сервисов. Этап 2 идёт: в `sql/ddl/` лежит вся цепочка
|
||||
keeper, Kafka, каркас сервисов. Этап 2 собран: в `sql/ddl/` лежит вся цепочка
|
||||
`Kafka → STG → ODS` — чтец топика `hits`, таблицы сырья, типизированное
|
||||
событие с таблицей ошибок, поверхность актуального состояния и три матвью.
|
||||
Этап 3 добавил вход второго источника и довёл его до ODS: топик `orders`, свой
|
||||
@@ -14,7 +14,8 @@ keeper, Kafka, каркас сервисов. Этап 2 идёт: в `sql/ddl/`
|
||||
состояния. Наполняет всю цепочку даг `orders_ingest` двумя шагами, а не матвью.
|
||||
Тот же этап принёс первый справочник — словарь товаров из общего с генератором
|
||||
CSV-файла. Живёт он вне цепочки слоёв, в зоне `dic`, и читает не файл, а
|
||||
подложку над ним ([ADR 0012](../adr/0012-dictionary-home.md)).
|
||||
подложку над ним ([ADR 0012](../adr/0012-dictionary-home.md)). Этап 4 начат
|
||||
публичным договором события `dds.event_v` над точным состоянием ODS.
|
||||
Дальше по тексту устройство описано так, как оно проектируется; построенное от
|
||||
заложенного отличает карта таблиц в конце.
|
||||
|
||||
@@ -64,21 +65,22 @@ CSV-файла. Живёт он вне цепочки слоёв, в зоне `d
|
||||
проходит по STG, и имена её показывают.
|
||||
|
||||
В DDS публичный договор сущности заканчивается на `_v`. Потребительские запросы
|
||||
и витрины называют только представление; `_rep` и `_dist` остаются ролям
|
||||
загрузки, диагностики и обслуживания. Представление перечисляет колонки явно,
|
||||
даже если его запрос — простая проекция над `_dist`: договор не выдаёт
|
||||
устройство кластера и случайно добавленные физической таблице колонки. У
|
||||
события физической копии в DDS нет, но правило то же: `dds.event_v` — его
|
||||
публичный договор.
|
||||
и витрины называют только представление; `_rep` и `_dist` служат загрузке,
|
||||
диагностике и обслуживанию. Представление перечисляет колонки явно, даже если
|
||||
его запрос — простая проекция над `_dist`: договор не выдаёт устройство
|
||||
кластера и случайно добавленные в физическую таблицу колонки. У события
|
||||
физической копии в DDS нет, но правило то же: `dds.event_v` — его публичный
|
||||
договор.
|
||||
|
||||
Граница доступа — часть договора, а не следствие имени. Обычное представление
|
||||
создаётся с явными `DEFINER = CURRENT_USER SQL SECURITY DEFINER`: определивший
|
||||
его пользователь читает источники, потребительская роль получает `SELECT` на
|
||||
`_v`, физические объекты — роль загрузки или диагностики. При стандартном
|
||||
`INVOKER` потребителю нужны были бы права и на источник ([документация
|
||||
ClickHouse](https://clickhouse.com/docs/sql-reference/statements/create/view#sql-security)).
|
||||
Значит реализация публичной поверхности закончена, когда запрос
|
||||
потребительской ролью проходит через `_v` и отклоняется для `_rep` и `_dist`.
|
||||
Право доступа здесь намеренно шире договора. Роль `bi_reader` может читать
|
||||
любые объекты ODS, DDS и DM, но физические объекты от этого не становятся
|
||||
публичной поверхностью. Конвенцию держат явный список колонок, документация и
|
||||
ревью, а не запрет на физические таблицы.
|
||||
|
||||
Широкое право принято в [ADR 0007](../adr/0007-clickhouse-access.md): узкая
|
||||
граница поверх `Distributed` потребовала бы отдельной механики. Механизм
|
||||
ClickHouse и отклонённые варианты записаны в
|
||||
[исследовании](../research/2026-08-25-clickhouse-distributed-view-security.md).
|
||||
|
||||
## Раскладка по шардам
|
||||
|
||||
@@ -204,9 +206,9 @@ ODS и в таблицу ошибок. Нужен ли он выше ODS, реш
|
||||
|
||||
`ods.event_v` — обычное представление над `ods.event_dist FINAL`. Оно сохраняет
|
||||
имена, типы и зерно события, но всегда возвращает актуальную версию. Актуальное
|
||||
состояние читают через него, а не повторяют `FINAL` в каждом запросе. Будущее
|
||||
`dds.event_v` отвечает за другое: даёт событию язык бизнес-модели, в том числе
|
||||
snake_case-имена и расшифровку кодов.
|
||||
состояние читают через него, а не повторяют `FINAL` в каждом запросе.
|
||||
`dds.event_v` отвечает за другое: даёт событию язык бизнес-модели, в том
|
||||
числе snake_case-имена и расшифровку кодов.
|
||||
|
||||
## Версии заказов
|
||||
|
||||
@@ -495,8 +497,8 @@ SQL-файлы исполняет штатный `SQLExecuteQueryOperator`. Пр
|
||||
|
||||
### DDL
|
||||
|
||||
Файлы лежат в `sql/ddl/` и применяются по порядку имён. Сначала все статичные
|
||||
объекты, потом матвью — тогда к моменту создания матвью её цель уже существует.
|
||||
Файлы лежат в `sql/ddl/` и применяются по порядку имён: зависимости создаются
|
||||
раньше потребителей.
|
||||
|
||||
| Файл | Что в нём |
|
||||
|---|---|
|
||||
@@ -506,19 +508,20 @@ SQL-файлы исполняет штатный `SQLExecuteQueryOperator`. Пр
|
||||
| `20-ods-tables.sql` | типизированное событие, версии заказа и обе таблицы ошибок |
|
||||
| `30-ods-views.sql` | актуальные события, текущие заказы и матвью разбора в ODS |
|
||||
| `40-stg-views.sql` | матвью приёма: чтец в сырьё |
|
||||
| `50-dds-views.sql` | публичный договор события на языке модели DDS |
|
||||
|
||||
Справочники идут сразу за базами: зона `dic` не зависит ни от одного слоя, и
|
||||
правила порядка слоёв к ней не применяются.
|
||||
|
||||
Порядок остальных задают два правила. Первое: матвью принадлежит слою своей
|
||||
цели, а не источника, — разбор из STG в ODS лежит среди файлов ODS, потому что
|
||||
наполняет ODS. Второе: матвью приёма создаётся последней из всех, и потому
|
||||
нарушает нумерацию слоёв. Kafka-движок начинает читать топик, когда к нему
|
||||
привязывают первую матвью; создай её раньше разбора — и всё, что доедет в
|
||||
зазоре, ляжет в сырьё и не попадёт в ODS никуда, ни в событие, ни в ошибки. На
|
||||
пустом топике зазор безвреден, поэтому первый прогон о нём не скажет. Проснётся
|
||||
он, когда тома ClickHouse снесены, а данные Kafka целы, — то есть на обычной
|
||||
отладке.
|
||||
цели, а не источника, — разбор из STG в ODS лежит среди файлов ODS, потому
|
||||
что наполняет ODS. Второе: последней среди матвью цепочки Kafka создаётся
|
||||
матвью приёма, и потому она нарушает нумерацию слоёв. Kafka-движок начинает
|
||||
читать топик, когда к нему привязывают первую матвью; создай её раньше
|
||||
разбора — и всё, что доедет в зазоре, ляжет в сырьё и не попадёт в ODS
|
||||
никуда, ни в событие, ни в ошибки. На пустом топике зазор безвреден,
|
||||
поэтому первый прогон о нём не скажет. Проснётся он, когда тома ClickHouse
|
||||
снесены, а данные Kafka целы, — то есть на обычной отладке.
|
||||
|
||||
Файлы применяет даг `world_initialize` с ноды 1 отдельной учётной записью
|
||||
`lifecycle`: один файл — одна последовательная задача
|
||||
@@ -546,7 +549,8 @@ SQL-файлы исполняет штатный `SQLExecuteQueryOperator`. Пр
|
||||
|
||||
## Карта таблиц
|
||||
|
||||
Ниже — то, что закладывают этапы 2 и 3; всё перечисленное лежит в `sql/ddl/`.
|
||||
Ниже — объекты, уже построенные этапами 2–4; всё перечисленное лежит в
|
||||
`sql/ddl/`.
|
||||
|
||||
| База | Объект | Что это |
|
||||
|---|---|---|
|
||||
@@ -562,6 +566,7 @@ SQL-файлы исполняет штатный `SQLExecuteQueryOperator`. Пр
|
||||
| `ods` | `ods.order_rep` / `_dist` | типизированные версии заказа |
|
||||
| `ods` | `ods.order_v` | текущая версия заказа на языке источника |
|
||||
| `ods` | `ods.order_errors_rep` / `_dist` | строки слепка, не прошедшие строгий приём |
|
||||
| `dds` | `dds.event_v` | событие на языке бизнес-модели без физической копии |
|
||||
| `dic` | `dic.products_file` | чтец CSV-каталога, общего с генератором |
|
||||
| `dic` | `dic.products` | словарь товаров поверх подложки |
|
||||
|
||||
@@ -569,8 +574,9 @@ SQL-файлы исполняет штатный `SQLExecuteQueryOperator`. Пр
|
||||
`INSERT SELECT` одной задачи `parse_batch` из файла
|
||||
`sql/ods/order_parse.sql`.
|
||||
|
||||
Слой DDS и слой DM появляются на следующих этапах; их состав задан разделом
|
||||
7 мастер-спеки и переносится сюда по мере постройки.
|
||||
Слой DDS начат представлением `dds.event_v`; остальные его сущности и слой DM
|
||||
появятся в следующих тикетах этапа. Их состав задан разделом 7 мастер-спеки и
|
||||
переносится сюда по мере постройки.
|
||||
|
||||
## Что проверено
|
||||
|
||||
|
||||
Reference in new issue
Block a user