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

GET /api/v1/developers/property-objects/{propertyObjectId} — Карточка объекта недвижимости (кабинет застройщика)

Назначение

Экран карточки/редактирования объекта недвижимости в кабинете застройщика. Возвращает полное состояние объекта своего tenant-а без маскирования — в отличие от публичной карточки public/property-objects/get-property-object.md, скрывающей цену/статус от анонима, и от списка объектов. Дом полей — сущность Объект недвижимости.

Metadata

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

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

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

HTTP-контракт

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

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

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

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

Все поля — проекция PropertyObjectEntity (дом полей), без дельты типов; масштаб — свой tenant (видны и Hidden, и цена/статус/таймеры/HoldDealId), маскирование не применяется.

ПолеТипОбязательностьИсточникОписание
IdGuidДаPropertyObject.IdИдентификатор объекта недвижимости.
TenantIdGuidДаPropertyObject.TenantIdЗастройщик (= DeveloperId, ADR-0052).
ProjectIdGuidДаPropertyObject.ProjectIdПроект (денормализация).
BuildingIdGuidДаPropertyObject.BuildingIdЗдание (литер/корпус).
LayoutIdGuid?НетPropertyObject.LayoutIdПланировка (layout.md); null — не привязана.
StatusPropertyObjectStatus (string)ДаPropertyObject.StatusFree/Reserved/Booked/Sold/Hidden (reference-data.md).
StatusSourcePropertyObjectStatusSource (string)ДаPropertyObject.StatusSourceКто выполнил переход: Crm/TalentSync/DeveloperApi/ExpirationJob.
StatusChangedAtDateTimeOffsetДаPropertyObject.StatusChangedAtМомент последнего перехода Status.
ReservedUntilDateTimeOffset?НетPropertyObject.ReservedUntilТаймер резерва (⇔ Reserved, INV-CHS-002).
BookedUntilDateTimeOffset?НетPropertyObject.BookedUntilТаймер брони (⇔ Booked).
HoldDealIdGuid?НетPropertyObject.HoldDealIdId сделки CRM, удерживающей объект недвижимости (⇔ Reserved/Booked).
SoldAtDateTimeOffset?НетPropertyObject.SoldAtМомент продажи (⇔ Sold).
NumberstringДаPropertyObject.NumberНомер объекта («квартира 145»); уникален в здании.
FloorshortДаPropertyObject.FloorЭтаж (ось Y шахматки).
Sectionshort?НетPropertyObject.SectionСекция/подъезд (ось X).
RoomsshortДаPropertyObject.RoomsКомнатность; 0 = студия.
TotalAreadecimalДаPropertyObject.TotalAreaОбщая площадь, м².
LivingAreadecimal?НетPropertyObject.LivingAreaЖилая площадь, м².
CeilingHeightMetersdecimal?НетPropertyObject.CeilingHeightMetersВысота потолков (null → берётся у здания).
PricedecimalДаPropertyObject.PriceТекущая цена (без masking — свой tenant).
CurrencyIdshortДаPropertyObject.CurrencyIdВалюта — ссылка на справочник handbook (= Project.CurrencyId, INV-PRJ-6; RUB-only, ADR-0048).
PricePerMeterdecimalДаPropertyObject.PricePerMeterЦена за м² (вычисляемая денормализация).
WindowViewsPropertyObjectWindowViewsDocumentДаPropertyObject.WindowViewsВиды из окон + панорама (typed, ContractVersion = 1; property-object.md).
Capacityshort?НетPropertyObject.CapacityВместимость (гостей) — апарт-отели.
Descriptionstring?НетPropertyObject.DescriptionПубличное описание (PIN-поле).
SyncSourceChessboardSyncSource (string)ДаPropertyObject.SyncSourcePin/TalentChessboard.
SyncManagedFieldsIReadOnlyList<string>Да (может быть пустым)вычисляетсяИмена реплика-полей, закрытых для правки при SyncSource = TalentChessboard: Number,Floor,Section,Rooms,TotalArea,LivingArea,WindowViews,LayoutId; при Pin — пустой список. UI дизейблит поля.
ExternalTalentPropertyObjectIdGuid?НетPropertyObject.ExternalTalentPropertyObjectIdId объекта в Talent Chessboard.
LastSyncedAtDateTimeOffset?НетPropertyObject.LastSyncedAtПоследний применённый синк Talent.
CreatedAtDateTimeOffsetДаPropertyObject.CreatedAtСоздан.
UpdatedAtDateTimeOffsetДаPropertyObject.UpdatedAtИзменён.
VersionlongДаPropertyObject.VersionВерсия агрегата (для optimistic PUT, update-property-object.md).

