UC-STA-001. Застройщик смотрит статистику проекта (период + проект)
Назначение
Застройщик открывает в личном кабинете аналитику внимания к своей недвижимости: задаёт период
(DateFrom/DateTo) и проект (ProjectId) и получает сводку (просмотры / уникальные зрители / средняя
длительность / повторные просмотры) и временной ряд просмотров. Сценарий только читает данные — ничего не
меняет. Контракты операций — get-views-summary.md и
get-views-trend.md; состав дашборда —
dev-stats-overview.md; модель фильтра —
dev-stats-filter.md; источник данных — суточный агрегат просмотров
property_object_view_daily. Контекст — dev-stats (ADR-0057).
Metadata
| Поле | Значение |
|---|---|
| ID | UC-STA-001 |
| Контекст | dev-stats (см. docs/06-services/dev-stats/) |
| Тип | основной |
| Статус | draft |
Актор
| Роль | Permissions / scope | Tenant | Record-level |
|---|---|---|---|
Девелопер (застройщик, ЛК-аналитика) | dev-stats.view; scope строго = свой DeveloperId | TenantId = DeveloperId = CompanyEntity.Id (тип Developer, ADR-0052) | не применяется — выдаются только агрегаты (не персоны) |
Запрос жёстко фильтруется по DeveloperId = актор (обязательный компонент DevStatsFilterModel);
DeveloperId берётся из контекста безопасности, не из параметров запроса; доступ к чужому застройщику
невозможен (fail-closed).
Предусловие
- Суточный агрегат property_object_view_daily наполнен: факты
просмотров обогащены иерархией из измерений
dim_*; свежесть ≤ 5 мин от события. - Реплики-измерения
dim_developer/dim_projectнаполнены (для выбора проекта в UI и валидности иерархии). - Токен застройщика содержит право
dev-stats.viewи разрешённыйDeveloperId(роль developer).
Триггер
| Поле | Значение |
|---|---|
| Источник | UI (страница ЛК-аналитики застройщика) → API call |
| Триггерящий элемент | дашборд /developer/stats (выбор периода + проекта) → GET /api/v1/dev-stats/views/summary (+ .../timeseries) |
Основной Поток
Полный контракт операций — get-views-summary.md / get-views-trend.md; ниже — сценарий и особенности чтения витрины.
- Ввод. Застройщик выбирает период (
DateFrom/DateTo) и проект (ProjectId); опционально — тип зрителя (ViewerKind) / источник (ViewSource) и гранулярность ряда (day/week/month). - Запрос. Интерфейс запрашивает сводку и временной ряд за выбранные период/проект.
DeveloperIdв запросе не передаётся — он берётся из контекста безопасности (токена). - Проверка входа и доступа.
DateFrom/DateToобязательны иDateFrom ≤ DateTo, диапазон ≤ 3 лет (глубина хранения);ProjectId— валидный идентификатор.DeveloperIdподставляется из контекста безопасности; если клиент прислалDeveloperId, отличный от актора, либо у актора нет праваdev-stats.view— отказFORBIDDEN(A3) до чтения данных. Нарушение формата/диапазона входа —VALIDATION_ERROR. - Чтение метрик. Данные читаются из суточного агрегата
property_object_view_daily(не из сырых фактов), строго в срезеDeveloperId = актор ∧ ProjectId ∧ EventDate ∈ [DateFrom; DateTo]. Сканируется только нужная ветка иерархии (префикс(DeveloperId, ProjectId)) и только затронутые месячные партиции по дате; уровни ниже проекта (BuildingId→PropertyObjectId) не читаются.ViewerKind/ViewSource, если заданы, дополнительно сужают срез. - Расчёт мер (устойчивый к дублям). Подсчёт устойчив к повторам и at-least-once-доставке: дубликат факта
и пара open/closed одной сессии не задваивают меры. Сводка:
Views,UniqViewers, средняя длительность =DurationSum / Views, повторные просмотры =Views − UniqViewers. Временной ряд — те же меры с группировкой по дате (или по началу недели/месяца согласноgranularity). - Результат. Возвращается типизированная сводка
ViewsSummary(Views,UniqViewers,AvgDurationSeconds,RepeatViews) и рядViewsTimeseries(список точекViewsTimeseriesPointсDate,Views,UniqViewers). Интерфейс рисует KPI-плитки сводки и линейный график ряда; пустой период → A1; смена гранулярности — повторный запрос ряда.
Диаграмма
Интеграция и согласованность
Сценарий не делает синхронных вызовов соседних сервисов: он читает только собственную витрину
property_object_view_daily. Наполнение витрины — асинхронное (Kafka-ingestion user-activity →
факты → MV), окно eventual-consistency ≤ 5 мин (freshness SLA). Практические следствия для читателя:
- Просмотры последних минут могут ещё не отразиться (в пределах окна freshness) — не ошибка, догоняется.
- Текущий день «доуточняется»: длительности дорастают по мере прихода closed-фактов, счётчики прошедших дней могут вырасти при догоне late-dimension (идемпотентно). Ряд за завершённые прошлые дни стабилен.
Альтернативные Потоки
A1. Пустой период (нет просмотров)
- Срез не совпал ни с одной строкой агрегата за период/проект.
- Возвращается сводка из нулей (
Views=0,UniqViewers=0,AvgDurationSeconds=0,RepeatViews=0) и пустой ряд — HTTP200(отсутствие данных — валидный исход, не ошибка).
Завершается: фронт рендерит пустое состояние дашборда.
A2. Разбивка по типу зрителя (groupBy = viewerKind)
- Застройщик включает разбивку Guest/Agent/Investor.
- К мерам добавляется группировка по
ViewerKind— доли по типам зрителя за тот же срез(DeveloperId, ProjectId).
Возвращается к основному потоку на шаг 6 (сборка разбивки).
A3. Попытка чужого DeveloperId
- Клиент передал
DeveloperId ≠ актор(или у актора нет праваdev-stats.view). - Операция завершается
FORBIDDEN(403) до чтения витрины (fail-closed, изоляция tenant).
A4. Свежие данные ещё догружаются (окно freshness)
- Застройщик запросил статистику за период, включающий текущий день/последние минуты.
- Часть просмотров ещё не доехала в витрину (в пределах ≤ 5 мин) — возвращается
200с текущими (частичными по последнему интервалу) значениями; прошлые завершённые дни полны. - Повторный запрос через несколько минут отражает догнавшие данные (значения монотонно дорастают, идемпотентно — без задвоения).
Завершается: фронт показывает данные с пометкой актуальности «данные за последние минуты могут уточняться».
Постусловие
- Мутаций нет (read-only): факты/агрегаты/измерения не изменяются, доменные и интеграционные (Kafka) события
не публикуются (
dev-stats— листовая аналитика, событий не порождает), аудит не пишется (аудит — только экспорт, UC-STA-005). - Клиент получил типизированную сводку + временной ряд строго в scope своего
DeveloperId.
Возможные Ошибки
| Код | HTTP | Условие | Поведение клиента |
|---|---|---|---|
VALIDATION_ERROR | 400 | Нет DateFrom/DateTo; DateFrom > DateTo; диапазон > 3 лет; невалидный ProjectId | Показать ошибку параметров периода |
FORBIDDEN | 403 | DeveloperId в запросе ≠ актор; нет dev-stats.view (A3) | Скрыть данные, не ретраить |
| — (не ошибка) | 200 | Нет просмотров за период (A1) | Пустое состояние дашборда |
5xx (ProblemDetails) | 500/503 | Отказ аналитической витрины pin_dev_stats | Инфраструктурная ошибка; ретрай позже |
Acceptance Criteria
| # | Критерий | Проверка |
|---|---|---|
| AC1 | Запрос «проект за период» сканирует только префикс (DeveloperId, ProjectId) + затронутые месячные партиции | Тест плана запроса: уровни иерархии ниже проекта не сканируются |
| AC2 | DeveloperId берётся из актора; чужой DeveloperId → 403 до чтения витрины | Изоляционный тест: подстановка чужого id не возвращает данные |
| AC3 | Подсчёт устойчив к дублям: повтор факта и пара open+closed одной сессии не задваивают Views | Тест: дубль факта и open+closed одной сессии считаются один раз |
| AC4 | Средняя длительность = DurationSum / Views (нулевая длительность open-строк не искажает среднюю) | Тест: смесь open (0 c) и closed → корректная средняя |
| AC5 | Пустой период → 200 с нулевой сводкой и пустым рядом (не ошибка) | Тест A1 |
| AC6 | Ряд поддерживает granularity day/week/month (группировка по дате/началу недели/месяца) | Тест: три гранулярности над одним диапазоном |
| AC7 | Ответ строго типизирован (ViewsSummary/ViewsTimeseriesPoint) | Ревью контракта ответа |
| AC8 | Нет синхронных вызовов соседних сервисов; данные последних минут догоняются в окне freshness ≤ 5 мин (A4) | Тест: запрос за текущий день не блокируется/не ошибается; повторный запрос отражает догнавшие факты |
Обратные ссылки
Автоссылки: где используется этот документ.
- Use Cases (4): UC-STA-002. Детализация просмотров до здания / группы планировок / планировки, 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-views-summary.md, get-views-trend.md; композиция ЛК — dev-stats-overview.md.
- Домены: dev-stats-filter.md (
DevStatsFilterModel+groupBy), response-models.md (типизированные ряды/сводки), viewer-classification.md (ViewerKind/ViewSource). - Источник: property-object-view-daily-rollup.md (меры/агрегат), property-object-view-facts.md (order-key/обогащение); карта областей — README.md.
- Смежные use-cases: UC-STA-002 (детализация), UC-STA-003 (сравнение), UC-STA-005 (экспорт).
- ADR: 0057 dev-stats/ClickHouse, 0056 simplicity-first, 0052 tenancy.