Перейти к основному содержимому

GET /api/v1/developers/buildings/{buildingId} — Карточка здания

Назначение

Экран редактирования литера/корпуса в кабинете застройщика. Возвращает полное состояние здания своей компании: все поля карточки и признаки полей, управляемых синхронизацией Talent. Дом полей — сущность Здание.

Metadata

ПолеЗначение
Сервис/контекстchessboard
API areadevelopers
Feature groupbuildings
Статусdraft
Документdocs/06-services/chessboard/api/developers/get-building.md

Актор и доступ

ПроверкаЗначение
Actor typeUser (менеджер застройщика)
Auth policy / Permissionschessboard.buildings.manage
Scope (RBAC)организация / группа проектов / проект (building.ProjectId в scope)
Tenant isolationTenantId = CompanyId из JWT; чужое здание → 404

HTTP-контракт

ПолеЗначение
MethodGET
Route/api/v1/developers/buildings/{buildingId}
Success status200
Correlationсквозной trace через заголовок traceparent

Входные данные / параметры запроса

ПолеИсточникТипОбязательностьВалидация / ОграниченияБезопасность
TenantIdidentity claims (tenant_id)GuidДаRequiredTenant isolation
BuildingIdrouteGuidДасуществующее здание tenant-а404 при чужом

Модель ответа DeveloperBuildingDetail

ПолеТипОбязательностьИсточникMaskingОписание
IdGuidДаBuildingEntity.IdId здания.
ProjectIdGuidДаProjectIdПроект-родитель.
StatusBuildingStatusДаStatusDraft/Published/Hidden.
NamestringДаNameНазвание литера.
Codestring?НетCodeТехнический код (реплика-поле).
FloorsTotalshortДаFloorsTotalЭтажность.
SectionsCountshort?НетSectionsCountСекции.
DeliveryYearshort?НетDeliveryYearГод сдачи.
DeliveryQuartershort?НетDeliveryQuarterКвартал сдачи.
DeliveredAtDateOnly?НетDeliveredAtФактический ввод в эксплуатацию.
ConstructionStatusConstructionStatusДаConstructionStatusСтатус строительства здания.
ReadinessPercentdecimalДаReadinessPercentГотовность.
CeilingHeightMetersdecimal?НетCeilingHeightMetersТиповая высота потолков.
PropertyObjectsTotalCountintДаPropertyObjectsTotalCountДенормализация.
PropertyObjectsFreeCountintДаPropertyObjectsFreeCountДенормализация.
SyncSourceChessboardSyncSourceДаSyncSourcePin/TalentChessboard.
SyncManagedFieldsstring[]ДавычисляетсяПри TalentChessboard (INV-BLD-7): Name,Code,FloorsTotal,SectionsCount,DeliveryYear,DeliveryQuarter,ConstructionStatus,ReadinessPercent; иначе пусто.
LastSyncedAtDateTimeOffset?НетLastSyncedAtПоследний синк.
CreatedAtDateTimeOffsetДаCreatedAtСоздано.
UpdatedAtDateTimeOffsetДаUpdatedAtИзменено.
VersionlongДаVersionДля optimistic PUT.

Предусловия

  • Пользователь авторизован (валидный JWT identity); tenant_id = его компания-застройщик.
  • У актора есть permission chessboard.buildings.manage хотя бы в одном scope компании (иначе — FORBIDDEN до чтения).
  • Запрашиваемое здание существует в БД и принадлежит tenant-у актора; иначе неотличимо от отсутствия (404).
  • Денормализованные счётчики (PropertyObjectsTotalCount/PropertyObjectsFreeCount) отражают последний фоновый пересчёт; при незавершённом пересчёте — читаются устаревшие (eventual consistency, ниже).

Алгоритм