Предусловия

  • Пользователь авторизован; tenant_id = его компания-застройщик (= DeveloperId).
  • У актора есть permission chessboard.property-objects.manage хотя бы в одном scope (иначе FORBIDDEN).
  • Объект недвижимости существует, принадлежит tenant-у актора и не soft-deleted; иначе неотличим от отсутствия (404).
  • Status/таймеры/HoldDealId отражают последнее применённое событие CRM; в момент запроса они могут на несколько секунд опережать/отставать от реального применения release-события (eventual consistency, ниже).

Алгоритм

Чтение полного паспорта объекта недвижимости по идентификатору (кабинет застройщика — без маскирования). Операция read-only, доменных событий не публикует.

  1. Контекст и доступ. Актор — менеджер застройщика; TenantId = DeveloperId из claims. Требуется permission chessboard.property-objects.manage; нет ни в одном scope → FORBIDDEN (403). Просроченный/ отозванный доступ → UNAUTHORIZED (401) / FORBIDDEN (403).
  2. Выборка и разграничение. Объект ищется по PropertyObjectId среди не удалённых записей tenant-а актора:
    • записи нет, DeletedAt != null или объект чужого tenant-а → CHESSBOARD_PROPERTY_OBJECT_NOT_FOUND (404, единый код без утечки существования);
    • актор с суженным scope «группа проектов/проект»: propertyObject.ProjectId вне разрешённого набора — объект недостижим и отдаётся тем же CHESSBOARD_PROPERTY_OBJECT_NOT_FOUND (404), не 403 (симметрично фильтрации выдачи в search-property-objects.md); FORBIDDEN (403) — только при полном отсутствии permission.
  3. Формирование ответа. Допустим любой статус, включая Hidden и Sold (карточка застройщика показывает весь паспорт: цену/статус/таймеры/HoldDealId). Все поля берутся из объекта; SyncManagedFields вычисляется по SyncSource (реплика-поля при TalentChessboard, пусто при Pin); маскирование не применяется (свой tenant).
Freshness

Read-committed снимок. Таймеры ReservedUntil/BookedUntil могут на несколько секунд опережать применение release-события CRM (истёкший таймер при ещё Reserved/Booked — норма до страховочного job property-object-hold-expiration, grace 10 мин); статус/таймеры/HoldDealId отражают последнее применённое CRM-событие (INV-CHS-002: таймер заполнен ⇔ соответствующий статус).

Acceptance Criteria

  • Happy path. Given объект tenant-а актора в scope; When GET .../property-objects/{propertyObjectId}; Then 200 с полным паспортом, Version пригоден для optimistic PUT.
  • Скрытый/проданный виден. Given объект в Hidden (или Sold); When чтение; Then 200 со всеми полями (в отличие от публичной карточки).
  • Занятый объект. Given объект в Reserved с ReservedUntil/HoldDealId; When чтение; Then 200, таймер и HoldDealId заполнены (INV-CHS-002).
  • Чужой/удалённый. Given propertyObjectId чужого tenant-а или soft-deleted; When чтение; Then 404 CHESSBOARD_PROPERTY_OBJECT_NOT_FOUND.
  • Вне scope. Given scope сужен; When чтение объекта вне scope; Then 404 (не 403).
  • Нет права. Given нет chessboard.property-objects.manage; When чтение; Then 403 FORBIDDEN.

Ошибки и failure modes

КодHTTP statusУсловиеСообщениеRetry
CHESSBOARD_PROPERTY_OBJECT_NOT_FOUND404Объект недвижимости не существует / чужой tenant / удалён / вне scope-набора«Объект не найден» (единый код — без утечки существования чужого)no retry
FORBIDDEN403Нет chessboard.property-objects.manage в scope«Недостаточно прав»no retry

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

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

  • Новые optional-поля ответа — additive; изменение PropertyObjectWindowViewsDocument — по правилам ContractVersion (property-object.md); enum-строки (PropertyObjectStatus, PropertyObjectStatusSource, ChessboardSyncSource, WindowViewKind) — клиентский fallback на unknown обязателен.
  • Logs: TenantId, PropertyObjectId (без PII); metrics: chessboard_developers_property_object_get_total, latency histogram (SLO p99 < 300 мс); traces: OTel (traceparent). Dashboard — chessboard-overview.

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

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

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