docs(generator): закрыты находки финального ревью цепочки

- Зачем:
  - финальный review должен видеть согласованные PRD, issue, курс, Superset и архитектурные документы.
- Что:
  - обновлены PRD, чекбоксы закрытых issue и журнал coordinator-loop.
  - синхронизированы архитектура, карта репозитория, CONTEXT и курс со startup-history-путём.
  - убраны старые маркеры Superset-геокарты после перехода на Top Countries.
- Проверка:
  - rg-проверки финального review по PRD, issue и Superset-маркерам.
  - git diff --cached --check.
This commit is contained in:
ddadmin committed 2026-07-04 23:09:15 +03:00
1 parent 3d4e13c541
commit f8b419d84d
18 files changed
+181 -119

No files matched your search

+32 -33
View File
@@ -27,12 +27,12 @@
flowchart LR
subgraph AF["Airflow"]
DAG1["ddl_init"]
DAG2["kafka_load (bootstrap)"]
DAG2["generator_control"]
DAG3["etl_pipeline"]
end
subgraph GEN["Generator"]
G["generator-service (steady-stream)"]
G["generator-service"]
end
subgraph Kafka["Kafka"]
@@ -57,8 +57,8 @@ flowchart LR
V[витрины VIEW]
end
DAG2 -->|bootstrap JSONL| K
G -->|stream events| K
DAG2 -->|startup-history backfill/import| K
G -->|live после make generator-continue| K
K -->|MV| S
S -->|batch| O
O -->|argMax + JOIN| D1 & D2
@@ -69,10 +69,10 @@ flowchart LR
DAG3 -.->|batch| ODS & DDS
```
В учебном стенде предусмотрены два пути ingest:
В учебном стенде предусмотрены два пути загрузки:
- `bootstrap`: DAG `kafka_load` для разового/контрольного прогона из `data/*.jsonl`;
- `steady-stream`: автономный генератор, публикующий события в Kafka непрерывно.
- `startup-history`: DAG `generator_control` создаёт или импортирует историю, запускает ETL и проверяет витрины;
- `live`: генератор запускается явно через `make generator-continue`, когда нужна непрерывная подача новых событий.
### Слои и их назначение
@@ -80,7 +80,7 @@ flowchart LR
flowchart LR
subgraph AF["Airflow"]
DAG1["ddl_init"]
DAG2["kafka_load (bootstrap)"]
DAG2["generator_control"]
DAG3["etl_pipeline"]
end
@@ -106,8 +106,8 @@ flowchart LR
DM_T["VIEW"]
end
DAG2 -->|bootstrap JSONL| KAFKA
G -->|steady-stream| KAFKA
DAG2 -->|startup-history| KAFKA
G -->|live| KAFKA
KAFKA -->|MV| STG_T
STG_T -->|batch| ODS_T
ODS_T -->|argMax + JOIN| DDS_T -->|VIEW| DM_T
@@ -376,7 +376,6 @@ sequenceDiagram
Compose->>K: docker compose up -d kafka
Compose->>CH: docker compose up -d clickhouse
Compose->>Airflow: docker compose up -d airflow-*
Compose->>Gen: docker compose up -d generator
Compose-->>User: ✅ Инфраструктура готова
User->>Airflow: Trigger ddl_init
@@ -387,14 +386,13 @@ sequenceDiagram
Airflow->>CH: sql/ddl/dm/40_dm.sql
CH-->>User: ✅ Структура БД создана
alt Bootstrap режим
User->>Airflow: Trigger kafka_load
Airflow->>K: precheck + prepare_topics
loop 4 файла
Airflow->>K: KafkaProducer.send(topic, json_line)
end
K-->>User: ✅ Данные в Kafka
else Streaming режим
alt Startup-history режим
User->>Airflow: Trigger generator_control (backfill/import)
Airflow->>K: события стартовой истории
Airflow->>Airflow: trigger etl_pipeline + check
K-->>User: ✅ История в Kafka и витринах
else Live режим
User->>Compose: make generator-continue
loop каждые 1-10 секунд
Gen->>K: send N_t (Poisson) в 4 топика
end
@@ -634,32 +632,33 @@ INSERT INTO dm.daily_traffic SELECT * FROM dm.v_daily_traffic;
### Airflow-оркестрация
Инфраструктура Airflow развёрнута и отвечает за DDL/ETL.
Генератор работает отдельно и не управляется через Airflow DAG-и.
Инфраструктура Airflow развёрнута и отвечает за DDL/ETL и стартовую историю.
Живой генератор контейнеров запускается отдельно через Makefile.
```python
# airflow/dags/ddl_init_dag.py — создание баз/таблиц (ручной запуск при bootstrap)
# airflow/dags/kafka_load_dag.py — bootstrap-загрузка JSONL в Kafka (через kafka-python)
# airflow/dags/ddl_init_dag.py — создание баз/таблиц
# airflow/dags/generator_control_dag.py — backfill/import/check стартовой истории
# airflow/dags/etl_pipeline_dag.py — основной ETL (STG→ODS→DDS→DM)
# airflow/dags/kafka_load_dag.py — архивный ручной путь из JSONL, не основной контур
# Учебный формат:
# - DDL и трансформации выполняются явными SQL-task через ClickHouseOperator;
# - SQL-файлы вызываются по фиксированным путям;
# - ingest может идти двумя путями:
# 1) bootstrap через DAG `kafka_load`;
# 2) непрерывный поток через автономный `generator-service`.
# - загрузка может идти двумя путями:
# 1) startup-history через DAG `generator_control`;
# 2) live-поток через явный `make generator-continue`.
#
# Базовый demo-сценарий:
# ddl_init -> kafka_load -> etl_pipeline
# ddl_init -> generator_control(backfill/import) -> etl_pipeline -> check
# Расширенный учебный сценарий:
# generator-service (continuous) + периодический etl_pipeline
# make generator-continue + периодический etl_pipeline
```
**DAG `kafka_load`**:
- Загрузка данных из `data/*.jsonl` в Kafka через `kafka-python`
- TaskGroup `precheck`: проверка Kafka, файлов, параметров
- TaskGroup `ingest`: создание топиков → параллельная загрузка 4 потоков → проверка
- Параметры: `limit` (0 = все), `reset_topics`
**DAG `generator_control`**:
- `backfill`: создаёт стартовую историю через генератор
- `import`: импортирует портативный артефакт стартовой истории
- `check`: сверяет ClickHouse с manifest стартовой истории
- После `backfill` и `import` запускает `etl_pipeline` с `full_refresh`
**Подключение к ClickHouse:**
- Connection: `clickhouse_default`
+2 -1
View File
@@ -588,7 +588,8 @@ make generated-history-check
## Быстрые проверки
- Kafka ingest: наличие данных генератора в `stg.*` и типизированных строк в `ods.*`.
- Airflow UI: `http://localhost:8080` показывает DAG `ddl_init`, `kafka_load`, `etl_pipeline`.
- Airflow UI: `http://localhost:8080` показывает DAG `ddl_init`, `generator_control`,
`kafka_load`, `etl_pipeline`; основной ручной пульт генератора — `generator_control`.
- BI: витрина `dm.v_events_enriched` отвечает за разумное время при фильтре по дате.
---
+1
View File
@@ -7,6 +7,7 @@
### Airflow (ручной и учебный путь запуска)
- `airflow/dags/ddl_init_dag.py` — инициализация схемы ClickHouse
- `airflow/dags/generator_control_dag.py` — Airflow-пульт стартовой истории: backfill/import/check
- `airflow/dags/kafka_load_dag.py` — архивная загрузка в Kafka из JSONL; не основной источник аналитики
- `airflow/dags/etl_pipeline_dag.py` — ETL процесс STG -> ODS -> DDS -> DM
- `airflow/dags/utils/kafka_helpers.py` — helper-функции для Kafka
+5 -5
View File
@@ -68,17 +68,17 @@ KPI разложены в одну строку по 12-колоночной с
#### География
- **🌍 Top Countries by Events** — top-15 стран по количеству событий
(`COUNT(*)`, единицы — события, штуки). Столбцы заменили legacy world map:
(`COUNT(*)`, единицы — события, штуки). Столбцы заменили прежнюю геовизуализацию:
на текущем разреженном распределении так видны страна, значение, порядок и
tooltip. Перекос стран приходит из гео-фактуры статического сида
`geo_by_click_id`; своя генерация гео описана как отдельный будущий шаг в
ADR-0006 и не лечится настройкой чарта.
> **Что проверили по Superset.** Через MCP Context7 проверили `/apache/superset`:
> legacy world map описан как отдельный legacy-плагин, а ECharts bar chart имеет
> прежний геоплагин описан как legacy-плагин, а ECharts bar chart имеет
> штатные параметры `show_legend`, `rich_tooltip`, подписи осей и формат чисел.
> Поэтому для разреженной географии выбран top-N bar chart
> (`viz_type: echarts_timeseries_bar`), а не донастройка `world_map`.
> (`viz_type: echarts_timeseries_bar`), а не донастройка прежней геовизуализации.
#### Маркетинг
- **🔗 UTM Effectiveness Table** — таблица эффективности UTM-меток
@@ -119,7 +119,7 @@ KPI разложены в одну строку по 12-колоночной с
| 🌐 Browser | `browser_name` | Multi-select | Charts на `dm.v_events_enriched` |
Фильтры работают через левую панель Superset. Click-to-filter между виджетами не включен:
клик по сектору pie chart, карте, строке таблицы или funnel не меняет остальные charts.
клик по сектору pie chart, столбцу Top Countries, строке таблицы или funnel не меняет остальные charts.
Фильтр применяется только к charts, где есть нужное поле. Агрегированные витрины
`dm.v_utm_effectiveness` и `dm.v_top_pages_daily` содержат `event_date`, но не содержат
@@ -182,7 +182,7 @@ python /app/superset_init/init_superset.py
1. Перейдите в **Charts → + Chart**
2. Выберите датасет (например, `dm.v_events_enriched`)
3. Настройте визуализацию:
- **Viz Type:** Big Number / Line Chart / Pie Chart / World Map / Table
- **Viz Type:** Big Number / Line Chart / Pie Chart / ECharts Bar / Table
- **Metrics:** COUNT(*), COUNT(DISTINCT ...)
- **Dimensions:** группировки
- **Filters:** фильтры
+3 -2
View File
@@ -95,8 +95,9 @@ Kafka → ClickHouse → BI).
- **Аудитория:** продвинутые менти, прошедшие базовую программу. Пишем обобщённо,
но затачиваем под реальный первый прогон, а не под гипотетических будущих менти.
- **Режим:** самостоятельный, асинхронный. Менти клонирует репозиторий, поднимает
стенд у себя (`make up`) и идёт по урокам из `docs/course/` рядом с кодом.
- **Режим:** самостоятельный, асинхронный. Менти клонирует репозиторий, готовит
стенд штатным путём (`make generated-history-analytics && make up`) и идёт по
урокам из `docs/course/` рядом с кодом.
Уроки короткие и односоставные — ожидаемый срок прохождения одного **около дня**.
- **Роль ментора:** еженедельный созвон-сверка (покрывает несколько уроков), без
построчного разбора кода.
+1 -1
View File
@@ -310,7 +310,7 @@ Native filters создаются в `build_dashboard_metadata`. Там есть
- `Browser` по `browser_name`.
Эти фильтры задаются в левой панели dashboard. Click-to-filter между виджетами не включен:
клик по сектору pie chart, карте, строке таблицы или funnel не меняет остальные charts.
клик по сектору pie chart, столбцу Top Countries, строке таблицы или funnel не меняет остальные charts.
Фильтр применяется только к charts, где есть нужное поле. `Country`, `Device Type` и
`Browser` работают с charts на `dm.v_events_enriched`; агрегированные витрины для UTM,
@@ -32,8 +32,9 @@
## Non-goals
- Не модернизируем **типы** виджетов (`pie`/`world_map`/`dist_bar` → ECharts) —
отдельный косметический заход.
- Не модернизируем **типы** виджетов (`pie`/геовизуализация/`dist_bar` → ECharts) —
отдельный косметический заход. Геоблок позже заменён задачей 10
`generator-model-time-startup-history`.
- Не трогаем эмодзи в тайтлах, секции-заголовки, языковой винегрет.
- Не трогаем генератор.
- Не правим код `create_dashboard.py` в рамках этой спеки — это реализация.
@@ -60,7 +61,7 @@ geo_country: 40 | device_type: 2 (Mobile/Computer) | utm_source: 5 | utm_medium:
| Avg Events/Session | big_number_total | оставить, переименовать `/Visit` |
| Top Pages | dist_bar | **апгрейд в Funnel** (центральный учебный объект) |
| UTM Effectiveness | table | оставить; **выкинуть колонки purchases/add_to_cart** (всегда 0) |
| Geography Map | world_map | оставить (40 стран; тип модернизировать отдельно) |
| Geography Map | прежняя геовизуализация | позже заменена на `Top Countries by Events` |
| Traffic by Device | pie | оставить |
| Events by Hour | line | **проверить на пустоту**, иначе дропнуть |
| Data Quality Summary | dist_bar | оставить (⚠️ позже пересмотрено — см. ниже) |