Чтение по идентификатору с разграничением доступа. Отдельного изменения состояния нет — операция read-only, доменных событий не публикует.

  1. Контекст и доступ. Актор — менеджер застройщика; TenantId из claims. Требуется permission chessboard.buildings.manage; если его нет ни в одном scope — FORBIDDEN (403). Право проверяется до чтения; отозванное/просроченное к моменту запроса право (revoked mid-session) даёт UNAUTHORIZED (401, истёкший JWT) либо FORBIDDEN (403, снятый permission).
  2. Выборка и разграничение. Здание ищется по BuildingId среди не удалённых записей tenant-а актора:
    • записи нет, DeletedAt != null (soft-deleted) или здание чужого tenant-а → CHESSBOARD_BUILDING_NOT_FOUND (404, единый код — существование чужой/удалённой записи не раскрывается);
    • актор с суженным scope «группа проектов/проект»: building.ProjectId вне разрешённого набора — здание считается недостижимым и отдаётся тем же CHESSBOARD_BUILDING_NOT_FOUND (404), не 403 (не раскрываем, что здание существует за пределами scope; ср. фильтрацию выдачи в search-buildings.md). FORBIDDEN (403) — только когда у актора нет самого permission chessboard.buildings.manage.
  3. Формирование ответа. Допустим любой статус здания (Draft/Published/Hidden) — карточка редактирования показывает корпус на любой стадии. Все поля берутся из здания; SyncManagedFields вычисляется по SyncSource (INV-BLD-7): при TalentChessboard — фиксированный список реплика-полей (UI дизейблит их для правки), при Pin — пустой список. Маскирование не требуется (свой tenant, PII нет).
Freshness

Read-committed снимок. Реплика-поля (Name/Code/FloorsTotal/SectionsCount/Delivery*/ ConstructionStatus/ReadinessPercent) отражают последний применённый синк Talent (LastSyncedAt); между приходом события синка и его применением может наблюдаться устаревшее значение. Счётчики объектов недвижимости могут отставать до фонового пересчёта агрегатов (окно ~40 с, project-aggregates-recalc).

Acceptance Criteria

  • Happy path. Given здание tenant-а актора в scope; When GET .../buildings/{buildingId}; Then 200 с полной карточкой, Version пригоден для последующего optimistic PUT, SyncManagedFields соответствует SyncSource.
  • Любой статус. Given здание в статусе Draft (или Hidden); When чтение; Then 200 (статус не ограничивает чтение в кабинете).
  • Чужой/удалённый. Given buildingId другого tenant-а или soft-deleted; When чтение; Then 404 CHESSBOARD_BUILDING_NOT_FOUND без раскрытия существования.
  • Вне scope. Given у актора scope сужен до другой группы проектов; When чтение здания вне scope; Then 404 CHESSBOARD_BUILDING_NOT_FOUND (не 403).
  • Нет права. Given у актора нет chessboard.buildings.manage; When чтение; Then 403 FORBIDDEN.
  • Sync-managed поля. Given SyncSource = TalentChessboard; When чтение; Then SyncManagedFields содержит реплика-поля (INV-BLD-7), UI блокирует их редактирование.
  • Отставание денормализации. Given только что изменился объект недвижимости, фоновый пересчёт агрегатов не завершён; When чтение карточки; Then 200 с прежними PropertyObjectsTotalCount/ PropertyObjectsFreeCount (eventual consistency, не ошибка).

Ошибки и failure modes

КодHTTP statusУсловиеСообщениеRetry
CHESSBOARD_BUILDING_NOT_FOUND404Нет здания / чужой tenant / soft-deleted / ProjectId вне scope-набора«Здание не найдено»no retry
FORBIDDEN403Нет permission chessboard.buildings.manage ни в одном scope«Недостаточно прав»no retry

Сквозные ошибки области (UNAUTHORIZED 401 — нет/просрочен JWT; ValidationError 400 — BuildingId == Guid.Empty) — по реестру README.md, здесь не повторяются.

Совместимость и наблюдаемость

  • Новые optional поля ответа — additive; изменение состава/семантики SyncManagedFields — согласуется с инвариантом INV-BLD-7 (building.md); enum-строки (BuildingStatus, ConstructionStatus, ChessboardSyncSource) — клиентский fallback на unknown обязателен.
  • Logs: TenantId, BuildingId, Status, SyncSource (без PII); metrics: chessboard_developers_building_get_total, latency histogram (SLO p99 < 300 мс); traces: OTel (traceparent). Dashboard chessboard-overview. Read-only — runbook не требуется (деградация = 404 при недостижимом здании).

Обратные ссылки

Автоссылки: где используется этот документ.

Связанные документы