GET /api/v1/public/projects/{projectId}/buildings/{buildingId} — Карточка здания (литера/корпуса)
Назначение
Публичная карточка здания (литера/корпуса) внутри проекта: этажность, срок сдачи, готовность, статус
строительства, счётчики объектов недвижимости. Используется для заголовка шахматки/ассортимента и для
деталей «срок сдачи» в ограниченной карточке объекта. Ограниченная (аноним) и полная (авторизованный)
проекции отличаются только счётчиком свободных объектов недвижимости — производной статусов объектов,
скрываемой от неавторизованных. Зеркалируется в agents area
(GET /api/v1/agents/projects/{projectId}/buildings/{buildingId}) той же операцией.
Metadata
| Поле | Значение |
|---|---|
| Сервис/контекст | chessboard |
| API area | public (зеркало: agents) |
| Feature group | buildings |
| Статус | draft |
| Owner | PIN Platform Core |
| Документ | docs/06-services/chessboard/api/public/buildings/get-building.md |
Актор и доступ
| Проверка | Значение |
|---|---|
| Actor type | Anonymous / User (инвестор, агент, менеджер застройщика) |
| Auth policy / Permissions | none — public endpoint; masking по признаку авторизации |
| Scope (RBAC) | не применяется |
| Record-level | не применяется |
| Tenant isolation | Bypass tenant-фильтра только для Building.Status = Published внутри Project.Status = Published при Developer.Status = Published |
| Audit | none (read) |
HTTP-контракт
| Поле | Значение |
|---|---|
| Method | GET |
| Route | /api/v1/public/projects/{projectId}/buildings/{buildingId} |
| Success status | 200 |
| Idempotency header | не применяется (GET) |
| Correlation | сквозной trace через заголовок traceparent |
Входные данные / параметры запроса
| Поле | Источник | Тип | Обязательность | Валидация / Ограничения | Безопасность |
|---|---|---|---|---|---|
ProjectId | route | Guid | Да | Required, != Guid.Empty | — |
BuildingId | route | Guid | Да | Required, != Guid.Empty; здание должно принадлежать проекту (шаг 2 алгоритма) | — |
IsAuthenticated | identity claims | bool | Да (вычисляется) | из контекста авторизации | определяет masking |
Модель ответа BuildingCardResponse
Проекция BuildingEntity; masking-колонка — правило для анонима.
| Поле | Тип | Обязательность | Источник | Masking (аноним) | Описание |
|---|---|---|---|---|---|
Id | Guid | Да | Building.Id | — | Идентификатор здания. |
ProjectId | Guid | Да | Building.ProjectId | — | Проект-родитель. |
ProjectName | string | Да | Project.Name | — | Для хлебных крошек без второго запроса. |
Name | string | Да | Building.Name | — | «Литер 3», «Корпус Б». |
FloorsTotal | short | Да | Building.FloorsTotal | — | Этажность (ось Y шахматки). |
SectionsCount | short? | Нет | Building.SectionsCount | — | Секций/подъездов (ось X шахматки). |
DeliveryYear | short? | Нет | Building.DeliveryYear | — | Год сдачи («срок сдачи»). |
DeliveryQuarter | short? | Нет | Building.DeliveryQuarter | — | Квартал сдачи («IV кв. 2027»). |
DeliveredAt | DateOnly? | Нет | Building.DeliveredAt | — | Фактический ввод в эксплуатацию. |
ConstructionStatus | ConstructionStatus (string) | Да | Building.ConstructionStatus | — | Статус строительства здания (reference-data.md). |
ReadinessPercent | decimal | Да | Building.ReadinessPercent | — | Готовность 0–100. |
CeilingHeightMeters | decimal? | Нет | Building.CeilingHeightMeters | — | Типовая высота потолков. |
PropertyObjectsTotalCount | int | Да | Building.PropertyObjectsTotalCount | — | Всего объектов недвижимости здания. |
PropertyObjectsFreeCount | int? | Нет | Building.PropertyObjectsFreeCount | null (производная статусов) | Свободных объектов недвижимости. |
IsLimited | bool | Да | вычисляется: !IsAuthenticated | — | Отдана ограниченная проекция. |
Version | long | Да | Building.Version | — | Версия агрегата. |
Предусловия и постусловия
Предусловия:
- Вызов анонимом (ограниченная проекция) или авторизованным пользователем (полная); признак авторизации определяет masking.
- Здание видимо только по публичному срезу:
Building.Status = PublishedвнутриProject.Status = PublishedприDeveloper.Status = Published(INV-DEV-6). Иначе — неотличимо от отсутствия (404).
Постусловия (read — состояние не меняется):
- Возвращена карточка здания; для анонима
PropertyObjectsFreeCount = null,IsLimited = true; для авторизованного значения отдаются как есть,IsLimited = false.
Счётчики PropertyObjectsTotalCount/PropertyObjectsFreeCount — денормализация, отстаёт до debounce-джоба
project-aggregates-recalc; остальные поля — прямое чтение source of truth.
Алгоритм
Чтение карточки здания по публичному срезу с проверкой публичности родителей и masking свободного счётчика для анонима.
- Контекст и доступ. Вызывает аноним или авторизованный пользователь; признак авторизации определяет masking. Чтение — только по публичному срезу (Published-иерархия).
- Проверка входа.
ProjectIdиBuildingIdзаданы (не пустые); иначе —VALIDATION_ERROR. Существование, публичность и принадлежность здания проекту проверяются при чтении (шаг 3, единый404). - Что читаем (родители до дочернего — для проверок публичности):
- Проект по id со статусом
Publishedи не удалённый; не найден →CHESSBOARD_PROJECT_NOT_FOUND. - Застройщик проекта; если его статус не
Published— проект публично невидим (INV-DEV-6) →CHESSBOARD_PROJECT_NOT_FOUND. - Здание по id в этом проекте со статусом
Publishedи не удалённое; не найдено →CHESSBOARD_BUILDING_NOT_FOUND. Условие принадлежности проекту проверяется вместе с существованием (несовпадение неотличимо от отсутствия — без утечки структуры чужих проектов).
- Проект по id со статусом
- Сборка ответа и masking. Поля ответа — по таблице модели: плоские значения здания,
ProjectNameиз проекта. При анонимеPropertyObjectsFreeCount = null,IsLimited = true; для авторизованного значения отдаются как есть,IsLimited = false. - Результат. Карточка здания, статус
200; не найдено/непублично →404; нарушение проверки входа →400.
Диаграмма
Ошибки и failure modes
| Код | HTTP status | Условие | Сообщение | Retry |
|---|---|---|---|---|
VALIDATION_ERROR | 400 | Пустые ProjectId/BuildingId | «Некорректные параметры запроса» | no retry |
CHESSBOARD_PROJECT_NOT_FOUND | 404 | Проект не существует / не публичен / застройщик скрыт | «Проект не найден» | no retry |
CHESSBOARD_BUILDING_NOT_FOUND | 404 | Здание не существует / не Published / не принадлежит проекту / удалено | «Здание не найдено» | no retry |
INTERNAL_ERROR | 500 | Инфраструктурный сбой | generic | retry (backoff) |
Совместимость и наблюдаемость
Optional-поля — additive; изменение masking в сторону раскрытия — breaking (новая версия route).
- Enum-строки: unknown-fallback на клиенте обязателен.
- Logs:
projectId,buildingId, actor type; metrics:chessboard_public_building_requests_total, latency histogram (SLO p99 < 300 мс); traces: OTel spanchessboard.get-public-building. - Dashboard/runbook — chessboard-overview (README).
Acceptance Criteria
- AC1 (полная проекция). Дано: авторизованный пользователь, published-здание published-проекта
published-застройщика. Когда:
GET. Тогда:200,PropertyObjectsFreeCountзаполнен,IsLimited = false. - AC2 (masking для анонима). Дано: тот же ресурс, вызывает аноним. Когда:
GET. Тогда:200,PropertyObjectsFreeCount = null,IsLimited = true. - AC3 (непубличный родитель). Дано: проект не
Publishedили застройщик скрыт (INV-DEV-6). Когда:GET. Тогда:CHESSBOARD_PROJECT_NOT_FOUND(404) — причина не раскрывается. - AC4 (здание вне проекта/не published). Дано:
BuildingIdне принадлежит проекту, неPublishedили удалён. Когда:GET. Тогда:CHESSBOARD_BUILDING_NOT_FOUND(404), неотличимо от отсутствия. - AC5 (пустые идентификаторы). Дано:
ProjectId/BuildingId = Guid.Empty. Когда:GET. Тогда:VALIDATION_ERROR(400).
Обратные ссылки
Автоссылки: где используется этот документ.
- API (2): GET /api/v1/public/projects — Лента published-проектов (поиск + фильтры + сортировки), GET /api/v1/public/projects/{projectId} — Карточка проекта (ограниченная/полная)
- registries (1): Реестр API-методов PIN
Связанные документы
- Сущности: building.md, project.md, developer.md, reference-data.md.
- Соседние операции: get-project.md, get-chessboard.md, list-property-objects.md.