docs(course): расщеплён план уроков и зафиксирован аудит путей

- Зачем:
  - середина пайплайна перегружала один урок тремя паттернами; нужны честный такт и разведённые слои.
- Что:
  - середина расщеплена: ODS и DDS — отдельные уроки (один паттерн на урок), DM демотирован в поверхность потребления; всего 7 уроков.
  - зафиксированы финальные вердикты аудита и список правок по урокам (LEARNING_PLAN §3/§3.1), включая гейт целостности DAG.
  - в LESSON_STANDARD добавлены шаг отката «верни как было» и артефакт на сессию; в PRD обновлены скоуп и такт ~день на урок.
- Проверка:
  - вычитка docs/course/{PRD,LEARNING_PLAN,LESSON_STANDARD}.md: номера уроков, скоуп и перекрёстные ссылки сходятся.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-03 21:22:07 +03:00
co-authored by Claude Opus 4.8
parent aecbf392d9
commit d8c5e61a3a
3 changed files with 132 additions and 31 deletions
+103 -22
View File
@@ -1,19 +1,26 @@
# План обучения: курс «Кликстрим на ClickHouse» # План обучения: курс «Кликстрим на ClickHouse»
> Статус: черновик (скелет). Дата: 2026-06-01. > Статус: черновик. Дата: 2026-06-03 (аудит путей выполнен; середина расщеплена —
> один паттерн на урок, всего 7 уроков, см. §1–2).
> Назначение: высокоуровневый маршрут менти по курсу — карта уроков, порядок, > Назначение: высокоуровневый маршрут менти по курсу — карта уроков, порядок,
> результаты аудита эталонных путей. Рамка курса (зачем/что/скоуп) — в `PRD.md`; > результаты аудита эталонных путей. Рамка курса (зачем/что/скоуп) — в `PRD.md`;
> как устроен отдельный урок — в `LESSON_STANDARD.md`. > как устроен отдельный урок — в `LESSON_STANDARD.md`.
> >
> Этот файл стартовый скелет. Детальный аудит путей и финальные вердикты > Раздел 3 содержит финальные вердикты аудита и конкретный список правок —
> дописываются перед стартом уроков. > их применяем при написании соответствующих уроков, а не отдельным забегом.
--- ---
## 1. Маршрут ## 1. Маршрут
Порядок линейный — уроки 0→4 идут цепочкой, повторяя сам пайплайн. Мониторинг (4) Порядок линейный — уроки 1→4 повторяют сам пайплайн (STG → ODS → DDS → оркестрация),
и Superset (5) более самостоятельны и работают как надстройки. а урок 0 — разминка перед ним. Мониторинг (5) и Superset (6) более самостоятельны и
работают как надстройки поверх готовых данных.
Принцип нарезки — **один прод-паттерн на урок** (`LESSON_STANDARD` §2). Поэтому
середина пайплайна разнесена: типизация+DQ (ODS) и сборка сущностей (DDS) — разные
уроки. Витрины DM **не отдельный урок**: их показываем в деле там, где их потребляют —
в мониторинге (DQ-витрины) и BI (traffic/utm-витрины).
**Что нужно знать заранее по Kafka:** перед уроком 0 менти смотрит обзорное видео по **Что нужно знать заранее по Kafka:** перед уроком 0 менти смотрит обзорное видео по
Kafka из роадмапа — оно даёт словарь терминов. Урок 0 связывает этот словарь с тем, Kafka из роадмапа — оно даёт словарь терминов. Урок 0 связывает этот словарь с тем,
@@ -25,33 +32,107 @@ Kafka из роадмапа — оно даёт словарь терминов.
|---|------|-------------------------------|--------|-------| |---|------|-------------------------------|--------|-------|
| 0 | Вводный урок по Kafka | Kafka UI: топики, партиции, offset'ы, consumer-группы, отставание (lag) | обязательный | наблюдение | | 0 | Вводный урок по Kafka | Kafka UI: топики, партиции, offset'ы, consumer-группы, отставание (lag) | обязательный | наблюдение |
| 1 | Заземление Kafka → ClickHouse | `sql/ddl/stg/10_stg.sql` (Kafka engine → MV → MergeTree) | обязательный | руки | | 1 | Заземление Kafka → ClickHouse | `sql/ddl/stg/10_stg.sql` (Kafka engine → MV → MergeTree) | обязательный | руки |
| 2 | Слоёный ETL: где MV, а где батч | `sql/ods/*`, `sql/dds/*`, `sql/dm/*` (батч поверх стримингового STG) | обязательный | руки | | 2 | STG → ODS: типизация и DQ-split | `sql/ods/20_stg_to_ods.sql` + DDL `sql/ddl/ods/20_ods.sql` | обязательный | руки |
| 3 | Оркестрация в Airflow | `airflow/dags/etl_pipeline_dag.py` (зависимости, проверки, остановка при нарушениях) | обязательный | руки | | 3 | ODS → DDS: сборка сущностей | `sql/dds/30_ods_to_dds.sql` + DDL `sql/ddl/dds/30_dds.sql` (argMax, UNION, сироты) | обязательный | руки |
| 4 | Мониторинг | Prometheus + Grafana + экспортёры | обязательный | наблюдение | | 4 | Оркестрация в Airflow | `airflow/dags/etl_pipeline_dag.py` (зависимости, гейты, остановка при нарушениях) | обязательный | руки |
| 5 | BI-витрина | Superset поверх ClickHouse | опциональный | руки | | 5 | Мониторинг | Prometheus + Grafana + экспортёры | обязательный | наблюдение |
| 6 | BI-витрина | Superset поверх ClickHouse | опциональный | руки |
Урок 0 — обязательная разминка (без правок кода, только наблюдение); уроки 1–3 Урок 0 — обязательная разминка (без правок кода, только наблюдение); уроки 1–4
с управляемыми правками; урок 4 ближе к наблюдению (глубину уточняем, см. с управляемыми правками; урок 5 ближе к наблюдению (глубину уточняем, см.
«Открытые вопросы» в `PRD.md`). «Открытые вопросы» в `PRD.md`).
**Где «MV vs батч»:** контраст из цели №2 PRD — это мост уроков 1→2. Урок 1 (STG)
заканчивается вопросом «мы приземлили поток через MV — почему дальше не MV?»; урок 2
(ODS) отвечает: батч ради наблюдаемости и управляемости пересчёта. Отдельным уроком
контраст не выделяем — он живёт на стыке.
**Витрины DM** показываем в деле в уроках 5–6; единственную концепцию DM («VIEW
сейчас, материализуем если затормозит») даём короткой заметкой в финале урока 3.
## 3. Аудит эталонных путей ## 3. Аудит эталонных путей
Вердикт по каждому пути — один из трёх: **годно как есть / точечно править / Вердикт по каждому пути — один из трёх: **годно как есть / точечно править /
переписать** (критерии «учебного качества» — в `LESSON_STANDARD.md`). переписать** (критерии «учебного качества» — в `LESSON_STANDARD.md`).
Предварительная оценка (до детального аудита): Финальная оценка (детальный аудит от 2026-06-03):
| Путь | Файлы | Вердикт (предв.) | Заметки | | Урок | Путь | Файлы | Вердикт |
|------|-------|------------------|---------| |------|------|-------|---------|
| STG (Kafka→CH) | `sql/ddl/stg/10_stg.sql` | годно как есть | внятные русские комментарии, метаданные доставки, обработка ошибок, партиционирование | | 1 | STG (Kafka→CH) | `sql/ddl/stg/10_stg.sql` | **годно как есть** (+1 строка «зачем») |
| ETL слои | `sql/ods/*`, `sql/dds/*`, `sql/dm/*` | точечно править | логика и комментарии крепкие; проверить «тест одного прохода» | | 2 | STG→ODS | `sql/ods/20_stg_to_ods.sql` + DDL `sql/ddl/ods/20_ods.sql` | **точечно править** |
| Airflow DAG | `airflow/dags/etl_pipeline_dag.py` | под вопросом | нужен детальный аудит | | 3 | ODS→DDS (+ демоут DM) | `sql/dds/30_ods_to_dds.sql` + DDL `sql/ddl/dds/30_dds.sql`; DM `sql/dm/40_dds_to_dm.sql` + `sql/ddl/dm/40_dm.sql` | **точечно править** |
| Мониторинг | `configs/*`, экспортёры | под вопросом | нужен детальный аудит | | 4 | Airflow DAG | `airflow/dags/etl_pipeline_dag.py` | **точечно править** |
| 5 | Мониторинг | `configs/*`, экспортёры | **годно как есть** (для режима наблюдения) |
Финальные вердикты и список конкретных правок — дописать перед стартом уроков. > Карты путей раздела 2 включают и DDL целевых таблиц (`sql/ddl/{ods,dds}/*`), а не
> только батч-трансформации: без формы целевых таблиц слой читается неполно.
### 3.1. Список правок (применяем при написании урока)
Правки точечные, делаем не отдельным забегом, а в составе соответствующего урока.
**Урок 1 — STG (`sql/ddl/stg/10_stg.sql`):**
- [ ] Добавить одну строку «зачем» к `fromUnixTimestamp64Milli(toInt64(_timestamp_ms))`
в MV — это единственный неочевидный трюк файла (конвертация Kafka-таймстампа).
- Колоночные комментарии-пересказы (`-- Партиция`, `-- Имя топика`) безвредны — не трогаем.
- В финале урока — мост к уроку 2: вопрос «почему дальше не MV?».
**Урок 2 — STG→ODS, типизация + DQ-split (`sql/ods/20_stg_to_ods.sql` + DDL `sql/ddl/ods/20_ods.sql`):**
- [ ] Добавить однострочный «поток данных» в шапку `20_stg_to_ods.sql`
(`stg.*_raw → ods.* + ods.*_errors`) — п.3 чеклиста.
- [ ] Добавить строку «зачем»: основная таблица = валидный ключ (но может иметь
`parse_errors` по неключевым полям), а `*_errors` = любая ошибка. Без этого
непонятно, почему одна строка попадает в оба места (двойной учёт) — проваливается
тест одного прохода.
- [ ] Убрать мусор: в `sql/ddl/ods/20_ods.sql` (стр. ~15–25) — восемь
`DROP TABLE IF EXISTS stg.mv_*_to_ods` (чистка legacy-MV). Шум прошлой
архитектуры, мента читает его раньше сути. Вынести из учебного файла.
- [ ] Минор: в `20_ods.sql` разнобой партиционирования (`browser` по `event_date`,
остальные по `src_ingest_ts`) — одна строка «почему» либо унифицировать.
- В «Зачем» урока — ответ на мост из урока 1: батч ради наблюдаемости/управляемости.
**Урок 3 — ODS→DDS, сборка сущностей (`sql/dds/30_ods_to_dds.sql` + DDL `sql/ddl/dds/30_dds.sql`):**
- [ ] Добавить однострочный «поток данных» в шапку `30_ods_to_dds.sql`
(`ods.* → dds.click + dds.event`) — п.3 чеклиста.
- [ ] В финале урока — **recap всей цепочки** STG→ODS→DDS: защита от фрагментации после
расщепления середины (менти должен собрать сквозную модель, а не три изолированных слоя).
- [ ] **Демоут DM** оформляем здесь: убрать мусор в `sql/dm/40_dds_to_dm.sql`
(стр. ~14–37, закомментированный «пример материализации витрины») и превратить его
в короткую заметку «VIEW сейчас, материализуем если затормозит, см. `docs/ARCHITECTURE.md`».
Добавить «поток данных» в шапку `40_dds_to_dm.sql`.
- [ ] Минор: `sql/ddl/dm/40_dm.sql` — магическое `1919` в `groupArraySample`
(строка «зачем» или упростить).
- Сами витрины DM показываем в деле в уроках 5–6, отдельного разбора не делаем.
**Урок 4 — Airflow DAG (`airflow/dags/etl_pipeline_dag.py`):**
- [ ] **Главная правка (код↔доки):** сделать `check_dds_integrity` честным гейтом —
добавить `assert_dds_integrity` (PythonOperator), роняющий DAG при
`orphan_events > 0`. Сейчас «проверка» только считает сирот в xcom и пишет их в
`dq_summary`, но DAG остаётся зелёным, хотя `LESSON_STANDARD` §3 и `PRD` §2 (цель 3)
обещают остановку при нарушении целостности. После правки доки и код сходятся.
- [ ] **Управляемая правка урока 4** строится на этом гейте: менти намеренно ломает
целостность (вставляет «осиротевшее» событие) и видит, как DAG краснеет на
`assert_dds_integrity`. Опирается на понятие сирот из урока 3.
- [ ] Добавить ASCII-поток задач в docstring DAG
(`precheck → transform: wait → ods → dq → branch → dds → integrity → dm → validate`)
— для теста одного прохода.
- Замечание: `check_ods_quality` тоже measure-only (метрики в xcom, без гейта) — это
ок и намеренно (DQ по `parse_errors` информативен, но не блокирует). В тексте
урока развести: какие проверки **гейтят** пайплайн, а какие только **измеряют**.
**Урок 5 — мониторинг (`configs/*`):**
- Конфиги (`prometheus.yml`, экспортёры, provisioning Grafana) полировать под «учебное
качество кода» не нужно: дашборды/JSON не читаются построчно. Вся учебная нагрузка
ложится на **текст урока** (маршрут по дашбордам + смысл панелей).
- [ ] При написании проверить, что имена дашбордов/панелей/метрик в тексте совпадают
с реальными (`configs/grafana/provisioning/dashboards/*.json`).
- [ ] Кандидат на мини-правку (зеркало урока 4): погасить сервис → увидеть, как панель/
алерт в Grafana краснеет. Решает открытый вопрос PRD про глубину урока (даёт
«сломал-увидел» вместо чистого наблюдения) — обсудить при написании.
## 4. Что дальше ## 4. Что дальше
После согласования этого плана — пишем уроки по одному, по шаблону из Пишем уроки по одному, по шаблону из `LESSON_STANDARD.md`, начиная с урока 1
`LESSON_STANDARD.md`, начиная с урока 1 (Kafka→CH). Урок 0 (разминка на Kafka UI) (Kafka→CH). Урок 0 (разминка на Kafka UI) можно готовить параллельно — он не зависит
можно готовить параллельно — он не зависит от полировки кода. от полировки кода. Правки кода из §3.1 применяем в составе соответствующего урока.
+7 -1
View File
@@ -19,9 +19,15 @@
Например: добавить поле в Materialized View и увидеть его в `*_raw`; «сломать» Например: добавить поле в Materialized View и увидеть его в `*_raw`; «сломать»
запись и увидеть `+1` в таблице ошибок `parse_errors`; сменить `kafka_group_name` запись и увидеть `+1` в таблице ошибок `parse_errors`; сменить `kafka_group_name`
и увидеть, как топик читается заново. Менти меняет — видит эффект — объясняет. и увидеть, как топик читается заново. Менти меняет — видит эффект — объясняет.
**Верни как было** — каждая правка завершается явным шагом отката к чистому
состоянию (откатить изменение либо `make clean/up/ddl/data/transform`), чтобы
самостоятельный менти не застрял со сломанным стендом без ментора.
(Урок 0 — без этого шага, только наблюдение.) (Урок 0 — без этого шага, только наблюдение.)
5. **Проверь себя** — самопроверка (раздел 3). 5. **Проверь себя** — самопроверка (раздел 3).
6. **Принеси на сессию**что доложить ментору и какие вопросы задать. 6. **Принеси на сессию****конкретный артефакт** плюс вопросы: скрин видимого
результата правки (например, красный DAG или `+1` в таблице ошибок), один абзац
«своими словами» про паттерн урока или запрос, который пришлось написать. Артефакт
делает самопроверку проверяемой, а сверку — предметной (критерий успеха `PRD` §5).
## 2. Стандарт качества эталонного кода ## 2. Стандарт качества эталонного кода
+22 -8
View File
@@ -1,6 +1,11 @@
# PRD: продвинутый курс «Кликстрим на ClickHouse» (со звёздочкой) # PRD: продвинутый курс «Кликстрим на ClickHouse» (со звёздочкой)
> Статус: черновик (прообраз PRD). Дата: 2026-06-01. > Статус: черновик (прообраз PRD). Дата: 2026-06-01.
> Поправка 2026-06-03 (разморозка по делу): середина пайплайна расщеплена — ODS и DDS
> теперь разные уроки (принцип «один паттерн на урок»), витрины DM демотированы в
> поверхность потребления. Обязательных уроков стало 0–5, опциональный Superset — урок 6.
> Затронуты §4 (скоуп) и §3/§5 (ожидаемый такт — ~день на урок). Это изменение рамки,
> а не план реализации.
> Назначение документа: зафиксировать для будущих сессий, что это за курс, зачем > Назначение документа: зафиксировать для будущих сессий, что это за курс, зачем
> он, что входит в скоуп работ, а что нет. Это договорная **рамка**, а не план > он, что входит в скоуп работ, а что нет. Это договорная **рамка**, а не план
> реализации и не стандарт уроков (см. раздел «Связанные документы»). > реализации и не стандарт уроков (см. раздел «Связанные документы»).
@@ -55,7 +60,9 @@ Kafka → ClickHouse → BI).
но затачиваем под реальный первый прогон, а не под гипотетических будущих менти. но затачиваем под реальный первый прогон, а не под гипотетических будущих менти.
- **Режим:** самостоятельный, асинхронный. Менти клонирует репозиторий, поднимает - **Режим:** самостоятельный, асинхронный. Менти клонирует репозиторий, поднимает
стенд у себя (`make up`) и идёт по урокам из `docs/course/` рядом с кодом. стенд у себя (`make up`) и идёт по урокам из `docs/course/` рядом с кодом.
- **Роль ментора:** еженедельная сессия-сверка, без построчного разбора кода. Уроки короткие и односоставные — ожидаемый срок прохождения одного **около дня**.
- **Роль ментора:** еженедельная сессия-сверка (покрывает несколько уроков), без
построчного разбора кода.
- **Железо:** стек тяжёлый (Kafka + ClickHouse + Airflow + Superset + Prometheus + - **Железо:** стек тяжёлый (Kafka + ClickHouse + Airflow + Superset + Prometheus +
Grafana одновременно). Считаем наличие подходящего железа данностью; стек не режем Grafana одновременно). Считаем наличие подходящего железа данностью; стек не режем
на части — это усложнило бы жизнь и менти, и автору материала. на части — это усложнило бы жизнь и менти, и автору материала.
@@ -63,8 +70,12 @@ Kafka → ClickHouse → BI).
## 4. Скоуп ## 4. Скоуп
### Входит ### Входит
- **Уроки 04 (обязательные):** вводный урок по Kafka, заземление Kafka→CH, слоёный - **Уроки 05 (обязательные):** вводный урок по Kafka, заземление Kafka→CH, STG→ODS
ETL (где Materialized View, а где батч), Airflow, мониторинг. (типизация + DQ), ODS→DDS (сборка сущностей), Airflow, мониторинг. Принцип нарезки —
один прод-паттерн на урок; контраст «где Materialized View, а где батч» проходит
мостом уроков 1→2.
- Витрины **DM — не отдельный урок**: их показываем в деле там, где их потребляют
(мониторинг и BI). См. `LEARNING_PLAN.md` §12.
- **Аудит и точечная полировка эталонных путей** этих уроков до учебного качества - **Аудит и точечная полировка эталонных путей** этих уроков до учебного качества
(стандарт — в `LESSON_STANDARD.md`). (стандарт — в `LESSON_STANDARD.md`).
- Учебная часть вокруг каждого эталонного пути по единому шаблону урока. - Учебная часть вокруг каждого эталонного пути по единому шаблону урока.
@@ -73,7 +84,7 @@ Kafka → ClickHouse → BI).
обучения `LEARNING_PLAN.md`. обучения `LEARNING_PLAN.md`.
### Опционально ### Опционально
- **Урок 5: Superset (BI-витрина).** Делаем, если останется ресурс; обязательные - **Урок 6: Superset (BI-витрина).** Делаем, если останется ресурс; обязательные
уроки он не блокирует. уроки он не блокирует.
### Не входит ### Не входит
@@ -88,7 +99,8 @@ Kafka → ClickHouse → BI).
## 5. Критерии успеха ## 5. Критерии успеха
- Менти проходит урок за неделю **сам**, без построчного разбора с ментором. - Менти проходит урок **сам**, без построчного разбора с ментором (ожидаемый срок —
около дня на урок: уроки короткие и односоставные).
- Может своими словами объяснить паттерн урока и привязать его к обычной - Может своими словами объяснить паттерн урока и привязать его к обычной
кликстрим-аналитике. кликстрим-аналитике.
- На сессии приносит осмысленные вопросы по сути, а не «застрял на запуске». - На сессии приносит осмысленные вопросы по сути, а не «застрял на запуске».
@@ -98,7 +110,8 @@ Kafka → ClickHouse → BI).
Порядок создания артефактов: Порядок создания артефактов:
1. **`PRD.md`** (этот документ) — рамка: что, зачем, скоуп. **Замороженный** документ. 1. **`PRD.md`** (этот документ) — рамка: что, зачем, скоуп. По умолчанию **заморожен**;
меняется только осознанной поправкой с датой и причиной в шапке (как 2026-06-03).
2. **`LEARNING_PLAN.md`** — высокоуровневый план обучения: карта уроков, маршрут 2. **`LEARNING_PLAN.md`** — высокоуровневый план обучения: карта уроков, маршрут
менти, результаты аудита путей. Пишется после согласования PRD. менти, результаты аудита путей. Пишется после согласования PRD.
3. **`LESSON_STANDARD.md`** — стандарт уроков: шаблон урока, стандарт качества кода, 3. **`LESSON_STANDARD.md`** — стандарт уроков: шаблон урока, стандарт качества кода,
@@ -113,8 +126,9 @@ Kafka → ClickHouse → BI).
## 7. Открытые вопросы / на будущее ## 7. Открытые вопросы / на будущее
- Глубина урока 4 (мониторинг): сколько внутреннего устройства показывать против - Глубина урока 5 (мониторинг): сколько внутреннего устройства показывать против
«просто наблюдай дашборд». «просто наблюдай дашборд». Кандидат — мини-правка «погаси сервис → алерт краснеет»
(зеркало урока 4), см. `LEARNING_PLAN.md` §3.1.
- Нужна ли BI-витрина (Superset) уже в первой версии или переносим на следующую. - Нужна ли BI-витрина (Superset) уже в первой версии или переносим на следующую.
- Переиспользование: после первого прогона — ретроспектива и обобщение материала - Переиспользование: после первого прогона — ретроспектива и обобщение материала
под других менти. под других менти.