Модели ответа dev-stats (типизированные ряды / точки / сводки)
Дом общих строительных блоков типизированных ответов области developers (ADR-0057): value objects,
ref-модели и примитивы рядов/точек, переиспользуемые методами. Модель ответа каждого метода (её поля)
описана в документе самого метода — здесь только разделяемые типы и карта «метод → модель». Все модели
строго типизированы. Пагинируемые рейтинги возвращают страницу (items/totalCount/page/pageSize/
hasMore).
Value objects
NullableRange<T>
Диапазон с опциональными границами (From/To) — вместо парных скалярных *From/*Max/*Min/*To
полей. Одна модель, одна валидация From <= To.
| Поле | Тип | Описание |
|---|---|---|
From | T? | нижняя граница (включительно) |
To | T? | верхняя граница (исключительно для бинов; null — открытый хвост) |
Применение: период фильтра NullableRange<DateOnly> (dev-stats-filter.md); бины
гистограммы длительностей NullableRange<int> (get-duration-histogram
— DurationBinModel.Range); бакеты частоты повторов NullableRange<int>
(get-repeat-frequency — RepeatBucketModel.Range).
Семантика границ зависит от применения (единый тип — разные соглашения о включении):
| Применение | From | To | Открытый хвост |
|---|---|---|---|
Период дат (DateOnly) | включительно | включительно (день To входит в выборку) | обе границы обязательны (период — required-поле фильтра) |
Бины длительности/повторов (int) | включительно | исключительно ([From; To)) | последний бин To = null — «From и больше» |
Общее правило валидности во всех применениях: если обе границы заданы — From <= To; для наборов бинов
диапазоны идут без перекрытий и без разрывов, покрывая всю ось (первый бин от 0, последний — открытый).
Страница рейтинга
Единый формат страницы для пагинируемых рейтингов (top-objects, bounce-signal, time-to-first-view).
Параметры пагинации (page/pageSize) — dev-stats-filter.md, method-specific.
| Поле | Тип | Описание |
|---|---|---|
Items | T[] | строки текущей страницы, отсортированные по мере уровня (по умолчанию по убыванию) |
TotalCount | long | общее число групп уровня по срезу (для счётчика/пейджера) |
Page | int | номер запрошенной страницы (с 1) |
PageSize | int | размер страницы (≤ 100; см. валидацию пагинации) |
HasMore | bool | есть ли следующая страница (Page · PageSize < TotalCount) |
Правила: страница за пределом последней (Page больше числа страниц) — валидный 200 с пустым Items и
прежним TotalCount (не ошибка). Сортировка при равенстве меры доопределяется стабильным вторичным ключом
(id узла) — порядок между вызовами одной страницы детерминирован.
TimeSeriesPointModel
Базовая точка временного ряда (наследуется/переиспользуется рядами trend/unique-viewers).
| Поле | Тип | Описание |
|---|---|---|
Date | string (ISO date) | начало бакета (day/toMonday/toStartOfMonth) |
Views | long | просмотры бакета (uniqMerge) |
UniqViewers | long | уникальные зрители бакета |
Ref-модели узлов иерархии
Пара «id + имя» узла иерархии выносится во вложенную ref-модель (а не двумя плоскими полями). Имя
резолвится из реплик-измерений dim_* (../dimensions/); при лаге измерения Name —
пустой/last-known (деградация подписи, не ошибка).
| Модель | Поля | Источник имени |
|---|---|---|
DeveloperRefModel | DeveloperId: Guid, DeveloperName: string | dim_developer |
ProjectRefModel | ProjectId: Guid, ProjectName: string | dim_project |
BuildingRefModel | BuildingId: Guid, BuildingName: string | dim_building |
LayoutGroupRefModel | LayoutGroupId: Guid, LayoutGroupName: string | dim_layout_group |
LayoutRefModel | LayoutId: Guid, LayoutName: string | dim_layout |
PropertyObjectRefModel | PropertyObjectId: Guid, PropertyObjectNumber: string | dim_property_object |
Узлы в get-hierarchy-funnel (HierarchyStageModel/
HierarchyNodeModel) и get-top-objects (TopObjectRow) несут
соответствующую ref-модель уровня вместо разрозненных id/name.
PropertyObjectLayoutModel (группа связанных полей планировки)
Связанные атрибуты планировки объекта недвижимости — одной под-моделью (а не набором плоских полей).
| Поле | Тип | Источник |
|---|---|---|
LayoutId | Guid? | dim_property_object.LayoutId |
LayoutGroupId | Guid? | dim_property_object.LayoutGroupId |
LayoutName | string | dim_layout.Name |
Rooms | int | dim_layout.Rooms (0 = студия) |
TotalAreaM2 | decimal | dim_layout.TotalArea |
Карта «метод → result-модель» (поля — в документе метода)
| Метод | Result-модель | Ключевые под-модели |
|---|---|---|
| get-views-summary | ViewsSummaryResult | ViewerKindSummaryModel |
| get-views-trend | ViewsTrendResult | ViewsTrendPointModel, ViewsTrendComparisonModel |
| get-unique-viewers | UniqueViewersResult | ViewerKindCountModel, UniqueViewersPointModel |
| get-duration-histogram | DurationHistogramResult | DurationBinModel (NullableRange<int>) |
| get-repeat-frequency | RepeatFrequencyResult | RepeatBucketModel (NullableRange<int>) |
| get-hierarchy-funnel | HierarchyFunnelResult | HierarchyStageModel, HierarchyNodeModel (ref-модели) |
| get-conversion-funnel | ConversionFunnelResult | ConversionStageModel |
| get-top-objects | страница TopObjectRow | TopObjectRow (ref-модель уровня) |
| get-session-depth | SessionDepthResult | SessionDepthBucketModel, SessionDepthByViewerKindModel |
| get-activity-heatmap | ActivityHeatmapResult | HeatmapCellModel |
| get-bounce-signal | BounceSignalResult | BounceOverallModel, PropertyObjectBounceModel |
| get-time-to-first-view | TimeToFirstViewResult | TtfvOverallModel, PropertyObjectTtfvModel |
Экспорт-отчёт (DevStatsReportRowModel/DevStatsReportTotalsModel) — reports/dev-stats-export.md.
Инварианты моделей ответа
| Код | Инвариант | Смысл |
|---|---|---|
| INV-RM-1 AggregateOnly | Любая модель ответа несёт только агрегаты и сегменты (счётчики, доли, длительности, ViewerKind/ViewSource) — без UserId/AnonymousId/SessionId/ФИО/контактов | PII зрителей не выходит наружу (ADR-0057 §6) |
| INV-RM-2 RefPairConsistency | В ref-модели id — обязателен и всегда заполнен; Name/Number — из dim_* и может быть пустым/last-known при лаге измерения | Метрика не блокируется отсутствием подписи; клиент рисует id, подпись догоняет |
| INV-RM-3 NullMeansNoBase | Производные (конверсии, Δ%, средние на пустом знаменателе) при нулевом знаменателе → null, не 0 и не ошибка | Отличие «нет базы/нового» от «ноль»; нет деления на ноль |
| INV-RM-4 UniqNotSummable | UniqViewers/уникальные счётчики агрегируются пересчётом из состояний, а не суммой строк-детей | Сумма уникальных по узлам ≥ уникальных по родителю — родительский показатель не задваивается |
Совместимость и маскирование
- Additive: новое опциональное поле модели/новая под-модель — совместимо; клиент-визуализатор игнорирует неизвестные поля. Удаление/переименование/смена типа поля — breaking (согласовать с потребителем).
- Новое wire-значение enum (
ViewerKind/ViewSource) в ответе — breaking для визуализатора (см. viewer-classification.md, «Совместимость»). - Маскирование:
DeveloperIdв презентационных выгрузках маскируется; в API-ответах наружу отдаются только агрегаты — маскировать нечего (персональные идентификаторы в модель не попадают, INV-RM-1).
Обратные ссылки
Автоссылки: где используется этот документ.
- Домен (CQRS) (1): DevStatsFilterModel (общий вход метрик dev-stats)
- API (8): GET /api/v1/dev-stats/activity-heatmap — Хитмап активности (час × день недели), GET /api/v1/dev-stats/bounce-signal — Сигнал отказа (короткие просмотры по объекту), GET /api/v1/dev-stats/conversion-funnel — Воронка конверсии (просмотр→сделка), GET /api/v1/dev-stats/session-depth — Глубина сессии (объектов за сессию), GET /api/v1/dev-stats/time-to-first-view — Время до первого просмотра (TTFV), GET /api/v1/dev-stats/top-objects — Топ объектов по просмотрам и времени, GET /api/v1/dev-stats/views/hierarchy-funnel — Воронка просмотров по иерархии, GET /api/v1/dev-stats/views/trend — Динамика просмотров + сравнение периодов
- Use Cases (5): UC-STA-001. Застройщик смотрит статистику проекта (период + проект), UC-STA-002. Детализация просмотров до здания / группы планировок / планировки, UC-STA-003. Сравнение периодов и тренд просмотров, UC-STA-004. Воронка конверсии «просмотр → сделка», UC-STA-005. Экспорт отчёта статистики (Excel / PDF) с аудитом
- Отчёты (1): Отчет/Export: dev-stats-export (выгрузка аналитики застройщика)
- index.md (1): DevStats Service (Pin.DevStats)
- registries (1): Реестр сущностей PIN
Связанные документы
- Общий вход: dev-stats-filter.md; enum'ы: viewer-classification.md.
- Меры/источники: property-object-view-daily-rollup.md, funnel-daily-rollup.md; имена узлов — ../dimensions/.
- ADR: ADR-0057, ADR-0056.