UC-CHS-004. Просмотр шахматки проекта: гость vs инвестор (разница полей)
Назначение
Read-only сценарий просмотра шахматки проекта (матрица «этажи × секции» с цветовой индикацией статусов)
и различие проекций для неавторизованного гостя и авторизованного инвестора/агента: гостю точные цены,
статусы объектов и сама шахматка не отдаются. Сценарий относится к контексту chessboard.
Metadata
| Поле | Значение |
|---|---|
| ID | UC-CHS-004 |
| Контекст | chessboard (см. docs/06-services/chessboard/) |
| Тип | основной |
| Статус | draft |
Актор
| Поле | Значение |
|---|---|
| Роль | Гость (ограниченная проекция) / Инвестор / Агент (полная проекция) |
| Permissions / scope | Permission не требуется: public area. Разница проекций — по факту аутентификации (валидный access-JWT identity). Agents area — те же полные чтения |
| Tenant | Актор вне tenant (инвестор/гость — TenantId = null, ADR-0052); публичное чтение отдаёт только Published-срезы |
| Record-level | Не применяется |
Предусловие
- Проект
Published, его застройщикPublished(иначе public-проекции фильтруют — INV-DEV-6), зданиеPublished. - Объекты недвижимости заведены (UC-CHS-002 / UC-CHS-005);
Hidden-объекты недвижимости публично не отдаются.
Триггер
| Поле | Значение |
|---|---|
| Источник | Переход в интерфейсе / вызов API |
| Триггерящий элемент | Карточка проекта → вкладка «Шахматка» (/hotels/[id]/chessboard) |
Основной Поток
- Инвестор (авторизован) открывает вкладку «Шахматка» карточки проекта; фронт вызывает
GET /public/projects/{projectId}/chessboard?buildingId={buildingId}. Актор берётся из access-JWT, если передан (гость — анонимный). - Проверяется вход:
projectId/buildingId— Guid; состояние —Project.Status = PublishedиDeveloper.Status = Published(иначе404— скрытые срезы неотличимы от несуществующих); связь —building.ProjectId == projectId. - Читаются данные под проекцию (без загрузки агрегатов): проект (
Status,DeveloperId,Name,CurrencyId) → застройщик (Status) → корпуса проектаStatus = Published(список для переключателя, сортировка поName) → объекты недвижимости выбранного здания (DeletedAt == null, для гостя и publicStatus != Hidden, сортировкаFloor desc,Section,Number) — один range-scan по индексуix_property_objects_building_floor(building_id, floor, section). - Строится read-модель шахматки: объекты недвижимости группируются по
Floor(ось Y, отBuilding.FloorsTotalвниз) иSection(ось X). Маппинг ячейки:PropertyObjectId,Number,Rooms,TotalArea,Status→ цвет (Free— зелёный,Reserved/Booked— жёлтый,Sold— красный,Hidden— серый, только для застройщика в developers area — публично отсутствует),Price+PricePerMeter(tooltip), таймерыReservedUntil/BookedUntil(обратный отсчёт в tooltip для авторизованных). - Результат —
ChessboardModel:ProjectId,Buildings[] {Id, Name, FloorsTotal, SectionsCount},SelectedBuildingId,Floors[] {Floor, Cells[] {PropertyObjectId, Number, Section, Rooms, TotalArea, Status, StatusColor, Price, PricePerMeter, ReservedUntil?, BookedUntil?}},Legend[](маппинг статус→цвет),CurrencyId+CurrencySnapshot(display-имя/знак валюты — snapshots.md). Freshness: read-committed снимок; таймеры клиент считает от серверногоNowв ответе. - Фронт рисует интерактивную матрицу: hover — tooltip (номер, цена), клик по ячейке — переход в карточку
объекта (
GET /public/property-objects/{id}— полная для авторизованного). Переключение корпуса/этажа — повторный запрос с другимbuildingId(пагинация по этажам для больших зданий — параметрыfloorFrom/floorTo, виртуализация).
Альтернативные Потоки
A1. Гость запрашивает шахматку
- Запрос без валидного JWT →
401c кодомCHESSBOARD_AUTH_REQUIRED: шахматка, точные цены и статусы объектов неавторизованным скрываются. - Фронт показывает ограниченную карточку проекта (
GET /public/projects/{id}— вкладки Информация/Локация/Финансирование/Юрданные/Ход строительства/Видео/Карта, диапазон цен проектаPrice(Min–Max) без цен объектов недвижимости) и CTA входа. После авторизации (identity, UC-IDN-001) — возврат на шаг 1 основного потока.
A2. Гость смотрит ограниченную карточку объекта
GET /public/property-objects/{id}без JWT → ограниченная проекция: описание, срок сдачи (Building.DeliveryYear/Quarter), общая/жилая площадь, этаж, застройщик — без точной цены, статуса, таймеров, инвест-аналитики. Авторизованному — полная (сама аналитика/график —invest-analyticsиcatalog, не шахматка).
A3. Проект скрыт/архивирован или застройщик Hidden
Project.Status != PublishedлибоDeveloper.Status != Published(INV-DEV-6) →404(утечка существования скрытых срезов недопустима).Building.Status = Hidden— корпус отсутствует в спискеBuildings[]; прямой запрос по нему →404.
A4. В здании нет доступных к показу объектов недвижимости
- Список объектов пуст →
200c пустымиFloors[]; фронт показывает «объекты появятся позже» (не ошибка).
A5. Просмотр шахматки застройщиком (developers area)
- Менеджер застройщика смотрит ту же матрицу через
GET /developers/projects/{id}/chessboard— без public-фильтров: видитHidden-объекты недвижимости (серым),Draft/Hidden-корпуса,HoldDealIdактивных холдов. Permissionchessboard.property-objects.manage, ограничение своим tenant-ом обычное (без bypass).
Межсервисный контракт, согласованность и наблюдаемость
Что читается и чего шахматка ожидает от соседей. Матрица строится только из локального состояния
шахматки — source of truth статуса, таймеров и цены объектов недвижимости; синхронных вызовов соседних
сервисов при отрисовке нет. Актуальность локального состояния обеспечивают фоновые потоки: статусы/таймеры
— consumer CRM (UC-CHS-006, топики pin.crm.booking-*/deal-*); цены — UC-CHS-003/UC-CHS-005; паспортные
поля и продажи вне PIN — синк Talent (UC-CHS-005).
Окно согласованности (что видит инвестор). Между событием CRM (например, резерв объекта недвижимости)
и его применением consumer-ом UC-CHS-006 есть короткое окно, в котором матрица ещё показывает прежний
статус (ячейка зелёная Free, хотя заявка на бронирование уже создана). После применения события
повторный запрос вернёт жёлтую ячейку с ReservedUntil. Это ожидаемая eventual consistency, а не
рассинхрон: шахматка всегда отдаёт свой последний закоммиченный (read-committed) статус.
Деградация зависимостей. Инвест-аналитика и график роста цены (invest-analytics/catalog) — вне
границ шахматки; их недоступность не ломает саму матрицу (деградация: аналитический блок карточки скрыт,
статусы/цены/таймеры объектов недвижимости отдаются как обычно).
Наблюдаемость / НФТ. Публичное чтение без записи и без PII; целевая латентность p95 — десятки мс на
проект средней величины (один range-scan по ix_property_objects_building_floor); большие здания —
пагинация по этажам (floorFrom/floorTo) + виртуализация. Public API под rate-limit (превышение →
429 с backoff); короткое кеширование матрицы допустимо, инвалидация — по статус/ценовым событиям объектов
недвижимости здания. Разница проекций гость/инвестор — критичная точка приватности: контракт-тесты
фиксируют, что неавторизованному не отдаются шахматка, точные цены, статусы и таймеры.
Постусловие
- Состояние системы не изменилось (read-only); мутаций, событий, транзакций нет.
- Инвестор видит актуальную (read-committed) матрицу со статусами/ценами/таймерами; гость — только ограниченную карточку без шахматки.
- Факт просмотра фиксирует контекст
user-activity(вне границ шахматки).
Возможные Ошибки
| Код | HTTP | Условие | Поведение клиента |
|---|---|---|---|
CHESSBOARD_AUTH_REQUIRED | 401 | Запрос шахматки/полной карточки без JWT (A1) | Показать CTA входа + ограниченную версию |
CHESSBOARD_PROJECT_NOT_FOUND | 404 | Проект не существует / не Published / застройщик Hidden (A3) | Страница 404 |
CHESSBOARD_BUILDING_NOT_FOUND | 404 | buildingId не существует / не Published / чужого проекта | Сброс на первый корпус проекта |
| — (validation) | 400 | Невалидные Guid / floorFrom > floorTo | Исправить параметры |
| — (rate limit) | 429 | Превышение лимита public API | Retry с backoff |
Доменные События
Не поднимаются — read-only сценарий (просмотры трекает user-activity: события
property-object-view-ended/session-ended по ADR-0056; шахматка событий просмотра не пишет).
Kafka Интеграционные События
Не публикуются. Потребляемая связь: актуальность статусов/цен в матрице обеспечивают UC-CHS-006 (consumer
статусов CRM pin.crm.booking-*/pin.crm.deal-* — маппинг «событие → переход» в
../consumers/crm-property-object-status.md) и
UC-CHS-003/005 (цены) — шахматка всегда читает своё локальное состояние-source-of-truth.
Acceptance Criteria
| # | Критерий | Проверка |
|---|---|---|
| AC1 | Гость: 401 на шахматку; ограниченные карточки проекта/объекта без точных цен и статусов | contract-тест проекций гостя |
| AC2 | Инвестор: полная матрица со статусами, ценами, ценой/м², таймерами | contract-тест авторизованной проекции |
| AC3 | Hidden-объекты недвижимости и Hidden/Draft-корпуса отсутствуют в public-ответе, но видны застройщику (A5) | тест трёх областей (public/agents/developers) |
| AC4 | Скрытый проект/застройщик → 404 без утечки существования (A3) | тест INV-DEV-6 |
| AC5 | Ячейки сгруппированы Floor desc × Section; цветовая легенда соответствует статусам | snapshot-тест read-модели |
| AC6 | После CRM-события резерва (UC-CHS-006) повторный запрос показывает жёлтую ячейку с ReservedUntil | e2e-тест цепочки |
| AC7 | Пагинация по этажам (floorFrom/floorTo) возвращает согласованные срезы | тест пагинации |
| AC8 | Недоступность invest-analytics/catalog не ломает матрицу: аналитический блок скрыт, статусы/цены/таймеры отдаются | тест деградации зависимостей |
| AC9 | До применения CRM-события матрица показывает прежний статус, после — обновлённый (окно eventual consistency) | тест окна согласованности |
Обратные ссылки
Автоссылки: где используется этот документ.
- scenarios (1): UC-OVR-007. Просмотр каталога «глазами инвестора» (impersonation)
- registries (1): Реестр use cases и user stories PIN
Связанные Документы
- API методы: ../api/public/chessboard/get-chessboard.md, ../api/public/projects/search-projects.md, ../api/public/property-objects/get-property-object.md.
- Domain entities: ../domain/property-object.md (статусы/цвета), ../domain/building.md (оси матрицы), ../domain/project.md, ../domain/developer.md (INV-DEV-6).
- Витрина/ранжирование/оверрайды —
docs/06-services/catalog/; трекинг просмотров —docs/06-services/user-activity/; статистика для застройщика —docs/06-services/dev-stats/. - Связанные UC: UC-CHS-006 (откуда берутся статусы), UC-CHS-003 (цены), UC-IDN-001 (вход гостя).