GET /api/v1/public/property-objects/{propertyObjectId} — Карточка объекта/объекта недвижимости (ограниченная/полная)
Назначение
Карточка объекта недвижимости: паспортные данные, планировка со схемами, цена, статус продажи с таймерами.
Ограниченная карточка (для анонима) — описание, срок сдачи, площади, этаж, застройщик; полная (для
авторизованного) — дополнительно цена и статус свободно/забронировано. Ограниченная проекция скрывает
точную цену, цену за м², статус продажи и таймеры. Инвестиционная аналитика/история цен — не этот метод, а
invest-analytics. Зеркалируется в agents area
(GET /api/v1/agents/property-objects/{propertyObjectId}) той же операцией с обязательной авторизацией.
Metadata
| Поле | Значение |
|---|---|
| Сервис/контекст | chessboard |
| API area | public (зеркало: agents) |
| Feature group | propertyObjects |
| Статус | draft |
| Owner | PIN Platform Core |
| Документ | docs/06-services/chessboard/api/public/property-objects/get-property-object.md |
Актор и доступ
| Проверка | Значение |
|---|---|
| Actor type | Anonymous (ограниченная проекция) / User — инвестор, агент, менеджер застройщика (полная) |
| Auth policy / Permissions | none — public endpoint; masking по признаку авторизации |
| Scope (RBAC) | не применяется |
| Record-level | не применяется |
| Tenant isolation | Bypass tenant-фильтра: отдаются только объекты недвижимости Status != Hidden published-зданий published-проектов published-застройщиков |
| Audit | none (read; просмотр объекта недвижимости трекает user-activity — PropertyObjectView, ADR-0056) |
HTTP-контракт
| Поле | Значение |
|---|---|
| Method | GET |
| Route | /api/v1/public/property-objects/{propertyObjectId} |
| Success status | 200 |
| Idempotency header | не применяется (GET) |
| Correlation | сквозной trace через заголовок traceparent |
Входные данные / параметры запроса
| Поле | Источник | Тип | Обязательность | Валидация / Ограничения | Безопасность |
|---|---|---|---|---|---|
PropertyObjectId | route | Guid | Да | Required, != Guid.Empty | — |
IsAuthenticated | identity claims | bool | Да (вычисляется) | из контекста авторизации | определяет masking |
Модель ответа PropertyObjectCardResponse
Проекция PropertyObjectEntity + summary родителей и планировки. Masking-колонка —
правило для анонима (авторизованный получает значение всегда).
| Поле | Тип | Обязательность | Источник | Masking (аноним) | Описание |
|---|---|---|---|---|---|
Id | Guid | Да | PropertyObject.Id | — | Идентификатор объекта недвижимости. |
Number | string | Да | PropertyObject.Number | — | Номер объекта («квартира 145»). |
Floor | short | Да | PropertyObject.Floor | — | Этаж (ограниченная карточка). |
Section | short? | Нет | PropertyObject.Section | — | Секция/подъезд. |
Rooms | short | Да | PropertyObject.Rooms | — | Комнатность; 0 = студия. |
TotalArea | decimal | Да | PropertyObject.TotalArea | — | Общая площадь, м². |
LivingArea | decimal? | Нет | PropertyObject.LivingArea | — | Жилая площадь, м². |
CeilingHeightMeters | decimal? | Нет | вычисляется: PropertyObject.CeilingHeightMeters ?? Building.CeilingHeightMeters | — | Высота потолков (fallback на типовую здания — правило дома property-object.md). |
Price | decimal? | Нет | PropertyObject.Price | null (точные цены скрыты) | Текущая цена. |
CurrencyId | short | Да | PropertyObject.CurrencyId | — | Ссылка на валюту справочника (RUB-only, ADR-0048); display-код/знак — публичный lookup handbook. |
PricePerMeter | decimal? | Нет | PropertyObject.PricePerMeter | null | Цена за м². |
Status | PropertyObjectStatus (string)? | Нет | PropertyObject.Status | null (статусы скрыты от анонима) | Free/Reserved/Booked/Sold (объект недвижимости Hidden публично не отдаётся — 404). |
ReservedUntil | DateTimeOffset? | Нет | PropertyObject.ReservedUntil | null | Таймер резерва (обратный отсчёт в карточке). |
BookedUntil | DateTimeOffset? | Нет | PropertyObject.BookedUntil | null | Таймер брони. |
WindowViews | IReadOnlyList<WindowViewKind> (string) | Да (может быть пустым) | PropertyObject.WindowViews.Views | — | Виды из окон (reference-data.md). |
PanoramaUrl | string? | Нет | PropertyObject.WindowViews.PanoramaUrl | — | 3D-тур/панорама. |
Capacity | short? | Нет | PropertyObject.Capacity | — | Вместимость (гостей) — апарт-отели. |
Description | string? | Нет | PropertyObject.Description | — | Публичное описание. |
Layout | LayoutSummaryModel? | Нет | загруженный LayoutEntity | — | Планировка со схемами (ниже). |
Building | PropertyObjectBuildingSummaryModel | Да | загруженный BuildingEntity | — | Здание: срок сдачи для ограниченной карточки (ниже). |
Project | PropertyObjectProjectSummaryModel | Да | загруженный ProjectEntity | — | Проект (ниже). |
Developer | PropertyObjectDeveloperSummaryModel | Да | загруженный DeveloperEntity | — | Застройщик (ограниченная карточка). |
IsLimited | bool | Да | вычисляется: !IsAuthenticated | — | Отдана ограниченная проекция; фронт показывает «войдите, чтобы увидеть цену и статус». |
StatusChangedAt | DateTimeOffset? | Нет | PropertyObject.StatusChangedAt | null | Момент последнего перехода статуса. |
Version | long | Да | PropertyObject.Version | — | Версия агрегата. |
Вложенная модель LayoutSummaryModel (проекция layout.md)
| Поле | Тип | Обязательность | Источник | Masking | Описание |
|---|---|---|---|---|---|
Id | Guid | Да | Layout.Id | — | Идентификатор планировки. |
Name | string | Да | Layout.Name | — | «1К-А 32.5». |
Rooms | short | Да | Layout.Rooms | — | Типовая комнатность. |
TotalArea | decimal | Да | Layout.TotalArea | — | Типовая общая площадь. |
LivingArea | decimal? | Нет | Layout.LivingArea | — | Типовая жилая площадь. |
LayoutGroupId | Guid? | Нет | Layout.LayoutGroupId | — | Группа планировок. |
Schemas | IReadOnlyList<LayoutSchemaItemModel> | Да (может быть пустым) | Layout.Schemas.Items (сорт. SortOrder) | — | Схемы планировки. |
Вложенная модель LayoutSchemaItemModel (дельта LayoutSchemaModel из layout.md)
| Поле | Тип | Обязательность | Источник | Masking | Описание |
|---|---|---|---|---|---|
FileId | Guid | Да | LayoutSchemaModel.FileId | — | Файл схемы (пресайн — storage/CDN). |
Kind | LayoutSchemaKind (string) | Да | LayoutSchemaModel.Kind | — | Plan2D/Plan3D/FloorPosition/Visualization. |
Title | string? | Нет | LayoutSchemaModel.Title | — | Подпись. |
SortOrder | int | Да | LayoutSchemaModel.SortOrder | — | Порядок. |
Вложенная модель PropertyObjectBuildingSummaryModel (проекция building.md)
| Поле | Тип | Обязательность | Источник | Masking | Описание |
|---|---|---|---|---|---|
Id | Guid | Да | Building.Id | — | Идентификатор здания. |
Name | string | Да | Building.Name | — | «Литер 3». |
FloorsTotal | short | Да | Building.FloorsTotal | — | Этажность (отображение «этаж 5 из 24»). |
DeliveryYear | short? | Нет | Building.DeliveryYear | — | Срок сдачи (ограниченная карточка). |
DeliveryQuarter | short? | Нет | Building.DeliveryQuarter | — | Квартал сдачи. |
ConstructionStatus | ConstructionStatus (string) | Да | Building.ConstructionStatus | — | Статус строительства. |
ReadinessPercent | decimal | Да | Building.ReadinessPercent | — | Готовность. |
Вложенная модель PropertyObjectProjectSummaryModel (проекция project.md)
| Поле | Тип | Обязательность | Источник | Masking | Описание |
|---|---|---|---|---|---|
Id | Guid | Да | Project.Id | — | Идентификатор проекта. |
Name | string | Да | Project.Name | — | Название ЖК/отеля. |
Type | ProjectType (string) | Да | Project.Type | — | Тип. |
RegionId | long | Да | Project.RegionId | — | Ссылка на регион справочника (у Published-проекта резолвлена, INV-PRJ-3). |
RegionName | string | Да | Project.RegionName (денормализация) | — | Display-имя региона. |
CityId | long | Да | Project.CityId | — | Ссылка на город справочника (INV-PRJ-3). |
CityName | string | Да | Project.CityName (денормализация) | — | Display-имя города. |
AddressLine | string? | Нет | Project.Location.AddressLine | — | Адрес. |
Вложенная модель PropertyObjectDeveloperSummaryModel (проекция developer.md)
| Поле | Тип | Обязательность | Источник | Masking | Описание |
|---|---|---|---|---|---|
Id | Guid | Да | Developer.Id | — | = CompanyId identity. |
Name | string | Да | Developer.Name | — | Название застройщика. |
LogoFileId | Guid? | Нет | 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 цены/статуса/таймеров для анонима.
- Контекст и доступ. Вызывает аноним (ограниченная проекция) или авторизованный пользователь (полная); признак авторизации определяет masking. Чтение — только по публичному срезу.
- Проверка входа.
PropertyObjectIdзадан; иначе —VALIDATION_ERROR. Существование и публичность — шаг 3 (единый404без утечки существованияHidden-объектов). - Что читаем (объект → родители для проверок публичности → планировка):
- Объект по 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).
- Объект по id,
- Сборка ответа и masking. Поля — по таблицам моделей; вычисления:
CeilingHeightMeters— значение объекта либо fallback на типовую высоту здания; схемы планировки — по порядкуSortOrder. При анониме:Price = null,PricePerMeter = null,Status = null,ReservedUntil = null,BookedUntil = null,StatusChangedAt = null,IsLimited = true; для авторизованного значения отдаются как есть,IsLimited = false. - Результат. Карточка объекта, статус
200; не найдено/непублично →404; нарушение проверки входа →400. Трекинг просмотра объекта —user-activity(отдельный вызов клиента), не этот метод.
Диаграмма
Ошибки и failure modes
| Код | HTTP status | Условие | Сообщение | Retry |
|---|---|---|---|---|
VALIDATION_ERROR | 400 | PropertyObjectId == Guid.Empty | «Некорректный идентификатор объекта» | no retry |
CHESSBOARD_PROPERTY_OBJECT_NOT_FOUND | 404 | Объект недвижимости не существует / Hidden / удалён / здание, проект или застройщик не публичны | «Объект не найден» (единый код — без утечки причины) | no retry |
INTERNAL_ERROR | 500 | Инфраструктурный сбой | generic | retry (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 spanchessboard.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).
Обратные ссылки
Автоссылки: где используется этот документ.
- API (4): GET /api/v1/developers/property-objects/{propertyObjectId} — Карточка объекта недвижимости (кабинет застройщика), GET /api/v1/public/projects — Лента published-проектов (поиск + фильтры + сортировки), GET /api/v1/public/projects/{projectId}/chessboard — Шахматка проекта (матрица этажи × секции), GET /api/v1/public/property-objects — Список объектов недвижимости проекта/здания с фильтрами
- Use Cases (2): UC-CHS-004. Просмотр шахматки проекта: гость vs инвестор (разница полей), UC-PRC-002. Расчёт доходности объекта недвижимости с выбором субъекта (юр/физ) и налогового режима
- registries (1): Реестр API-методов PIN
Связанные документы
- Сущности: property-object.md, layout.md, building.md, project.md, developer.md, reference-data.md.
- Соседние операции: list-property-objects.md, get-chessboard.md, get-project.md.
- Инвест-аналитика объекта недвижимости (график роста, ROI) —
docs/06-services/invest-analytics/; бронирование —docs/06-services/crm/.