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

GET /api/v1/public/property-objects/{propertyObjectId} — Карточка объекта/объекта недвижимости (ограниченная/полная)

Назначение

Карточка объекта недвижимости: паспортные данные, планировка со схемами, цена, статус продажи с таймерами. Ограниченная карточка (для анонима) — описание, срок сдачи, площади, этаж, застройщик; полная (для авторизованного) — дополнительно цена и статус свободно/забронировано. Ограниченная проекция скрывает точную цену, цену за м², статус продажи и таймеры. Инвестиционная аналитика/история цен — не этот метод, а invest-analytics. Зеркалируется в agents area (GET /api/v1/agents/property-objects/{propertyObjectId}) той же операцией с обязательной авторизацией.

Metadata

ПолеЗначение
Сервис/контекстchessboard
API areapublic (зеркало: agents)
Feature grouppropertyObjects
Статусdraft
OwnerPIN Platform Core
Документdocs/06-services/chessboard/api/public/property-objects/get-property-object.md

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

ПроверкаЗначение
Actor typeAnonymous (ограниченная проекция) / User — инвестор, агент, менеджер застройщика (полная)
Auth policy / Permissionsnone — public endpoint; masking по признаку авторизации
Scope (RBAC)не применяется
Record-levelне применяется
Tenant isolationBypass tenant-фильтра: отдаются только объекты недвижимости Status != Hidden published-зданий published-проектов published-застройщиков
Auditnone (read; просмотр объекта недвижимости трекает user-activity — PropertyObjectView, ADR-0056)

HTTP-контракт

ПолеЗначение
MethodGET
Route/api/v1/public/property-objects/{propertyObjectId}
Success status200
Idempotency headerне применяется (GET)
Correlationсквозной trace через заголовок traceparent

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

ПолеИсточникТипОбязательностьВалидация / ОграниченияБезопасность
PropertyObjectIdrouteGuidДаRequired, != Guid.Empty
IsAuthenticatedidentity claimsboolДа (вычисляется)из контекста авторизацииопределяет masking

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

Проекция PropertyObjectEntity + summary родителей и планировки. Masking-колонка — правило для анонима (авторизованный получает значение всегда).

ПолеТипОбязательностьИсточникMasking (аноним)Описание
IdGuidДаPropertyObject.IdИдентификатор объекта недвижимости.
NumberstringДаPropertyObject.NumberНомер объекта («квартира 145»).
FloorshortДаPropertyObject.FloorЭтаж (ограниченная карточка).
Sectionshort?НетPropertyObject.SectionСекция/подъезд.
RoomsshortДаPropertyObject.RoomsКомнатность; 0 = студия.
TotalAreadecimalДаPropertyObject.TotalAreaОбщая площадь, м².
LivingAreadecimal?НетPropertyObject.LivingAreaЖилая площадь, м².
CeilingHeightMetersdecimal?Нетвычисляется: PropertyObject.CeilingHeightMeters ?? Building.CeilingHeightMetersВысота потолков (fallback на типовую здания — правило дома property-object.md).
Pricedecimal?НетPropertyObject.Pricenull (точные цены скрыты)Текущая цена.
CurrencyIdshortДаPropertyObject.CurrencyIdСсылка на валюту справочника (RUB-only, ADR-0048); display-код/знак — публичный lookup handbook.
PricePerMeterdecimal?НетPropertyObject.PricePerMeternullЦена за м².
StatusPropertyObjectStatus (string)?НетPropertyObject.Statusnull (статусы скрыты от анонима)Free/Reserved/Booked/Sold (объект недвижимости Hidden публично не отдаётся — 404).
ReservedUntilDateTimeOffset?НетPropertyObject.ReservedUntilnullТаймер резерва (обратный отсчёт в карточке).
BookedUntilDateTimeOffset?НетPropertyObject.BookedUntilnullТаймер брони.
WindowViewsIReadOnlyList<WindowViewKind> (string)Да (может быть пустым)PropertyObject.WindowViews.ViewsВиды из окон (reference-data.md).
PanoramaUrlstring?НетPropertyObject.WindowViews.PanoramaUrl3D-тур/панорама.
Capacityshort?НетPropertyObject.CapacityВместимость (гостей) — апарт-отели.
Descriptionstring?НетPropertyObject.DescriptionПубличное описание.
LayoutLayoutSummaryModel?Нетзагруженный LayoutEntityПланировка со схемами (ниже).
BuildingPropertyObjectBuildingSummaryModelДазагруженный BuildingEntityЗдание: срок сдачи для ограниченной карточки (ниже).
ProjectPropertyObjectProjectSummaryModelДазагруженный ProjectEntityПроект (ниже).
DeveloperPropertyObjectDeveloperSummaryModelДазагруженный DeveloperEntityЗастройщик (ограниченная карточка).
IsLimitedboolДавычисляется: !IsAuthenticatedОтдана ограниченная проекция; фронт показывает «войдите, чтобы увидеть цену и статус».
StatusChangedAtDateTimeOffset?НетPropertyObject.StatusChangedAtnullМомент последнего перехода статуса.
VersionlongДаPropertyObject.VersionВерсия агрегата.

