- Зачем: - нужно убрать дублирующий KPI Unique Sessions и сделать эталонный dashboard честнее для учебного анализа. - Что: - обновлены KPI, добавлена Conversion to /confirmation и Page Funnel. - добавлена идемпотентная миграция старых chart names без дублей. - синхронизированы документация, урок 6 и спека редизайна. - добавлен handoff для продолжения работы в новой сессии. - Проверка: - python3 -m py_compile superset/create_dashboard.py. - make superset-dashboard. - Superset metadata: dashboard_charts=10, obsolete_unique_sessions=0, page_funnel_type=funnel.
10 KiB
Редизайн KPI-полосы и состава чартов дашборда «E-commerce Analytics»
Дата: 2026-06-06
Статус: Implemented (superset/create_dashboard.py, docs/SUPERSET_DASHBOARD.md,
docs/course/lessons/06_superset_bi.md)
Связано: 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 становится наглядным.
Recommended approach
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
- Resolved: точная формула Conversion. Используем page-funnel conversion:
countIf(page_url_path = '/confirmation') / countIf(page_url_path = '/home'). На полном датасете это35 / 426 = 8.2%. Визитовая формула даёт 25.3% и отклонена, потому что KPI должен совпадать с логикой chartPage Funnel. - Resolved: Events by Hour. Оставляем: на полном датасете есть два часовых
бакета (
20 → 256,21 → 744), график не пустой. - Resolved: Funnel в Superset 4.1.2. MCP Context7 по
/apache/supersetне дал точной строкиviz_type; установленный Superset 4.1.2 проверен по bundled exampleFeatured Charts/Funnel.yamlи frontend assets. Используемviz_type: funnel. - Требования к будущему генератору, вытекающие из упёртостей этих данных
(разнообразие
event_type, возвраты пользователей → sessions>users, реалистичная воронка) — при возврате к генератору перенести в егоKNOWN_ISSUES.md.