# 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`; на текущих данных она дала бы те же группы (разброс времени внутри `click_id` ≤ 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`. ## Почему на демо `Unique Users == Unique Sessions` В демо-датасете (`data/*.jsonl`) каждый пользователь имеет **ровно один** `click_id` — связь user↔визит строго 1:1 (проверено: 99 пользователей = 99 `click_id` в полном файле). Поэтому `uniqExact(user_domain_id)` и `uniqExact(click_id)` дают одинаковое число. Это **свойство конкретного датасета, а не закон модели и не баг расчёта.** В реальных данных пользователь возвращается несколькими визитами, и числа расходятся. Поэтому на дашборде мы **не** показываем две одинаковые KPI-плитки (это читалось бы как ошибка) — вместо дубля идут производные метрики (события на визит, доля визитов с одним событием), а различие «пользователь vs сессия» объясняется текстом урока. Синтетический генератор (ветка `feature/data-generator`) проблему не решает, а усугубляет: он штампует свежий `click_id` на каждое событие, и `click_id` вырождается в «событие». См. `generator/KNOWN_ISSUES.md` на той ветке. ## Слои данных `STG → ODS → DDS → DM` — см. [`docs/ARCHITECTURE.md`](./docs/ARCHITECTURE.md). Витрины (`dm.*`) и дашборд Superset строятся на статическом сиде, не на потоке.