UC-STA-002. Детализация просмотров до здания / группы планировок / планировки
Назначение
Застройщик из сводки по проекту последовательно проваливается вниз по иерархии —
проект → здание → группа планировок → планировка (→ объект недвижимости) — и на каждом уровне видит
разбивку просмотров (top-N с постраничной выдачей). Каждый уровень детализации сужает срез до выбранной ветки
иерархии. Сценарий только читает данные. Контракты операций —
get-hierarchy-funnel.md,
get-top-objects.md; модель фильтра —
dev-stats-filter.md; источник —
property_object_view_daily. Контекст — dev-stats (ADR-0057).
Metadata
| Поле | Значение |
|---|---|
| ID | UC-STA-002 |
| Контекст | dev-stats (см. docs/06-services/dev-stats/) |
| Тип | основной |
| Статус | draft |
Актор
| Роль | Permissions / scope | Tenant | Record-level |
|---|---|---|---|
Девелопер (застройщик) | dev-stats.view; scope строго = свой DeveloperId | TenantId = DeveloperId = CompanyEntity.Id (ADR-0052) | не применяется (агрегаты) |
Каждый уровень детализации остаётся в scope застройщика: DeveloperId = актор — обязательный префикс любого
запроса; провал вниз лишь добавляет фильтры дочерних уровней.
Предусловие
- Выполнен UC-STA-001 (застройщик уже на дашборде проекта).
- Агрегат property_object_view_daily наполнен; измерения
dim_building/dim_layout_group/dim_layout/dim_property_objectнаполнены (для подписей уровней в UI). - Токен застройщика содержит право
dev-stats.view.
Триггер
| Поле | Значение |
|---|---|
| Источник | UI (клик по строке разбивки — «провалиться в здание/группу/планировку») → API call |
| Триггерящий элемент | таблица разбивки дашборда → GET /api/v1/dev-stats/views/hierarchy-funnel → .../hierarchy-funnel(layout) → top-objects |
Основной Поток
Полный контракт операций — get-hierarchy-funnel.md / get-top-objects.md; ниже — сценарий drill-down.
- Ввод. На дашборде проекта (
ProjectIdзафиксирован из UC-STA-001) застройщик кликает строку здания — запрашивает разбивку по зданиям проекта; затем провал в конкретноеBuildingId— разбивку по группам планировок; далееLayoutGroupId— по планировкам; глубжеLayoutId— топ объектов недвижимости. - Запрос. Каждый уровень — свой запрос с накопленным фильтром и постраничной выдачей: разбивка уровня за
период/проект; при провале добавляется
buildingId, затемlayoutIdи т. д.DeveloperId— из токена. - Проверка входа и доступа.
DateFrom/DateToобязательны (DateFrom ≤ DateTo); заданные уровни-фильтры — валидные идентификаторы;DeveloperId = актор(fail-closed); параметры страницы — размер страницыPageSize ≤ 100, сортировка по мере (по умолчаниюViewsпо убыванию). Нарушение —VALIDATION_ERROR; чужойDeveloperId/нет права —FORBIDDEN. - Чтение разбивки уровня. Данные читаются из
property_object_view_dailyв срезе, удлинённом на выбранный уровень: разбивка по зданиям — срез(DeveloperId, ProjectId)с группировкой поBuildingId; по группам —(DeveloperId, ProjectId, BuildingId)с группировкой поLayoutGroupId; по планировкам —+ LayoutGroupIdс группировкой поLayoutId; топ объектов —+ LayoutIdс группировкой поPropertyObjectId. Каждый уровень читает только выбранную ветку (без соседних) и только затронутые месячные партиции по дате. - Расчёт мер (устойчивый к дублям). На каждую группу —
Views,UniqViewers, средняя длительность =DurationSum / Views; сортировка top-N поViewsпо убыванию + смещение страницы; общее число групп уровня — для счётчикаTotalпостраничной выдачи. Подсчёт устойчив к дублям и at-least-once-доставке. - Результат. Возвращается постраничная разбивка
HierarchyBreakdownRow(LevelId,LevelName— изdim_*,Views,UniqViewers,AvgDurationSeconds) с признаком «есть ещё» и общим счётчикомTotal. Интерфейс показывает таблицу уровня с «показать ещё»; клик по строке — запрос глубже (шаг 2 с добавленным фильтром); «наверх» — возврат к родительскому уровню.
Диаграмма
Альтернативные Потоки
A1. Уровень без просмотров
- На выбранном срезе нет строк агрегата.
- Возвращается пустая разбивка (
Total = 0, «есть ещё» = false) — HTTP200(не ошибка).
Завершается: фронт показывает пустую таблицу уровня.
A2. Прямой глубокий фильтр (без пошагового провала)
- Застройщик сразу задаёт
BuildingId+LayoutGroupIdв фильтре (deep-link/сохранённый вид). - Срез =
(DeveloperId, ProjectId, BuildingId, LayoutGroupId)с группировкой поLayoutId. Результат идентичен пошаговому drill-down (определяется срезом, а не порядком кликов).
Возвращается к основному потоку на шаг 5.
A3. Отсутствует подпись уровня в dim_*
dim_layout/dim_property_objectещё не догналиchessboard(лаг наполнения измерений).- Строка отдаётся с
LevelId, ноLevelName = null/last-known (деградация подписи, не ошибка — метрика считается независимо от подписи).
A4. Страница за пределом выдачи / устойчивость сортировки
- Застройщик запрашивает страницу с номером больше числа страниц уровня или на уровне много групп с равной мерой.
- Страница за пределом →
200с пустымItems, прежнимTotal,HasMore = false(не ошибка). При равенстве меры порядок доопределяется стабильным вторичным ключом (id узла) — одна и та же страница между вызовами детерминирована (нет «прыгающих» строк при пагинации).
Завершается: фронт показывает пустую страницу/стабильный список.
A5. Несуществующий id уровня (deep-link/устаревший вид)
- В накопленном фильтре задан
BuildingId/LayoutId, которого нет (удалён или ещё не реплицирован вdim_*). - Существование id не проверяется — срез не совпадает ни с одной строкой →
200с пустой разбивкой (Total = 0), не404/ошибка (деградационная устойчивость, см. dev-stats-filter.md).
Постусловие
- Мутаций нет (read-only): агрегаты/факты/измерения не изменяются, доменные и интеграционные (Kafka) события не публикуются, аудит не пишется.
- Клиент получил постраничную разбивку выбранного уровня иерархии в scope своего
DeveloperId.
Возможные Ошибки
| Код | HTTP | Условие | Поведение клиента |
|---|---|---|---|
VALIDATION_ERROR | 400 | Нет дат / DateFrom > DateTo; невалидный BuildingId/LayoutGroupId/LayoutId; PageSize > 100 | Показать ошибку параметров |
FORBIDDEN | 403 | DeveloperId ≠ актор; нет dev-stats.view | Скрыть данные |
| — (не ошибка) | 200 | Уровень без просмотров (A1) | Пустая таблица уровня |
5xx (ProblemDetails) | 500/503 | Отказ аналитической витрины pin_dev_stats | Ретрай позже |
Acceptance Criteria
| # | Критерий | Проверка |
|---|---|---|
| AC1 | Каждый уровень детализации сужает срез до выбранной ветки (без чтения соседних веток) | Тест плана: разбивка при заданном buildingId сканирует только срез (…, BuildingId) |
| AC2 | Результат определяется фильтром, а не порядком кликов (A2 == пошаговый drill) | Тест: deep-фильтр и пошаговый провал дают идентичную разбивку |
| AC3 | Постраничная выдача: размер страницы, признак «есть ещё», Total = число групп уровня | Тест: PageSize, «есть ещё», корректный Total |
| AC4 | Сортировка top-N по Views по убыванию | Тест: порядок строк разбивки |
| AC5 | DeveloperId = актор на всех уровнях (чужой → 403) | Изоляционный тест по каждому уровню |
| AC6 | Лаг dim_* → строка с LevelId и деградированной подписью (не ошибка) | Тест A3: метрика есть, LevelName пустой |
| AC7 | Ответ типизирован (HierarchyBreakdownRow) | Ревью контракта ответа |
| AC8 | Страница за пределом → 200 пустая (не ошибка); сортировка стабильна при равной мере | Тест A4: страница > последней и tie-break по id |
| AC9 | Несуществующий id уровня → 200 пустая разбивка (существование не проверяется) | Тест A5: deep-фильтр с неизвестным BuildingId |
Обратные ссылки
Автоссылки: где используется этот документ.
- Use Cases (4): UC-STA-001. Застройщик смотрит статистику проекта (период + проект), UC-STA-003. Сравнение периодов и тренд просмотров, UC-STA-004. Воронка конверсии «просмотр → сделка», UC-STA-005. Экспорт отчёта статистики (Excel / PDF) с аудитом
- index.md (1): DevStats Service (Pin.DevStats)
- registries (1): Реестр use cases и user stories PIN
Связанные Документы
- Контракты операций: get-hierarchy-funnel.md, get-top-objects.md.
- Домены: dev-stats-filter.md (
groupBy, уровни иерархии), response-models.md (HierarchyBreakdownRow). - Источник: property-object-view-daily-rollup.md, property-object-view-facts.md (order-key = иерархия фильтров); измерения — ../dimensions/property-object.md; карта областей — README.md.
- Смежные use-cases: UC-STA-001 (сводка проекта), UC-STA-004 (воронка по срезу).
- ADR: 0057 dev-stats/ClickHouse, 0056 simplicity-first, 0052 tenancy.