Вложенная модель LayoutSummaryModel (проекция layout.md)

ПолеТипОбязательностьИсточникMaskingОписание
IdGuidДаLayout.IdИдентификатор планировки.
NamestringДаLayout.Name«1К-А 32.5».
RoomsshortДаLayout.RoomsТиповая комнатность.
TotalAreadecimalДаLayout.TotalAreaТиповая общая площадь.
LivingAreadecimal?НетLayout.LivingAreaТиповая жилая площадь.
LayoutGroupIdGuid?НетLayout.LayoutGroupIdГруппа планировок.
SchemasIReadOnlyList<LayoutSchemaItemModel>Да (может быть пустым)Layout.Schemas.Items (сорт. SortOrder)Схемы планировки.

Вложенная модель LayoutSchemaItemModel (дельта LayoutSchemaModel из layout.md)

ПолеТипОбязательностьИсточникMaskingОписание
FileIdGuidДаLayoutSchemaModel.FileIdФайл схемы (пресайн — storage/CDN).
KindLayoutSchemaKind (string)ДаLayoutSchemaModel.KindPlan2D/Plan3D/FloorPosition/Visualization.
Titlestring?НетLayoutSchemaModel.TitleПодпись.
SortOrderintДаLayoutSchemaModel.SortOrderПорядок.

Вложенная модель PropertyObjectBuildingSummaryModel (проекция building.md)

ПолеТипОбязательностьИсточникMaskingОписание
IdGuidДаBuilding.IdИдентификатор здания.
NamestringДаBuilding.Name«Литер 3».
FloorsTotalshortДаBuilding.FloorsTotalЭтажность (отображение «этаж 5 из 24»).
DeliveryYearshort?НетBuilding.DeliveryYearСрок сдачи (ограниченная карточка).
DeliveryQuartershort?НетBuilding.DeliveryQuarterКвартал сдачи.
ConstructionStatusConstructionStatus (string)ДаBuilding.ConstructionStatusСтатус строительства.
ReadinessPercentdecimalДаBuilding.ReadinessPercentГотовность.

Вложенная модель PropertyObjectProjectSummaryModel (проекция project.md)

ПолеТипОбязательностьИсточникMaskingОписание
IdGuidДаProject.IdИдентификатор проекта.
NamestringДаProject.NameНазвание ЖК/отеля.
TypeProjectType (string)ДаProject.TypeТип.
RegionIdlongДаProject.RegionIdСсылка на регион справочника (у Published-проекта резолвлена, INV-PRJ-3).
RegionNamestringДаProject.RegionName (денормализация)Display-имя региона.
CityIdlongДаProject.CityIdСсылка на город справочника (INV-PRJ-3).
CityNamestringДаProject.CityName (денормализация)Display-имя города.
AddressLinestring?НетProject.Location.AddressLineАдрес.

Вложенная модель PropertyObjectDeveloperSummaryModel (проекция developer.md)

ПолеТипОбязательностьИсточникMaskingОписание
IdGuidДаDeveloper.Id= CompanyId identity.
NamestringДаDeveloper.NameНазвание застройщика.
LogoFileIdGuid?НетDeveloper.LogoFileIdЛого.

Предусловия и постусловия

Предусловия:

  • Вызов анонимом (ограниченная проекция) или авторизованным пользователем (полная); признак авторизации определяет masking.
  • Объект видим только по публичному срезу: PropertyObject.Status != Hidden, здание/проект/застройщик Published (INV-DEV-6). Иначе — единый 404 (без утечки существования Hidden-объектов).

Постусловия (read — состояние не меняется):

  • Возвращена карточка с summary планировки, здания, проекта, застройщика. Для анонима: Price, PricePerMeter, Status, ReservedUntil, BookedUntil, StatusChangedAt = null, IsLimited = true; для авторизованного значения отдаются как есть.
  • CeilingHeightMeters = значение объекта либо fallback на типовую высоту здания (правило дома property-object.md).
  • Freshness: прямое чтение source of truth; трекинг просмотра объекта пишет user-activity (PropertyObjectView, ADR-0056), не этот метод.

