Files
clickstream-ch-kafka-supers…/docs/specs/2026-06-06-superset-dashboard-redesign.md
T
ddadmin 7c7e9e5a7c docs(superset): спека редизайна дашборда и handoff
- Зачем:
  - дашборд-эталон показывал две одинаковые KPI-плитки; нужен честный состав метрик
    на полных данных, зафиксированный до реализации.
- Что:
  - docs/specs/2026-06-06-...: KPI Events/Users/Avg per Visit/Conversion, Top Pages → Funnel, триаж чартов.
  - .scratch/handoffs/2026-06-06-...: handoff для реализации в новой сессии.
- Проверка:
  - числа спеки сверены с прямым запросом в ClickHouse на полном датасете.
2026-06-06 16:12:10 +03:00

10 KiB
Raw Blame History

Редизайн KPI-полосы и состава чартов дашборда «E-commerce Analytics»

Дата: 2026-06-06 Статус: Accepted (не реализовано — код superset/create_dashboard.py правится отдельным заходом на реализацию) Связано: CONTEXT.md, ADR-0002, урок docs/course/lessons/06_superset_bi.md

Problem

Дашборд-эталон показывает две KPI-плитки — Unique Users и Unique Sessions — с одинаковым числом (26 на срезе, 99 на полных данных), потому что в датасете user_domain_id ↔ click_id строго 1:1. Две одинаковые цифры читаются как баг расчёта и ничему не учат менти, который копирует дашборд как образец. Нужен честный, копируемый состав KPI и чартов на полных данных.

