Files
airflow-greenplum/docs/archive/2026-03-10_stg-naming-unification.md
T
ddadmin 8932148c44 chore(docs): введена конвенция нейминга планов, переименованы архивные файлы
- Зачем:
  - файлы планов именовались хаотично (микс snake_case/kebab-case, без дат),
    из-за чего архив не сортировался хронологически.
- Что:
  - установлен формат YYYY-MM-DD_краткое-описание.md для docs/plans/ и docs/archive/.
  - переименованы 6 архивных файлов по новой конвенции (git mv).
  - конвенция зафиксирована в AGENTS.md (секция «Карта проекта»).
- Проверка:
  - ls docs/archive/ — все файлы начинаются с даты в kebab-case.
2026-03-11 19:34:45 +03:00

7.6 KiB
Raw Blame History

Унификация нейминга служебных полей в STG

Контекст

В STG-слое используются legacy-имена служебных полей (batch_id, load_dttm, src_created_at_ts), а начиная с ODS — каноничные (_load_id, _load_ts, event_ts). Студент видит разные имена для одного понятия. Цель — привести STG к канону, убрав расхождение.

Breaking change (dev-only). Это ломающее переименование колонок. Миграционный шаг (ALTER TABLE … RENAME COLUMN) не предусмотрен. DDL-файлы используют CREATE TABLE IF NOT EXISTS, поэтому сами по себе они не пересоздадут существующие таблицы с новыми именами колонок. План предполагает заранее пересозданную среду (например, make down && make up) или ручной DROP TABLE / DROP SCHEMA перед make ddl-gp. Обратная совместимость не обеспечивается.

Маппинг

Legacy (STG сейчас) Канон (ODS/DDS/DM)
batch_id _load_id
load_dttm _load_ts
src_created_at_ts event_ts

Оговорка про event_ts в snapshot-справочниках

В транзакционных STG-таблицах (bookings, tickets, flights, segments, boarding_passes) поле src_created_at_ts действительно хранит время события из источника — переименование в event_ts семантически точно.

В snapshot-справочниках (airports, airplanes, routes, seats) это поле заполняется now() при загрузке, т.е. по факту это ещё одно load-time, а не время события. Тем не менее мы сохраняем единое имя event_ts как учебное упрощение — ради консистентной структуры STG-таблиц. Это зафиксировано как осознанный trade-off: единообразие важнее семантической точности в справочниках. В naming_conventions.md нужно добавить соответствующую оговорку (раздел 4, «Time Rule»).

Что НЕ переименовываем

  • PL/pgSQL переменная v_batch_id — это локальная переменная, не колонка
  • Python-функция _resolve_stg_batch_id, переменная stg_batch_id, task_id resolve_stg_batch_id — это Python/Airflow-идентификаторы
  • XCom-ключи, ссылающиеся на task_id

Порядок выполнения

Шаг 1: STG DDL (9 файлов)

sql/stg/{bookings,tickets,flights,segments,airports,airplanes,routes,seats,boarding_passes}_ddl.sql

В каждом: batch_id_load_id, load_dttm_load_ts, src_created_at_tsevent_ts.

Шаг 2: STG Load (9 файлов)

sql/stg/{bookings,tickets,flights,segments,airports,airplanes,routes,seats,boarding_passes}_load.sql

INSERT-списки, SELECT, WHERE, комментарии — те же 3 замены.

Шаг 3: STG DQ (9 файлов)

sql/stg/{bookings,tickets,flights,segments,airports,airplanes,routes,seats,boarding_passes}_dq.sql

WHERE-условия (batch_id = v_batch_id_load_id = v_batch_id), RAISE-сообщения, комментарии.

Шаг 4: ODS Load (9 файлов)

Два подтипа — обрабатывать по-разному.

4a: Транзакционные таблицы (5 файлов)

sql/ods/{bookings,tickets,flights,segments,boarding_passes}_load.sql

SELECT из STG: s.batch_ids._load_id, s.load_dttms._load_ts, s.src_created_at_tss.event_ts. Убрать лишние алиасы (s.src_created_at_ts AS event_ts → просто s.event_ts).

4b: Snapshot-справочники (4 файла)

sql/ods/{airports,airplanes,routes,seats}_load.sql

Здесь event_ts отсутствует в целевой ODS-таблице — менять только ссылки на STG-колонки: s.batch_ids._load_id, s.load_dttms._load_ts, s.src_created_at_tss.event_ts (только в ORDER BY / WHERE, где они читают из STG). ODS-колонка _load_ts по-прежнему заполняется через now(), это не меняется.

Шаг 5: ODS DQ (9 файлов)

sql/ods/{bookings,tickets,flights,segments,airports,airplanes,routes,seats,boarding_passes}_dq.sql

WHERE batch_id =WHERE _load_id =, RAISE-сообщения.

Шаг 6: DAG-файлы (2 файла)

  • airflow/dags/bookings_to_gp_stage.py — комментарий про batch_id
  • airflow/dags/bookings_to_gp_ods.py — встроенный SQL-запрос резолвера: все batch_id как колонка → _load_id, load_dttm_load_ts. Python-имена не трогаем.

Шаг 7: Тесты (3 файла)

  • tests/test_ods_snapshot_integration.py — inline DDL и INSERT в тестах
  • tests/test_dags_smoke.py — комментарии
  • tests/test_ods_sql_contract.py — docstring

Шаг 8: Документация (~15 файлов)

  • docs/internal/naming_conventions.md — убрать legacy-исключение (секция 5/STG), убрать переходный маппинг (секция 6), добавить оговорку про event_ts в snapshot-справочниках (секция 4)
  • docs/internal/db_schema.md — описания STG-полей
  • docs/internal/bookings_stg_design.md — дизайн STG
  • docs/internal/bookings_ods_design.md — маппинг STG→ODS, SQL-примеры
  • docs/internal/qa-plan.md — SQL-запросы проверок
  • docs/internal/architecture_review.md — архитектурные заметки
  • docs/internal/bookings_stg_code_review.md — код-ревью
  • docs/bookings_to_gp_stage.md — описание STG DAG, примеры полей
  • docs/bookings_to_gp_ods.md — описание ODS DAG
  • docs/dag_execution_order.md — порядок выполнения DAG
  • educational-tasks.md — учебные задания
  • README.md — SQL-примеры в README
  • TESTING.md — чек-лист тестирования

Шаг 9: Верификация

# 1. Проверить SQL и Python — не должно быть колонок batch_id
#    (допустимы только: v_batch_id, stg_batch_id, resolve_stg_batch_id)
grep -rn 'batch_id' sql/stg/ sql/ods/ airflow/dags/ tests/ --include='*.sql' --include='*.py'

# 2. Ноль совпадений по старым именам в коде
grep -rn 'load_dttm' sql/ airflow/dags/ tests/ --include='*.sql' --include='*.py'
grep -rn 'src_created_at_ts' sql/ airflow/dags/ tests/ --include='*.sql' --include='*.py'

# 3. Проверить документацию — не должно быть старых имён как актуальных
#    (допустимы упоминания в историческом контексте)
grep -rn 'batch_id\|load_dttm\|src_created_at_ts' docs/ educational-tasks.md README.md TESTING.md

# 4. Тесты и линтер
make test
make fmt && make lint

Итого: ~55 файлов, ~3 механические замены в каждом