Алгоритм

Чтение карточки объекта по публичному срезу с проверкой публичности родителей и masking цены/статуса/таймеров для анонима.

  1. Контекст и доступ. Вызывает аноним (ограниченная проекция) или авторизованный пользователь (полная); признак авторизации определяет masking. Чтение — только по публичному срезу.
  2. Проверка входа. PropertyObjectId задан; иначе — VALIDATION_ERROR. Существование и публичность — шаг 3 (единый 404 без утечки существования Hidden-объектов).
  3. Что читаем (объект → родители для проверок публичности → планировка):
    • Объект по id, Status != Hidden, не удалён; не найден → CHESSBOARD_PROPERTY_OBJECT_NOT_FOUND.
    • Здание объекта; если не Published или удалено — скрытое здание скрывает объекты в public-проекциях → CHESSBOARD_PROPERTY_OBJECT_NOT_FOUND.
    • Проект объекта; если не Published или удалён → CHESSBOARD_PROPERTY_OBJECT_NOT_FOUND.
    • Застройщик проекта; если не Published (INV-DEV-6 HiddenCascades) → CHESSBOARD_PROPERTY_OBJECT_NOT_FOUND.
    • Планировка объекта (если задана); архивная планировка при живом объекте невозможна (INV-LAY-5).
  4. Сборка ответа и masking. Поля — по таблицам моделей; вычисления: CeilingHeightMeters — значение объекта либо fallback на типовую высоту здания; схемы планировки — по порядку SortOrder. При анониме: Price = null, PricePerMeter = null, Status = null, ReservedUntil = null, BookedUntil = null, StatusChangedAt = null, IsLimited = true; для авторизованного значения отдаются как есть, IsLimited = false.
  5. Результат. Карточка объекта, статус 200; не найдено/непублично → 404; нарушение проверки входа → 400. Трекинг просмотра объекта — user-activity (отдельный вызов клиента), не этот метод.

Диаграмма

Ошибки и failure modes

КодHTTP statusУсловиеСообщениеRetry
VALIDATION_ERROR400PropertyObjectId == Guid.Empty«Некорректный идентификатор объекта»no retry
CHESSBOARD_PROPERTY_OBJECT_NOT_FOUND404Объект недвижимости не существует / Hidden / удалён / здание, проект или застройщик не публичны«Объект не найден» (единый код — без утечки причины)no retry
INTERNAL_ERROR500Инфраструктурный сбойgenericretry (backoff)

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

  • Optional-поля — additive; раскрытие masked-полей анониму — breaking (решение продукта + новая версия).
  • Enum-строки (PropertyObjectStatus, WindowViewKind, LayoutSchemaKind) — клиентский fallback на unknown обязателен.
  • Logs: propertyObjectId, actor type, latency; без PII. Metrics: chessboard_public_property_object_requests_total{authenticated}, latency histogram (SLO p99 < 300 мс). Traces: OTel span chessboard.get-public-property-object.
  • Dashboard/runbook — chessboard-overview (README).

Acceptance Criteria

  • AC1 (полная карточка). Дано: авторизованный, published-объект и публичные родители. Когда: GET. Тогда: 200, Price/Status/таймеры отданы по данным, IsLimited = false.
  • AC2 (masking для анонима). Дано: тот же объект, вызывает аноним. Когда: GET. Тогда: 200, Price, PricePerMeter, Status, ReservedUntil, BookedUntil, StatusChangedAt = null, IsLimited = true.
  • AC3 (скрытый объект). Дано: PropertyObject.Status = Hidden. Когда: GET. Тогда: CHESSBOARD_PROPERTY_OBJECT_NOT_FOUND (404), неотличимо от отсутствия.
  • AC4 (непубличный родитель). Дано: здание, проект или застройщик не Published. Когда: GET. Тогда: CHESSBOARD_PROPERTY_OBJECT_NOT_FOUND (404).
  • AC5 (fallback высоты потолков). Дано: у объекта нет CeilingHeightMeters, у здания задана типовая. Когда: GET. Тогда: поле в ответе = типовая высота здания.
  • AC6 (валидация). Дано: PropertyObjectId = Guid.Empty. Когда: GET. Тогда: VALIDATION_ERROR (400).

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

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

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