Files
portal/docs/superpowers/specs/2026-06-28-dashboard-drilldown-scale-design.md
T
Дмитрий 6d313b0fbd feat(дашборд): выбор периода — свой диапазон дат + спека вложенности/масштаба
Фундамент под сквозную вложенность: periodRange() читает date_from/date_to
(приоритет) либо preset; Финансы и Клиенты считаются по выбранному периоду через
whereBetween. FE: «Свой период» + два date-поля + «Применить» → date_from/date_to.
Спека дизайна A+B+C+масштаб сохранена. Baseline перегенерирован (getJson тестов).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 09:54:09 +03:00

10 KiB
Raw Blame History

Дашборд: сквозная вложенность до источника + масштаб + выбор периода

Дата: 2026-06-28 Автор: Claude (по запросу владельца) Статус: одобрено владельцем (брейншторм 28.06)

Цель

С дашборда «Командный центр» по логике вложенности доходить до конечного источника (лид → откуда пришёл и кому ушёл), все списки должны оставаться читаемыми при больших объёмах (1000 клиентов, десятки тысяч лидов), а период анализа — выбираемым (пресеты + свой диапазон дат).

Решения владельца

  1. Полная цепочка лида: Дашборд → Лиды → список (фильтры) → конкретный лид → откуда (поставщик-проект B1/B2/B3 + канал сайт/звонок/sms + регион) → кому (клиент + сделка + статус).
  2. Масштаб: топ-N на дашборде + «Открыть всё →» в полноэкранный список с серверными поиском/фильтрами/страницами. Дашборд остаётся лёгким.
  3. Период: пресеты (Сегодня / 7 / 30 / 60 / 90 дней) + свой период (дата с — дата по). Все плитки, drill'ы и списки считаются по выбранному периоду.

Принцип вложенности (3 уровня)

L1 плитка (сводка, светофор)
  → L2 drill (топ-N + смысл + «Открыть всё →»)
      → L3 полноэкранный список (поиск + фильтры + страницы)
          → L4 карточка / конечный источник

Дашборд НЕ становится браузером данных: тяжёлые списки живут на полноэкранных экранах, которые держат объём (серверная пагинация). Карточки клиента/проекта переиспользуем существующие.

Кросс-режущее: период

  • Query-параметры всех эндпоинтов: period=today|7d|30d|60d|90d ИЛИ date_from=YYYY-MM-DD&date_to=YYYY-MM-DD (свой диапазон; приоритет над preset).
  • periodStart() в контроллере дополняется разбором date_from/date_to → возвращает [from, to]. Все запросы фильтруют >= from AND < to+1day.
  • Фронт: тумблер пресетов + кнопка «Свой период» открывает два date-picker'а (Vuetify v-date-input/диалог); выбор шлёт date_from/date_to. Подпись периода показывается в шапке.

Кросс-режущее: серверная пагинация (масштаб)

  • Полноэкранные списки отдают { data: [...], total, page, per_page } (Laravel paginator). Параметры: ?page, ?per_page (дефолт 25, max 100), ?search, плюс специфичные фильтры.
  • Индексы под фильтры — только аддитивные миграции (CREATE INDEX), без блокировок (CONCURRENTLY на проде, в окне). Сверять с db/CHANGELOG_schema.md.
  • На дашборде (L2) — только топ-N (10–20), без пагинации; «Открыть всё» уводит в L3.

Этап A — Лиды (полная цепочка) главное

L2 (drill Лиды): топ-10 последних лидов: время · источник (канал+identifier) · поставщик (B1/B2/B3) · клиент-получатель · статус. Кнопка «Открыть все лиды →».

L3 — новый экран «Лиды» (/admin/leads, nav-пункт):

  • Серверная таблица: время · источник (signal_type+identifier) · поставщик (platform) · регион · клиент(ы) · статус (доставлен/завис/ошибка).
  • Фильтры: диапазон дат, канал (signal_type: site/call/sms), поставщик (B1/B2/B3/direct), клиент (tenant), статус; поиск по identifier/телефону(маска)/id.
  • Пагинация серверная.

