# CONTEXT.md — глоссарий домена Доменный язык стенда: как мы называем сущности кликстрима и что под ними понимаем. Один термин — одно имя. Ведётся вместе с `docs/adr/` (см. [ADR-0001](./docs/adr/0001-spec-adr-issue-layout.md)). ## Сущности ### Пользователь (user) `user_domain_id` (`UUID`) — постоянный идентификатор пользователя (cookie-уровень), переживает отдельные визиты. Источник — `device_events`, привязан к `click_id`. В витринах: `uniqExact(user_domain_id)`. ### Визит / сессия (visit / session) `click_id` (`UUID`) — **визит**: envelope из одного и более событий с общим контекстом device/geo. В DDL `dds.click` описана как «контекст сессии пользователя» (см. [`sql/ddl/dds/30_dds.sql`](./sql/ddl/dds/30_dds.sql)). Важно: в источнике **нет отдельного session-таймаута** (как Snowplow `domain_sessionid`). Поэтому в этой модели **сессия ≡ визит ≡ `click_id`** — группа событий под одним идентификатором, а не окно активности по тайм-ауту. Если в будущем понадобится «настоящая» сессия по 30-минутному окну неактивности — это отдельная производная над `user_domain_id` + `event_ts`, и на сиде она дала бы **другие** группы: в полном сиде 11 внутрисессионных пауз превышают 30 минут, а разброс времени внутри `click_id` доходит до 49 минут (см. профиль сид-датасета ниже; ранее здесь ошибочно значилось «разброс ≤ 1 мин» — это был замер по малому срезу файла). «Сессию» и «визит» используем как синонимы; в UI предпочитаем «визит», когда важно подчеркнуть, что это не сессия-по-тайм-ауту. ### Событие (event) `event_id` (`UUID`) — отдельное действие пользователя в рамках визита: `pageview`, `click`, `purchase`, `add_to_cart` и т.п. (поле `event_type`). Источник — `browser_events` + `location_events`. В витринах: `count()`. ## Иерархия ``` user_domain_id (пользователь, постоянный) └── click_id (визит/сессия — 1..N событий с общим device/geo) └── event_id (событие: pageview / click / purchase ...) ``` Здоровые данные дают пирамиду `users ≤ sessions ≤ events`. ## Термины потоковой генерации (steady-stream) Относятся к синтетическому потоку из генератора (режим `steady-stream`), не к статическому сиду. Решение и контекст — [ADR-0004](./docs/adr/0004-steady-stream-synthetic-generator.md), форма доработки — [спека генератора](./docs/specs/2026-06-09-generator-rework-hierarchical.md). ### Популяция пользователей (user population) Множество пользователей с **постоянными** `user_domain_id`, которые генератор держит во времени и из которых разыгрывает активность. В отличие от сида (где пул `user_domain_id` плоский и 1:1 с визитами), популяция — это источник возвратов: один и тот же пользователь порождает несколько визитов. ### Возвращающийся пользователь (returning user) Пользователь, открывающий **более одного** визита (`click_id`) во времени, с межсессионными паузами. Именно возвраты дают расхождение `users < sessions` — то, чего нет на сиде (`users == sessions`) и что отличает поток от статики. ### Три значения слова «сид» Слово перегружено — в разговоре про генератор это **три разные сущности**, их нельзя путать (см. [ADR-0005](./docs/adr/0005-generator-model-clock.md)): - **`GEN_SEED`** — зерно ГПСЧ генератора (детерминизм случайных решений). Не данные, а число. - **архивный статический сид** (короткое имя — «статический сид», файлы `data/*.jsonl`) — кладовка готовых значений для генератора: браузеры, страны, устройства, метки кампаний. По [ADR-0006](./docs/adr/0006-generation-as-sole-analytics-source.md) он **выведен из аналитики и стал архивным**: витрины, дашборды и курс идут через startup-history/backfill → Kafka → STG → ODS → DDS → DM → Superset. Цель — **совсем убрать файл**, когда генератор научится придумывать фактуру сам (отдельная спека). Профиль ниже — теперь опорные цифры и список известных расхождений, а не эталон для подгонки (подгонять генерацию под сид число-в-число в ADR-0006 отклонено). - **стартовая история стенда** (синонимы — **«стартовый сид»** и **«новый сид»**; это не новые значения слова, а та же сущность) — сгенерированное прошлое (заливка `K → ∞` + заморозка состояния), с которого живой стенд стартует непрерывно. По ADR-0006 она **несущая**: именно с неё свежий стенд получает историю с первой минуты. Механизм реализован через Airflow DAG `generator_control` и служебный чистый путь `make generated-history-analytics`; решение про часы — [ADR-0005](./docs/adr/0005-generator-model-clock.md). ### Модельное время и масштаб (×K) **Модельное время стенда** отвязано от настенных часов: генератор крутит внутренние часы, а драйвер задаёт скорость — ×1 (как реальное время), ×K (ускоренно, учебная «ручка» урока 7) или `K → ∞` (мгновенная заливка прошлого). При ускорении «сейчас» стенда уходит вперёд настенного времени — это свойство, не баг (ключ аналитики — `event_timestamp`). Решение и режимы — [ADR-0005](./docs/adr/0005-generator-model-clock.md). ## Почему на статическом сиде `Unique Users == Unique Sessions` В архивном статическом сиде (`data/*.jsonl`) каждый пользователь имеет **ровно один** `click_id` — связь user↔визит строго 1:1 (проверено: 99 пользователей = 99 `click_id` в полном файле). Поэтому `uniqExact(user_domain_id)` и `uniqExact(click_id)` дают одинаковое число. Это **свойство конкретного датасета, а не закон модели и не баг расчёта.** В реальных данных пользователь возвращается несколькими визитами, и числа расходятся. Поэтому на дашборде мы **не** показываем две одинаковые KPI-плитки (это читалось бы как ошибка) — вместо дубля идут производные метрики (события на визит, доля визитов с одним событием), а различие «пользователь vs сессия» объясняется текстом урока. В аналитическом контуре это больше не опорный сценарий: генератор ведёт популяцию пользователей и возвращения во времени. ## Профиль сид-датасета (измерено 2026-06-10, полные файлы) Опорные цифры о статическом сиде (`data/*.jsonl`) — для калибровки генератора и проверки гипотез. Измерено по **полным** файлам (1000 событий); внимание: ранние оценки «1..7 событий на визит» делались по малому срезу и неверны. - **Объём:** 1000 событий, 99 визитов (`click_id`), 99 пользователей (1:1). - **Длина визита:** 1..27 событий, медиана 10, среднее 10.1. - **Паузы между событиями визита:** медиана ~20 с, p95 ≈ 17 мин, максимум ≈ 40 мин; пауз длиннее 30 минут — 11 штук. Разброс времени внутри одного `click_id` — до 49 минут. - **Воронка:** 25% визитов достигают `/confirmation`. Пути — с петлями: возвраты на `/home`, просмотр обоих товаров; у 21 из 25 «купивших» визитов есть события **после** `/confirmation`, у 9 — `/confirmation` встречается дважды. То есть `/confirmation` — последний *шаг воронки*, но не обязательно последнее *событие визита*. - **Страницы (по событиям):** `/home` 426, `/product_a` 236, `/product_b` 157, `/cart` 93, `/payment` 53, `/confirmation` 35. `event_type` — 100% `pageview`. ## Слои данных `STG → ODS → DDS → DM` — см. [`docs/ARCHITECTURE.md`](./docs/ARCHITECTURE.md). Сейчас витрины (`dm.*`) и дашборд Superset строятся на статическом сиде. По [ADR-0006](./docs/adr/0006-generation-as-sole-analytics-source.md) целевой источник аналитики — генерация (стартовая история и живой поток); перевод загрузки, витрин и дашбордов на неё входит в текущую работу, детальный план — отдельной спекой.