refactor(all): унифицированы служебные поля STG — переход на канонический нейминг

- Зачем:
  - STG-слой использовал legacy-имена (batch_id, load_dttm, src_created_at_ts),
    тогда как ODS/DDS/DM уже работали с каноном (_load_id, _load_ts, event_ts).
    Студент видел разные имена для одного понятия — это убрано.
- Что:
  - переименованы колонки в 9 STG DDL: batch_id→_load_id, load_dttm→_load_ts,
    src_created_at_ts→event_ts; добавлен NOT NULL для _load_id во всех таблицах.
  - обновлены 9 STG Load, 9 STG DQ, 9 ODS Load, 9 ODS DQ (INSERT/SELECT/WHERE).
  - обновлены DAG-файлы bookings_to_gp_stage.py и bookings_to_gp_ods.py
    (встроенный SQL резолвера, комментарии; Python-идентификаторы не тронуты).
  - обновлены тесты и ~15 документов (naming_conventions, PRD, db_schema,
    design-docs, qa-plan, README, TESTING и др.).
- Проверка:
  - grep -rn 'load_dttm\|src_created_at_ts' sql/ airflow/ tests/ — 0 совпадений.
  - make test — 4 passed.
  - e2e-etl: day1 прошёл полностью, day2 стартовал без ошибок.
This commit is contained in:
2026-03-10 00:07:08 +03:00
parent 3de4db8aa6
commit 5972bcc2d8
64 changed files with 582 additions and 484 deletions
+8 -9
View File
@@ -45,7 +45,7 @@ LEFT JOIN dds.dim_routes AS rte
GP-специфичная best practice, которую забывают даже опытные команды.
### 9. Идемпотентные STG-загрузки
`NOT EXISTS (... WHERE batch_id = '{{ run_id }}')` — простой, корректный, понятный паттерн для retry-safe загрузок.
`NOT EXISTS (... WHERE _load_id = '{{ run_id }}')` — простой, корректный, понятный паттерн для retry-safe загрузок.
---
@@ -56,7 +56,7 @@ GP-специфичная best practice, которую забывают даж
- [x] **ODS batch resolver теряет данные при двух STG-запусках подряд**
- Сценарий: STG run_1 загружает день N, STG run_2 загружает день N+1, затем ODS запускается
- `_resolve_stg_batch_id()` выбирает только последний согласованный batch (`run_2`)
- Все ODS load-скрипты фильтруют `WHERE batch_id = 'run_2'` → данные `run_1` навсегда пропущены
- Все ODS load-скрипты фильтруют `WHERE _load_id = 'run_2'` → данные `run_1` навсегда пропущены
- **Справочники** (airports, airplanes, routes, seats): проблемы нет — full snapshot, `run_2` содержит всё
- **Транзакционные таблицы** (bookings, tickets, flights, segments, boarding_passes): **потеря данных** — инкрементальные записи `run_1` никогда не попадут в ODS
- Корень проблемы: batch resolver проектировался для согласованности справочников (INTERSECT), но тот же single-batch фильтр применяется к транзакционным таблицам, где нужны **все необработанные** batch-и
@@ -117,12 +117,11 @@ GP-специфичная best practice, которую забывают даж
- **Решение**: вынесено в CREATE TEMP TABLE tmp_routes_src ON COMMIT DROP ✅ ВЫПОЛНЕНО
- Файл: `sql/dds/dim_routes_load.sql`
- [ ] **Несогласованность нейминга STG vs ODS+**РЕШЕНИЕ ПРИНЯТО
- STG: `batch_id`, `load_dttm`, `src_created_at_ts` → переименовать в канон `_load_id`, `_load_ts`, `event_ts`
- [x] **Несогласованность нейминга STG vs ODS+**ВЫПОЛНЕНО
- STG: `batch_id`, `load_dttm`, `src_created_at_ts` → переименованы в канон `_load_id`, `_load_ts`, `event_ts`
- Единый словарь во всех слоях снижает когнитивную нагрузку
- Добавить заметку в `naming_conventions.md` (секция «legacy-нейминг в реальных проектах»)
- Удалить секцию 6 «Переходный маппинг» как неактуальную
- Файлы: ~27 STG SQL + ODS load-скрипты + `naming_conventions.md` + тесты
- Секция 6 «Переходный маппинг» удалена из `naming_conventions.md` как неактуальная
- Файлы: 27 STG SQL + ODS load-скрипты + `naming_conventions.md` + тесты
- [x] **Дублирование CTE в ODS load-скриптах**
- `WITH src AS (...)` копируется 2-3 раза в каждом из 9 ODS load-файлов
@@ -149,7 +148,7 @@ GP-специфичная best practice, которую забывают даж
- [ ] **Отсутствующие паттерны** (комментарии/заметки):
- Partitioning (когда и зачем, почему не здесь)
- SCD Type 3/6 (хотя бы упомянуть существование)
- Data lineage (`_load_id` в DM ≠ `batch_id` в STG — нет сквозного трассирования)
- Data lineage (сквозное трассирование `_load_id` через STG → ODS → DDS → DM)
---
@@ -296,7 +295,7 @@ DROP TABLE tmp_fact_20170102;
| ~~P1~~ | ~~Добавить 7 точечных комментариев~~ | ~~30-40 мин~~ | ~~done~~ |
| **P2** | Явный storage type + AO где нет UPDATE (ADR-3) | 2-3 часа | все `*_ddl.sql` в ods/dds/dm + 4 ODS snapshot load |
| **P2** | Рефакторинг hashdiff → TEMP TABLE | 1 час | `sql/dds/dim_routes_load.sql` |
| **P2** | Переименовать STG поля в канон + заметка | 1-2 часа | 27 STG SQL + ODS load + naming_conventions.md |
| ~~P2~~ | ~~Переименовать STG поля в канон + заметка~~ | ~~1-2 часа~~ | ~~done~~ |
| **P2** | TEMP TABLE для сложных ODS load-ов | 1 час | 3-4 ODS load файла |
| **P2** | Реализовать `dm.route_performance` | 2-3 часа | 3 SQL + DAG + тесты |
| **P3** | Маршрут изучения DDS + distribution strategy doc | 1 час | 2 новых md-файла |