L4 — карточка лида (/admin/leads/{id}):

  • Откуда: поставщик-платформа + signal (канал+identifier) + регион (resolved_subject_code)
    • ссылка на проект у поставщика.
  • Что пришло: received_at, ключевые поля raw_payload (ПДн — маскируются по 152-ФЗ: телефон +7 9** *** ** 21, имя — инициалы).
  • Кому ушло: deals_created_count → список сделок (клиент + статус сделки + ссылка на карточку тенанта / сделку).
  • Обработка: processed_at, error (если был).

Данные: supplier_leads (platform, signal_type, signal_identifier?, raw_payload, received_at, processed_at, error, deals_created_count, resolved_subject_code, region_source)

  • deals (tenant_id, status, project_id, received_at) связь по лиду. Точную связь lead↔deal уточнить по схеме при реализации (deal.source_lead_id / по телефону+времени).

Безопасность: ПДн маскируются в списке и карточке (152-ФЗ); полный показ — только если уже так делается в клиентской карточке сделки. Не логировать ПДн.

Этап B — Заказ у поставщика (кликабельные группы)

  • Строки таблицы групп → кликабельны → детали группы: какие клиентские проекты входят (спрос по каждому) + проект(ы) у поставщика (факт) + «Открыть в Проектах у поставщика →» (/admin/supplier-projects с фильтром по группе).
  • «Открыть всё →» из drill → /admin/supplier-projects.
  • Конечный источник заказа = запись проекта у поставщика (существующий экран) + клиентские проекты группы.

Этап C — Здоровье + «Открыть всё» на Финансы/Клиенты

  • Здоровье: подсистемы кликабельны → Инциденты (/admin/incidents), очереди/джобы → экран системы/упавших джоб, синхрон/CSV → /admin/supplier-integration, вебхуки → соответствующий экран. (Куда именно — по наличию экранов.)
  • Финансы: «Требуют внимания»/«Топ» → уже карточка тенанта; добавить «Открыть всё →» → /admin/tenants (фильтр «в минусе») и /admin/billing.
  • Клиенты: новые/спящие → карточка тенанта; «Открыть всё →» → /admin/tenants (фильтры новые / спящие). Проверить, что /admin/tenants уже серверно-пагинирован и ищет; если нет — добавить (масштаб 1000 клиентов).

Масштаб — что проверить отдельно (1000 клиентов / 10⁴ лидов)

  • /admin/tenants (куда ведут Финансы/Клиенты): серверный поиск + пагинация + фильтры (новые/спящие/в минусе). Если сейчас клиентский список тянет всё — переделать на сервер.
  • Дашбордовые агрегаты (counts) — по индексам; тяжёлые DISTINCT/JOIN проверить на плане.
  • Лиды L3 — обязательно серверная пагинация + индексы по received_at (партиции уже есть), signal_type, platform.

Порядок работ

Владелец: «сразу всё» (A+B+C) + масштаб + выбор периода. Реализация по этапам с выкатом каждого (чтобы ценность приходила частями и риск был мал):

  1. Кросс: выбор периода (свой диапазон) + контракт серверной пагинации.
  2. Этап A: экран «Лиды» + карточка лида + связка из дашборда (главное).
  3. Этап B: Заказ кликабельный + «Открыть всё».
  4. Этап C: Здоровье-ссылки + «Открыть всё» на Финансы/Клиенты + аудит масштаба /admin/tenants.

Каждый этап: TDD (Pest + Vitest), показ глазами, выкат по «выкатывай» + prod-deploy-validator.

Известные ограничения / уточнить при реализации

  • Точная связь lead↔deal (по какому полю) — уточнить по db/schema.sql (Этап A Step 1).
  • Маскирование ПДн в админ-карточке лида — согласовать уровень (полный/маска).
  • Экраны-приёмники для подсистем «Здоровья» (упавшие джобы/вебхуки) — есть не все; вести в ближайший существующий, недостающее — отдельный follow-up.
  • «Свой период» для очень больших диапазонов на партиционированных таблицах — следить за планом запроса (партиции по received_at помогают).