Context

  • Дашборд — учебный эталон для менти. Требований обратной совместимости нет: состав можно менять свободно, критерий — учебная ценность.
  • Доменные термины зафиксированы в CONTEXT.md: пользователь = user_domain_id, визит/сессия = click_id, событие = event_id.
  • Источник данных — статический сид data/*.jsonl. Синтетический генератор (ветка feature/data-generator) источником не является и семантику ломает (см. generator/KNOWN_ISSUES.md на той ветке).

Goals

  • KPI-полоса из 4 различающихся честных метрик (без дубля одинаковых чисел).
  • Превратить слабые места данных в учебные объекты, а не маскировать их.
  • Консистентность с CONTEXT.md и уроком 6.

Non-goals

  • Не модернизируем типы виджетов (pie/world_map/dist_bar → ECharts) — отдельный косметический заход.
  • Не трогаем эмодзи в тайтлах, секции-заголовки, языковой винегрет.
  • Не трогаем генератор.
  • Не правим код create_dashboard.py в рамках этой спеки — это реализация.

Current state

Полный датасет (make data без LIMIT):

события: 1000 | визиты (click_id): 99 | пользователи (user_domain_id): 99 (1:1)
avg событий на визит: 10.10 | bounce (визиты с 1 событием): 4/99 = 4.0%
event_type: 100% pageview (других типов НЕТ)
page_url_path — воронка: /home 426 → /product_a 236 + /product_b 157 →
                          /cart 93 → /payment 53 → /confirmation 35 (~8% в конец)
geo_country: 40 | device_type: 2 (Mobile/Computer) | utm_source: 5 | utm_medium: 4

Текущие чарты и триаж по учебной ценности:

Чарт Тип Вердикт
Total Events, Unique Users big_number_total оставить (KPI)
Unique Sessions big_number_total убрать (дубль Users)
Avg Events/Session big_number_total оставить, переименовать /Visit
Top Pages dist_bar апгрейд в Funnel (центральный учебный объект)
UTM Effectiveness table оставить; выкинуть колонки purchases/add_to_cart (всегда 0)
Geography Map world_map оставить (40 стран; тип модернизировать отдельно)
Traffic by Device pie оставить
Events by Hour line проверить на пустоту, иначе дропнуть
Data Quality Summary dist_bar оставить

Options considered

  • A — честная воронка вовлечённости (стандартный KPI-strip). 4 плитки объём→охват→глубина→качество; различие user/session уходит в текст.
  • B — оставить обе плитки + Markdown-панель, объясняющая равенство 1:1.
  • C — strip как форма модели: воронка Events → Visits → Users вместо бизнес-KPI; вырожденное 1:1 становится наглядным.

A для KPI-полосы + идея C отдельным чартом-воронкой. KPI-полоса — стандартная и чистая (копируемый паттерн); иерархия модели подаётся отдельным чартом, а Top Pages превращается в Funnel по страницам.

KPI-полоса:

📊 Total Events 1000 · 👤 Unique Users 99 · 📈 Avg Events/Visit 10.1 · 🎯 Conversion to /confirmation ~8%

Rationale

  • Конверсия через page_url_path честнее блёклого bounce (4%) и превращает «всё pageview» из слабости в сильный урок: воронка реально затухает.
  • Различие user/session учим текстом (CONTEXT.md + урок 6), а не двумя одинаковыми числами — это убирает сигнал «баг».
  • Стандартный KPI-strip ценнее для копирования, чем нестандартный вариант C; но идею C сохраняем как отдельный наглядный чарт.

Decisions and rejected alternatives

  • Данные: полный датасет и для дашборда, и для урока 6. Срез LIMIT=50 отклонён: числа эталона разойдутся с тем, что менти получит у себя. Урок 6 — убрать LIMIT=50 make data. (Срез LIMIT оставить в доке как явный приём отладки, не как основной прогон. Замечание: ограничение head -n исходно возникло, чтобы агентский контекст не давился полным jsonl — это ограничение для агента, не для пайплайна.)
  • Убрать Unique Sessions из KPI — дубль Unique Users при 1:1.
  • 4-я KPI = Conversion, не bounce. Bounce 4% отклонён как блёклый.
  • Top Pages → Funnel. Воронка по страницам — главный учебный объект.
  • UTM-таблица: убрать колонки purchases/add_to_cart — всегда 0, т.к. event_type только pageview.
  • Гео/device/DQ не удаляем — данные оправдывают ценность; модернизация их типов виджетов — отдельно (non-goal здесь).
  • «Снести всё legacy» на практике = убрать дубль-KPI + мёртвые колонки + проверить Events by Hour. Инсайты не вырезаем — у большинства есть данные.

Risks and mitigations

  • Funnel в Superset 4.1.2 — проверить доступность viz_type воронки до реализации; при отсутствии — упорядоченный bar.
  • Формула Conversion — определить точно и валидировать SQL (см. Open questions).
  • Идемпотентность create_dashboard.py при смене состава (чарты по slice_name, дашборд по slug) — переименование Unique Sessions/Top Pages не должно плодить дубли; проверить апдейт на месте.

Validation

  • KPI-полоса: 4 разных числа, дубля нет.
  • GET /api/v1/dashboard/<id>/datasets → 200; DQ Summary без Columns missing in datasource.
  • Визуальная проверка через playwright-cli (скриншот в /tmp).
  • Числа на дашборде сходятся с прямым запросом в ClickHouse.

Documentation impact

  • docs/SUPERSET_DASHBOARD.md — обновить раздел «Структура дашборда» (состав чартов/KPI/фильтров) в момент реализации, чтобы пользовательская дока не описывала несуществующие чарты.
  • docs/course/lessons/06_superset_bi.md — убрать LIMIT=50, синхронизировать состав чартов и скриншоты.
  • CONTEXT.md — уже отражает user/visit/event; правок не требует.

Open questions

  • Точная формула Conversion: доля визитов с ≥1 pageview /confirmation, или просмотры /confirmation / просмотры /home? Влияет на число (~8%) и на то, что именно учим (визит-конверсия vs page-to-page).
  • Events by Hour — оставляем ли (зависит от проверки на пустоту на полных данных: разброс event_ts по часам).
  • Требования к будущему генератору, вытекающие из упёртостей этих данных (разнообразие event_type, возвраты пользователей → sessions>users, реалистичная воронка) — при возврате к генератору перенести в его KNOWN_ISSUES.md.