Сущность / агрегат: PropertyObjectTypeConfig
Уровень «тип объекта недвижимости» экономической модели доходности. Тип объекта недвижимости = группа
планировок (LayoutGroup) из контекста chessboard.
Назначение
PropertyObjectTypeConfig — nullable-оверрайды платформенных коэффициентов
EconomicModelConfig для конкретной группы планировок («Стандарт»,
«Комфорт», «Люкс», «Президентский люкс» и т.д.). Заполненное поле замещает платформенное значение;
null — «наследовать от платформы». Является средним уровнем разрешения коэффициентов:
PropertyObjectTypeMonthOverride → PropertyObjectTypeConfig → EconomicModelConfig → дефолты кода.
Агрегат владеет дочерней коллекцией помесячных оверрайдов
PropertyObjectTypeMonthOverride.
Настройка типа удаляется физически (soft-delete не применяется): расчёт по объектам этой группы
откатывается к платформенному уровню, история изменений — через Version и audit-события.
Классификация
| Поле | Значение |
|---|---|
| Контекст | invest-analytics |
| Kind | агрегат (граница: PropertyObjectTypeConfig + коллекция PropertyObjectTypeMonthOverride); натуральный ключ — внешний id группы планировок |
| Source of truth | коэффициенты — invest-analytics; сам справочник групп планировок — chessboard (реплика Talent) |
| Таблица | invest_analytics.property_object_type_config |
| Tenant isolation | не tenanted — платформенная настройка (ADR-0052 п.3) |
Поля
Все коэффициенты-оверрайды nullable: null = «взять значение из EconomicModelConfig». Семантика и
единицы каждого коэффициента — economic-model-config.md (здесь только дельта:
nullable + натуральный ключ). Диапазоны заполненных значений те же (INV-MC2).
| Поле | Тип | Обязательность | Ограничения (PK/FK/index/constraint) | Источник | Описание |
|---|---|---|---|---|---|
Id (GroupId) | long | Да | PK (натуральный, не generated) | chessboard (id LayoutGroup) | Группа планировок, к которой относится настройка. FK-констрейнта нет — справочник живёт в другом контексте; существование проверяется на уровне команды через chessboard (правило границ). |
Name | string | Да | varchar(128), not null | admin API / chessboard | Отображаемое имя типа («Стандарт», «Люкс»…); заполняется из группы планировок, админ может переименовать. |
MarketPremium | decimal? | Нет | numeric(9,6); check как INV-MC2 при not null | admin API | Оверрайд надбавки к прайсу. |
PriceGrowthMonthly | decimal? | Нет | numeric(9,6) | admin API | Оверрайд месячного роста цены. |
DailyRentM2 | decimal? | Нет | numeric(12,2) | admin API | Оверрайд ставки аренды руб/м²/сутки. |
RentGrowthMonthly | decimal? | Нет | numeric(9,6) | admin API | Оверрайд месячного роста аренды. |
ExpenseShare | decimal? | Нет | numeric(9,6) | admin API | Оверрайд доли расходов. |
AppreciationTaxMonthly | decimal? | Нет | numeric(9,6) | admin API | Легаси-оверрайд (не участвует в расчёте — см. дом поля). |
EbitdaTaxMonthly | decimal? | Нет | numeric(9,6) | admin API | Легаси-оверрайд (не участвует в расчёте). |
Occupancy | decimal? | Нет | numeric(9,6) | admin API | Оверрайд заполняемости. |
HorizonMonths | int? | Нет | check >= 1 AND <= 360 при not null | admin API | Оверрайд горизонта прогноза. |
Version | long | Да | >= 1 | app | Ревизии настройки типа. |
CreatedAt / UpdatedAt | DateTimeOffset | Да | — | app | Штампы. |
CreatedByUserId / UpdatedByUserId | Guid? | Нет | — | identity-context | Актор правки. |
Оптимистичная блокировка: конкурентные правки в админке не должны затирать друг друга (см. «Индексы,
хранение, безопасность» → 409 INVEST_ANALYTICS_PROPERTY_OBJECT_TYPE_CONFLICT).
Связи
| Связь | Тип | Ключ | Правило загрузки | Delete behavior |
|---|---|---|---|---|
PropertyObjectTypeMonthOverride | коллекция агрегата | GroupId (composite PK ребёнка) | при расчёте — все месяцы типа по GroupId без пагинации; в админке — вместе с родителем | cascade (удаление типа удаляет его помесячные оверрайды) |
LayoutGroup (chessboard) | replica-reference (логическая, без FK) | Id = GroupId | проверка существования — запрос в chessboard на команде создания | — |
EconomicModelConfig | reference (логическая, без FK) | well-known Id | отдельная загрузка при расчёте | — |
Инварианты и переходы состояний
| Инвариант | Условие | Где проверяется | Ошибка |
|---|---|---|---|
| INV-LT1 GroupExists | GroupId существует как группа планировок в chessboard | проверка при admin-upsert (запрос в chessboard) | INVEST_ANALYTICS_PROPERTY_OBJECT_TYPE_GROUP_NOT_FOUND |
| INV-LT2 Ranges | Заполненные (not null) коэффициенты — в диапазонах INV-MC2 | валидация + check-constraints | ValidationError |
| INV-LT3 FiniteNumbers | Заполненные значения — конечные числа (запрет NaN/Infinity) | тип numeric + валидация | ValidationError |
| INV-LT4 NameNotEmpty | Name непустое после trim, ≤ 128 символов | валидация | ValidationError |
Доменные и интеграционные события
| Событие | Тип | Когда | Snapshot/поля |
|---|---|---|---|
PropertyObjectTypeConfigUpsertedEvent | доменное | Создание/обновление настройки типа | GroupId, Version, UpdatedByUserId — audit-лог |
PropertyObjectTypeConfigDeletedEvent | доменное | Удаление настройки типа (возврат к платформенным значениям) | GroupId, UpdatedByUserId |
Интеграционное событие: upsert/delete настройки типа (PropertyObjectTypeConfigUpsertedEvent/
PropertyObjectTypeConfigDeletedEvent) публикует EconomicModelChangedKafkaEvent
(pin.invest-analytics.model-changed.v1, ChangeScope = PropertyObjectType, GroupId) через outbox —
internal recompute job пересчитывает метрики доходности объектов недвижимости этого типа и переиздаёт
pin.invest-analytics.property-object-metrics.v1 (../events/model-changed.md).
Коэффициенты в payload не уходят (подписчик читает модель напрямую).
Окно согласованности и промежуточное состояние
Правка/удаление настройки типа не пересчитывает витрину синхронно:
- Upsert/delete коммитится атомарно с outbox-записью
model-changed(ChangeScope = PropertyObjectType,GroupId). - Расчёт
investor-seriesпо объектам этогоGroupIdчитает уровни вживую — новые (или откатившиеся к платформенным после удаления) коэффициенты действуют со следующего запроса. - Витринные метрики объектов этого типа пересчитываются асинхронно recompute job-ом (окно до 15 мин); в этом окне карточки каталога затронутых объектов недвижимости могут ещё показывать прежние бейджи.
Конкурентность: upsert и delete одной и той же настройки типа сериализуются оптимистичной блокировкой по
Version — проигравший получает 409 INVEST_ANALYTICS_PROPERTY_OBJECT_TYPE_CONFLICT и перечитывает
актуальное состояние. Удаление типа с настроенными помесячными оверрайдами каскадно удаляет их (дочерняя
коллекция) — объекты недвижимости группы целиком возвращаются к платформенному уровню.
Индексы, хранение, безопасность
| Аспект | Значение |
|---|---|
| Индексы | PK (Id); дополнительные не нужны — таблица маленькая (единицы–десятки типов), выборки по PK |
| Партиционирование / retention | нет — справочная таблица |
| Concurrency | оптимистичная блокировка → 409 INVEST_ANALYTICS_PROPERTY_OBJECT_TYPE_CONFLICT; Version — ревизии |
| Permissions / PII | Чтение — внутреннее (расчёт) + admin invest-analytics.property-object-types.view; запись — admin invest-analytics.property-object-types.manage (ADR-0053). PII нет |
| Audit | actor-stamping + Version + доменные события |
Обратные ссылки
Автоссылки: где используется этот документ.
- Домен (CQRS) (3): Расчётные модели: InvestorMonth, AnalyticsSeries, AsideMetrics, Сущность / агрегат: EconomicModelConfig, Сущность: PropertyObjectTypeMonthOverride
- API (6): GET /api/admin/v1/property-object-types — Список настроек типов объектов недвижимости (admin), GET /api/admin/v1/property-object-types/{groupId}/month-overrides — Помесячные оверрайды типа объекта недвижимости (admin), GET /api/v1/property-objects/{propertyObjectId}/investor-series — Серии доходности объекта недвижимости, POST /api/admin/v1/investor-preview — Расчёт серий доходности по произвольным параметрам (admin preview / growth-chart), PUT /api/admin/v1/property-object-types/{groupId} — Upsert настройки типа объекта недвижимости (admin), PUT /api/admin/v1/property-object-types/{groupId}/month-overrides — Replace-all помесячных оверрайдов типа объекта недвижимости (admin)
- Use Cases (2): UC-PRC-002. Расчёт доходности объекта недвижимости с выбором субъекта (юр/физ) и налогового режима, UC-PRC-004. Admin: настройка типа объекта недвижимости и помесячных оверрайдов
- События (2): События invest-analytics: карта контрактов, Event Contract: pin.invest-analytics.model-changed (EconomicModelChangedKafkaEvent)
- index.md (1): InvestAnalytics Service
- registries (2): Реестр инвариантов PIN, Реестр сущностей PIN
Связанные документы
- Дом семантики коэффициентов: economic-model-config.md.
- Дочерняя сущность: property-object-type-month-override.md.
- Использование в расчёте: investor-series-models.md.
- Справочник групп планировок:
docs/06-services/chessboard/domain/layout-group.md. - Admin-операции: ../api/admin/list-property-object-types.md, ../api/admin/put-property-object-type.md.