UC-STA-004. Воронка конверсии «просмотр → сделка»
Назначение
Застройщик смотрит воронку конверсии своей недвижимости за период —
views → favorites → selections → leads → bookings → deals (с промежуточными
bookingsPaid/dealsCompleted) и коэффициенты перехода между этапами. Сценарий только читает данные; лиды и
клиенты в воронке обезличены — раскрываются только счётчики. Контракт операции —
get-conversion-funnel.md; модель фильтра —
dev-stats-filter.md; источник — суточный агрегат воронки
funnel_daily (каждый этап считается устойчиво к дублям по бизнес-ключу).
Контекст — dev-stats (ADR-0057).
Metadata
| Поле | Значение |
|---|---|
| ID | UC-STA-004 |
| Контекст | dev-stats (см. docs/06-services/dev-stats/) |
| Тип | основной |
| Статус | draft |
Актор
| Роль | Permissions / scope | Tenant | Record-level |
|---|---|---|---|
Девелопер (застройщик) | dev-stats.view; scope строго = свой DeveloperId | TenantId = DeveloperId = CompanyEntity.Id (ADR-0052) | не применяется — воронка агрегатна (персональные данные лидов/клиентов не раскрываются) |
DeveloperId = актор — головной компонент ключа funnel_daily и обязательный фильтр (fail-closed).
Предусловие
- Feature flag
dev-stats.funnel.enabled = true(иначе — A3, деградация до доступных этапов). - Агрегат funnel_daily наполняется: этап
views— из фактов просмотров; нижние этапы — из событий контекстовfavorites/selections(future)/crmс обогащением иерархии из измеренияdim_property_object. - Токен застройщика содержит право
dev-stats.view.
Триггер
| Поле | Значение |
|---|---|
| Источник | UI (вкладка «Воронка» дашборда) → API call |
| Триггерящий элемент | дашборд /developer/stats (таб воронки) → GET /api/v1/dev-stats/funnel |
Основной Поток
Полный контракт операции — get-conversion-funnel.md; ниже — сценарий воронки.
- Ввод. Застройщик задаёт период (
DateFrom/DateTo) и опционально срез иерархии (ProjectId/BuildingId/LayoutGroupId/LayoutId/PropertyObjectId). Разбивки по типу зрителя в воронке нет (она про конверсию объектов/иерархии — см. funnel_daily). - Запрос. Воронка за период и (опционально) срез иерархии;
DeveloperId— из токена. - Проверка входа и доступа.
DateFrom/DateToобязательны иDateFrom ≤ DateTo(≤ срок хранения); уровни-фильтры — валидные идентификаторы;DeveloperId = актор(fail-closed); проверяется флагdev-stats.funnel.enabled. Нарушение —VALIDATION_ERROR; чужойDeveloperId/нет права —FORBIDDEN; флаг выключен — деградацияFUNNEL_DISABLED(A3). - Чтение этапов. Данные читаются из
funnel_dailyв срезеDeveloperId = актор [∧ уровни] ∧ EventDate ∈ [DateFrom; DateTo]— только выбранная ветка иерархии и только затронутые месячные партиции по дате. Воронка «по проекту за период» = срез(DeveloperId, ProjectId); детализация — сужение среза до дочернего уровня. - Расчёт счётчиков и конверсий (устойчивый к дублям). На срез — счётчик по каждому этапу:
Views,Favorites,Selections,Leads,Bookings,BookingsPaid,Deals,DealsCompleted(каждый считается по своему бизнес-ключу —PropertyObjectViewId/FavoriteId/LeadId/BookingId/DealId— что даёт идемпотентность к at-least-once). Конверсии — производные при чтении:favorites/views,leads/favorites,bookings/leads,deals/bookings, сквознаяdeals/views(stage / prevStageс защитой от нуля:prev = 0→null). - Результат. Возвращается типизированный
FunnelModel: списокFunnelStage(StageName,Count,ConversionFromPrevPercent,ConversionFromTopPercent) в каноническом порядке этапов. Интерфейс рисует воронку с абсолютами и%перехода; недоступные этапы (источник не готов) помечены «нет данных» (A2); флаг выключен → толькоviews/готовые этапы (A3).
Диаграмма
Интеграция и согласованность этапов
Сценарий read-only читает единую витрину funnel_daily без синхронных вызовов соседей, но её этапы
наполняются разными источниками с независимой свежестью:
- Этап
views— из фактов просмотров (user-activity); нижние этапы (favorites/selections/leads/bookings/deals) — из событийfavorites/selections/crm, обогащённых иерархией изdim_property_object(событие несётPropertyObjectId, но не иерархию). Контракты входов — events/README.md. - Порядок доставки этапов не важен: каждый источник вставляет частичную строку только со своим этапом,
состояния сливаются по ключу
(иерархия, EventDate). Верхние этапы считаются независимо от нижних — отставаниеcrmне блокируетviews/favorites. - Каждый этап идемпотентен по своему бизнес-ключу — повтор события (at-least-once) не растит счётчик. Окно eventual-consistency ≤ 5 мин; отстающий нижний этап отдаётся частичным счётчиком, конверсия к нему помечается «предварительно».
Альтернативные Потоки
A1. Пустой период / срез
- На срезе нет ни одного этапа за период.
- Возвращается воронка из нулей (все
Count = 0, конверсииnull) — HTTP200.
Завершается: фронт показывает пустую воронку.
A2. Нижний этап отстаёт (источник лагает)
- Верхние этапы (
views/favorites) наполнены, нижний (leads/bookings/deals) отстаёт — контекстcrmдогоняет свою очередь событий. - Отстающий этап отдаётся текущим (частичным) счётчиком; конверсия к нему помечается «предварительно». Верхние этапы считаются независимо от нижних (частичные состояния сливаются по ключу).
Возвращается к основному потоку на шаг 6 (результат с пометкой freshness).
A3. Воронка отключена флагом (dev-stats.funnel.enabled = false)
- Источники нижних этапов (
selections/crm) ещё не готовы к проду. - API отдаёт только этап
viewsи уже подключённые этапы; выключенные этапы — с признакомEnabled = false; UI скрывает их либо показывает «скоро». Код деградации —FUNNEL_DISABLED.
Постусловие
- Мутаций нет (read-only): агрегаты/факты/измерения не изменяются, доменные и интеграционные (Kafka) события
не публикуются;
dev-stats— листовая аналитика (собственных событий не порождает), а этапы воронки потребляет из контекстовfavorites/selections/crm(см. funnel-daily-rollup.md). - Клиент получил воронку этапов + конверсии в scope своего
DeveloperId; персональные данные лидов/клиентов не раскрыты (только счётчики).
Возможные Ошибки
| Код | HTTP | Условие | Поведение клиента |
|---|---|---|---|
VALIDATION_ERROR | 400 | Нет дат / DateFrom > DateTo; невалидный уровень-идентификатор | Показать ошибку параметров |
FORBIDDEN | 403 | DeveloperId ≠ актор; нет dev-stats.view | Скрыть данные |
FUNNEL_DISABLED | 200/409 | Флаг dev-stats.funnel.enabled = false (A3) — деградация до доступных этапов | Показать частичную воронку/«скоро» |
| — (не ошибка) | 200 | Пустой период (A1) или отстающий этап (A2) | Пустая/частичная воронка |
5xx (ProblemDetails) | 500/503 | Отказ аналитической витрины pin_dev_stats | Ретрай позже |
Acceptance Criteria
| # | Критерий | Проверка |
|---|---|---|
| AC1 | Воронка «по проекту за период» сканирует только срез (DeveloperId, ProjectId) + затронутые партиции | Тест плана запроса |
| AC2 | Каждый этап считается по бизнес-ключу; повтор события не растит счётчик (идемпотентность) | Тест: дубль lead-created/favorite-added не меняет этап |
| AC3 | Конверсии = stage/prev с защитой от нуля; prev=0 → null (без деления на ноль) | Тест: срез с нулевым верхним этапом |
| AC4 | Отстающий нижний этап не блокирует верхние (частичные состояния сливаются по ключу) | Тест A2: views есть при пустых deals |
| AC5 | Флаг dev-stats.funnel.enabled=false → частичная воронка с Enabled=false этапами | Тест A3 |
| AC6 | Подсчёт устойчив к дублям; DeveloperId=актор (чужой → 403) | Тест изоляции + устойчивости к дублям |
| AC7 | Ответ типизирован (FunnelModel/FunnelStage); персональные данные не раскрыты | Ревью контракта ответа |
| AC8 | Порядок доставки этапов не влияет на результат; отставание нижнего этапа не блокирует верхние | Тест: события этапов в разном порядке/с лагом дают тот же итог, views полон при пустых deals |
Обратные ссылки
Автоссылки: где используется этот документ.
- Use Cases (2): UC-STA-002. Детализация просмотров до здания / группы планировок / планировки, UC-STA-005. Экспорт отчёта статистики (Excel / PDF) с аудитом
- index.md (1): DevStats Service (Pin.DevStats)
- facts (1): funnel_daily (ClickHouse rollup / воронка)
- registries (1): Реестр use cases и user stories PIN
Связанные Документы
- Контракт операции: get-conversion-funnel.md.
- Домены: dev-stats-filter.md,
response-models.md (
FunnelModel/FunnelStage). - Источник: funnel-daily-rollup.md (этапы, бизнес-ключи, order-key); измерения — ../dimensions/property-object.md; карта областей — README.md.
- Источники этапов (потребляются): events/README.md (favorites/selections/crm →
funnel_daily); события-источники —docs/06-services/crm/events/,docs/06-services/favorites/events/. - Смежные use-cases: UC-STA-001 (сводка), UC-STA-002 (детализация), UC-STA-005 (экспорт).
- ADR: 0057 dev-stats/ClickHouse, 0056 simplicity-first, 0052 tenancy.