docs(course): каркас курса и переобвязка уроков 0–6 на путь import (#21)

Зачем: после редизайна пути менти курс ссылался на старый путь
generated-history-analytics/backfill и не проходился по новому стенду.

Что: в README курса — единый блок подготовки и канонического сброса
(make clean -> make up + ddl_init/world_init -> make superset-init),
таблица уроков дополнена лабами 07–08 («в работе»); LESSON_STANDARD и
уроки 0–6 ссылаются на канонический блок; урок 1 переведён на дозаливку
через world_next_day (кнопкой-анонсом, цена в минутах названа); урок 4 —
лесенка DAG-ов; урок 5 — словарь «база import / живой поток»; урок 6
обязателен; цифры старого мира помечены маркером «сверить-на-стенде».

Проверка: grep по generated-history-analytics/backfill в docs/course/
пуст; правки только в docs/course/; git diff --check чистый.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-23 13:22:41 +03:00
co-authored by Claude Opus 4.8
parent b57a4e2292
commit cc1cffe2f3
11 changed files with 142 additions and 171 deletions
+17 -38
View File
@@ -49,15 +49,9 @@
## 2. Руки: убедись, что данные текут
Поднимаем стенд и создаём стартовую историю. Это штатный путь курса: готовый источник
данных стенда пишет события в Kafka, ClickHouse читает их в STG, затем batch строит
ODS, DDS и DM. Файлы `data/*.jsonl` в этом пути не источник аналитики; пока это только
кладовка значений для источника данных стенда.
```bash
make generated-history-analytics
make up
```
Подготовь стенд по
[канонической инструкции курса](../README.md#подготовка-и-канонический-сброс).
После успешного `world_init` эталонный мир уже прошёл путь Kafka → STG → ODS → DDS → DM.
Теперь смотрим, что доехало до ClickHouse. Открой SQL-консоль:
`http://localhost:9123/play` (или Kafka UI на `http://localhost:8082`, чтобы тем же
@@ -189,27 +183,23 @@ SELECT
FROM stg.kafka_browser_raw;
```
**Перезаливаем срез, чтобы новая колонка заполнилась.** Сначала чистим только таблицу
приёмника — иначе рядом останутся строки из секции 2, вставленные ещё *до*
`ADD COLUMN`, и в них `kafka_msg_ts` будет пустой (`1970-01-01`):
**Дозаливаем следующий день, чтобы новая колонка заполнилась.** Не очищай
`stg.browser_raw`: `world_next_day` растит уже импортированный мир, а его финальная
проверка сверяет весь накопленный результат. В старых строках, вставленных до
`ADD COLUMN`, `kafka_msg_ts` останется пустым (`1970-01-01`) — ниже мы их отфильтруем.
```sql
TRUNCATE TABLE stg.browser_raw;
```
Затем повторно создаём стартовую историю **без очистки volumes**. Это важно:
`CLEAN_START=0` сохраняет твою новую колонку и пересозданное MV, но добавляет свежие
сообщения в Kafka, чтобы ClickHouse прочитал их уже с новой схемой.
```bash
CLEAN_START=0 make generated-history-analytics
```
Открой Airflow и кнопкой **Trigger DAG** запусти `world_next_day` с пустой формой.
Он дозальёт в Kafka следующий день, а ClickHouse прочитает новые сообщения уже с
изменённой схемой. Такой прогон занимает несколько минут — дождись состояния
`success`. Здесь мы только нажимаем готовую кнопку; подробно `world_next_day`
разберём в лабе 07.
**Смотрим результат:**
```sql
SELECT kafka_ts, kafka_msg_ts
FROM stg.browser_raw
WHERE kafka_msg_ts > toDateTime(0)
ORDER BY kafka_offset
LIMIT 5;
```
@@ -224,19 +214,8 @@ LIMIT 5;
> теряется. Обратный случай — колонку добавил, а в MV не указал — тоже не упадёт: поле
> заполнится дефолтом. Вывод: за синхронность схемы и MV отвечаешь ты, а не движок.
**Верни как было** (откат — тоже две операции, и порядок важен):
```sql
DROP VIEW stg.mv_kafka_browser_to_stg; -- сначала MV, что ссылается на колонку
ALTER TABLE stg.browser_raw DROP COLUMN kafka_msg_ts;
```
```bash
make ddl # пересоздаёт эталонное MV из 10_stg.sql, схема снова как в репозитории
```
Если запутался в состоянии — всегда есть полный чистый прогон:
`make generated-history-analytics && make up`.
**Верни как было.** После дозаливки мир уже вырос, поэтому верни схему и данные
[каноническим сбросом](../README.md#подготовка-и-канонический-сброс).
---
@@ -244,10 +223,10 @@ make ddl # пересоздаёт эталонное MV из 10_stg.sql, с
| Действие | Где смотреть | Что ожидать |
|----------|--------------|-------------|
| `make generated-history-analytics && make up` | `SELECT count() FROM stg.browser_raw` | счётчик > 0 |
| каноническая подготовка | `SELECT count() FROM stg.browser_raw` | счётчик > 0 |
| глянуть строку | `SELECT raw FROM stg.browser_raw LIMIT 1` | валидный JSON целиком, неразобранный |
| глянуть offset'ы | `SELECT kafka_offset FROM stg.browser_raw ORDER BY kafka_offset` | идут по возрастанию, без дублей |
| правка из секции 4 | `SELECT kafka_msg_ts FROM stg.browser_raw LIMIT 5` | колонка заполнена временем сообщения |
| `world_next_day` после правки из секции 4 | `SELECT kafka_msg_ts FROM stg.browser_raw WHERE kafka_msg_ts > toDateTime(0) LIMIT 5` | новые строки заполнены временем сообщения |
---