Chessboard Service (Pin.Chessboard)
Назначение
chessboard владеет структурой недвижимости платформы PIN — иерархией
Застройщик → Проект (ЖК/отель) → Здание (литер/корпус) → Объект недвижимости плюс планировки
(Layout/LayoutGroup) и платформенные справочники (Банки, Отельеры) — и предоставляет шахматку
(матрица «этажи × секции» со статусами), CRUD для застройщиков и администраторов и события об изменениях
объектов, цен и статусов для остальных контекстов. Статусы продажи объектов недвижимости
(Резерв/Бронь/Продан) меняются событиями CRM (модуль бронирования). Часть данных реплицируется из внешней
системы Talent Chessboard и дополняется/корректируется собственными полями PIN.
Metadata
| Поле | Значение |
|---|---|
| Статус | draft |
| Owning team | PIN Platform Core |
| Domain | Real Estate Catalog Structure |
| Data classification | Internal/Public (PII нет; юрданные проектов публичны по 214-ФЗ) |
| Runtime criticality | high (без шахматки нет каталога, аналитики, бронирования) |
Ownership
| Artifact | Owner/Rule |
|---|---|
| PostgreSQL schema | chessboard |
| API areas | public (лента/карточки/шахматка, гость+инвестор), agents (чтение для агентов), developers (CRUD своего: застройщик/проекты/здания/объекты недвижимости + lookup справочников), admin (CRUD банков/отельеров, полный доступ — ADR-0053) |
| Owned entities | DeveloperEntity, ProjectEntity, BuildingEntity, PropertyObjectEntity, LayoutEntity, LayoutGroupEntity, BankEntity, HotelierEntity; enum-справочники (reference-data) |
| Produced events | pin.chessboard.developer-upserted.v1, pin.chessboard.project-upserted.v1, pin.chessboard.building-upserted.v1, pin.chessboard.property-object-upserted.v1, pin.chessboard.property-object-status-changed.v1, pin.chessboard.property-object-price-changed.v1, pin.chessboard.layout-upserted.v1, pin.chessboard.layout-group-upserted.v1 |
| Consumed events | talent.chessboard.* (синк developers/projects/buildings/property-objects/layouts), pin.crm.booking-created/booking-confirmed/booking-expired/booking-cancelled.v1, pin.crm.deal-completed/deal-cancelled.v1 (→ переходы Резерв/Бронь/Освобождение/Продан, маппинг в consumers/crm-property-object-status.md), pin.identity.companies.v1 (создание Developer-профиля по компании Type=Developer), pin.handbook.{countries|regions|cities|currencies}.v1 (локальная реплика справочников — consumers/handbook-sync.md) |
| Search indexes | Elasticsearch-проекция ProjectSearchDocument (search/projects.md, ADR-0059) — поиск проектов по name+address (fuzzy/транслитерация); не PostgreSQL-FTS |
| Analytics facts | none (история цен — invest-analytics; view-статистика — dev-stats, оба питаются событиями шахматки) |
Ответственность И Границы
- Делает: хранение и CRUD иерархии Developer→Project→Building→PropertyObject + Layout/LayoutGroup; шахматка
(матрица этажей/секций с цветовой индикацией статусов); справочники Bank/Hotelier (admin CRUD +
lookup); синк из Talent Chessboard с разделением «реплика-поля vs PIN-поля»; применение статусов
Резерв/Бронь/Продан по событиям CRM + таймеры
ReservedUntil/BookedUntil+ страховочный job истечения; публикация snapshot-/status-/price-событий; денормализованные агрегаты проекта (Price-диапазон, счётчики объектов недвижимости); локальная реплика справочниковhandbook(страны/регионы/города/валюты) — валидация ссылокCountryId/RegionId/CityId/CurrencyIdна write-path и refresh display-имёнRegionName/CityNameпроектов. - НЕ делает: витрину/ранжирование/оверрайды отображения и пакеты продвижения (
catalog); историю цен и расчёт доходности (invest-analytics, питаетсяproperty-object-price-changed); программы бронирования, таймерную логику брони и сообщения в чат (crm/messenger); правила вознаграждений (rewards); статистику просмотров (dev-stats); хранение медиа-файлов (storage/CDN — внешняя граница). - Source of truth: все owned-сущности; для Talent-реплик реплика-поля — Talent Chessboard
(инварианты
*-SyncOwnedFields); текущий статус/цена объекта недвижимости для всех контекстов PIN — шахматка (CRM лишь инициирует переходы событиями). - Реплики/проекции у потребителей:
catalog(витрина),dev-stats(измерения Developer→…→PropertyObject, ADR-0057),rewards(Layout/LayoutGroup),invest-analytics(объекты недвижимости+цены),identity(scope «группа проектов/проект»).
Зависимости
| Зависимость | Тип | Зачем Нужна | Failure mode |
|---|---|---|---|
PostgreSQL (schema chessboard) | db | Все агрегаты + outbox | Полный отказ сервиса |
| Kafka | queue | Синк Talent (in), события CRM (in), события pin.chessboard.* (out, outbox) | Чтение/CRUD работают; статусы объектов недвижимости и реплики потребителей отстают (лаг-алерты) |
| talent.microservices.chessboard | external system | Источник реплики застройщиков/проектов/зданий/объектов недвижимости/планировок | Синк отстаёт; локальные данные и PIN-поля не затронуты |
crm (события) | service (async) | Переходы Резерв/Бронь/Продан + таймеры | Статусы «залипают» — страховочный job property-object-hold-expiration возвращает истёкшие холды в Free |
identity (события) | service (async) | Появление компании Type=Developer → Developer-профиль | Новые застройщики не заводятся автоматически (ручной admin-путь) |
handbook (события) | service (async) | Локальная реплика справочников chessboard.handbook_* (страны/регионы/города/валюты): валидация ссылок на write-path (INV-PRJ-10), refresh display-имён проектов | Реплика отстаёт: новые записи справочника недоступны в валидации (fallback-резолв в handbook), refresh имён задерживается |
| storage/CDN | external system | Файлы (лого, схемы, фото хода строительства) — только FileId+пресайн | Карточки без картинок; данные целы |
Проекты
src/services/chessboard/
Pin.Chessboard.Api/ # areas: public, agents, developers, admin
Pin.Chessboard.Application/ # обработчики операций по областям
Pin.Chessboard.Domain/ # агрегаты domain/*.md
Pin.Chessboard.Infrastructure/ # доступ к PostgreSQL, публикация событий, хранение enum строкой
Pin.Chessboard.Background/ # consumers: talent-sync, crm-property-object-status, identity-companies, handbook-sync; jobs: property-object-hold-expiration, project-aggregates-recalc
Pin.Chessboard.Migrator/ # миграции схемы chessboard
Pin.Chessboard.Contracts/ # pin.chessboard.* event contracts
Основные Сущности
| Entity | Назначение | Source Of Truth | Документ |
|---|---|---|---|
DeveloperEntity | Профиль застройщика (Id = CompanyId identity), корень tenant шахматки | chessboard (+реплика-поля Talent) | domain/developer.md |
ProjectEntity | Проект (ЖК/отель): тип/класс/гео (страна/регион/город — ссылки справочника handbook)/статус строительства, 5 typed-jsonb вкладок, диапазон цен, окупаемость | chessboard (+реплика-поля Talent) | domain/project.md |
BuildingEntity | Здание/литер/корпус: этажность, срок сдачи, готовность | chessboard (+реплика-поля Talent) | domain/building.md |
PropertyObjectEntity | Объект недвижимости: номер, этаж, площади, комнатность, цена, статус+таймеры, вид из окна, вместимость | chessboard (статусы — по событиям crm) | domain/property-object.md |
LayoutEntity | Типовая планировка: схемы, площади | chessboard (+реплика-поля Talent) | domain/layout.md |
LayoutGroupEntity | Группа планировок (уровень rewards/dev-stats) | chessboard (+реплика-поля Talent) | domain/layout-group.md |
BankEntity | Справочник банков (Id, Название, Лого) | chessboard | domain/bank.md |
HotelierEntity | Справочник отельеров (Id, Название, Лого) | chessboard | domain/hotelier.md |
| enum-справочники | Типы/классы проектов, статусы строительства, виды из окон и служебные enum-ы | chessboard (код) | domain/reference-data.md |
handbook-реплика (HandbookCountryReplica, HandbookRegionReplica, HandbookCityReplica, HandbookCurrencyReplica) | Локальная реплика справочников: валидация ссылок CountryId/RegionId/CityId/CurrencyId (INV-PRJ-10), refresh display-имён RegionName/CityName | handbook (транзитивно — Talent Handbook, ADR-0063) | domain/handbook-replica.md |
ER-обзор
API (карта областей; детали — api/, будущие документы)
- Public (гость/инвестор; неавторизованным скрываются точные цены/статусы/шахматка):
лента published-проектов (пагинация, полнотекстовый поиск, фильтры тип/класс/регион/статус строительства/цена,
сортировки цена/дата/окупаемость), карточка проекта (ограниченная/полная: вкладки Информация/Локация/
Финансирование/Юрданные/Ход строительства/Видео/Карта), шахматка проекта (
/hotels/[id]/chessboard), список/карточка объектов недвижимости с фильтрами (этаж/комнатность/цена). - Agents: те же чтения без ограничений гостя + lookup банков/отельеров (для оформления сделок).
- Developers (scope своей компании): CRUD (search/list, get by id, update, lookup
list, lookup by id) — профиль застройщика, проекты, здания; управление объектами недвижимости (паспортные поля, цена,
Hide/Unhide), планировками и группами; lookup банков/отельеров (продублирован). - Admin (администратор платформы, ADR-0053): CRUD банков и отельеров (create, search/list, get by id, update, delete=архив, lookup list, lookup by id); сервисные операции над любыми застройщиками/проектами (publish/hide, разрешение конфликтов синка).
Events И Consumers
| Type | Name | Topic | Назначение | Link |
|---|---|---|---|---|
| Produced | DeveloperUpsertedKafkaEvent | pin.chessboard.developer-upserted.v1 | Snapshot застройщика для catalog/dev-stats/crm/rewards | domain/developer.md |
| Produced | ProjectUpsertedKafkaEvent | pin.chessboard.project-upserted.v1 | Snapshot проекта для catalog/dev-stats/identity(scope)/news | domain/project.md |
| Produced | BuildingUpsertedKafkaEvent | pin.chessboard.building-upserted.v1 | Snapshot здания для catalog/dev-stats | domain/building.md |
| Produced | PropertyObjectUpsertedKafkaEvent | pin.chessboard.property-object-upserted.v1 | Паспортный snapshot объекта недвижимости для catalog/dev-stats/rewards | domain/property-object.md |
| Produced | PropertyObjectStatusChangedKafkaEvent | pin.chessboard.property-object-status-changed.v1 | Резерв/Бронь/Продан/Скрыт + таймеры для catalog/favorites/selections/notifications | domain/property-object.md |
| Produced | PropertyObjectPriceChangedKafkaEvent | pin.chessboard.property-object-price-changed.v1 | Append-only история цен (invest-analytics), обновление витрины | domain/property-object.md |
| Produced | LayoutUpsertedKafkaEvent | pin.chessboard.layout-upserted.v1 | Измерение Layout (dev-stats), правила rewards, типы объектов недвижимости invest-analytics | domain/layout.md |
| Produced | LayoutGroupUpsertedKafkaEvent | pin.chessboard.layout-group-upserted.v1 | Измерение LayoutGroup (dev-stats), правила rewards | domain/layout-group.md |
| Consumed | синк Talent Chessboard | talent.chessboard.* (имена — assumption до подтверждения контрактов Talent) | Реплика developers/projects/buildings/property-objects/layouts (ReplicaVersion-guard); адресные строки резолвятся в ссылки справочника name-match-ем по реплике | consumers/talent-chessboard-sync.md |
| Consumed | Reserve/Book/Release/MarkSold (переходы) | pin.crm.booking-created.v1, pin.crm.booking-confirmed.v1, pin.crm.booking-expired.v1, pin.crm.booking-cancelled.v1, pin.crm.deal-completed.v1, pin.crm.deal-cancelled.v1 | Переходы статусов объекта недвижимости + таймеры (INV-CHS-001/002/003); маппинг событие→переход | consumers/crm-property-object-status.md; контракты — docs/06-services/crm/events/ |
| Consumed | CompanyUpsertedKafkaEvent | pin.identity.companies.v1 | Создание/обновление Developer-профиля для компаний Type=Developer; suspend → Hidden | domain/developer.md |
| Consumed | справочники handbook | pin.handbook.countries.v1, pin.handbook.regions.v1, pin.handbook.cities.v1, pin.handbook.currencies.v1 | Локальная реплика справочников (валидация ссылок INV-PRJ-10); при переименовании региона/города — refresh RegionName/CityName проектов + re-publish project-upserted (HR-6) | consumers/handbook-sync.md |
Гарантии Событий И Согласованность (кросс-сервисный контракт)
- Ключ партиционирования всех
pin.chessboard.*событий —Idзатронутого агрегата (Developer / Project / Building / PropertyObject / Layout / LayoutGroup). Порядок событий одного агрегата сохраняется; между разными агрегатами порядок не гарантируется. Потребители, которым важен порядок «проект раньше его объектов», опираются на наличие родителя, а не на межпартиционный порядок. - Доставка — at-least-once через outbox: событие фиксируется в том же согласованном изменении, что и
мутация агрегата; ответ API (
2xx) не ждёт доставки в шину. Отсюда — потребители обязаны быть идемпотентными и отбрасывать устаревшее по монотонномуVersion(snapshot-события*-upserted) либоChangedAt/StatusChangedAt(property-object-status-changed,property-object-price-changed). - Версионирование:
ContractVersionв конверте; расширение payload новыми optional-полями — additive без bump; несовместимое изменение — новый топик.v2+ dual-publish (контракты —events/*). - Окна согласованности (envelope). Собственное хранилище
chessboard— read-after-write: изменение видно инициатору сразу. Реплики соседей (catalog,dev-stats,rewards,invest-analytics,identity) — в пределах SLO применения событий (p99 < 5 с). Денормализованные агрегаты проекта (Price, счётчики объектов недвижимости) — послеproject-aggregates-recalc(debounce 30 с). Переходы статуса объекта недвижимости по событиям CRM — p99 < 5 с; при потере release-события статус возвращается вFreeстраховочным job-ом не позже grace 10 мин (INV-CHS-003). - Что видит пользователь в промежутке. Опубликованный проект и новая цена появляются в кабинете
застройщика немедленно, в публичной ленте/шахматке/поиске — после потребления события каталогом; scope
«проект» в
identityдля назначения ролей — после потребленияproject-upserted; публичные счётчики «свободно/всего» отстают на окно пересчёта агрегатов.
Runtime И Эксплуатация
| Область | Требование |
|---|---|
| Health checks | /health/live, /health/ready (PostgreSQL, Kafka), /health/startup (миграции применены) |
| SLO/SLA | Лента/шахматка p99 < 300 мс (индексные запросы PostgreSQL); применение события CRM p99 < 5 с; лаг синка Talent < 5 мин |
| Dashboard | chessboard-overview (RPS чтения, лаг consumers, DLQ, срабатывания job-а истечения) |
| Alerts | лаг синка > 5 мин; DLQ > 0; CHESSBOARD_PROPERTY_OBJECT_HOLD_MISMATCH (INV-CHS-003); срабатывания property-object-hold-expiration > порога (потерянные release-события CRM); chessboard_sync_unknown_enum_total рост; staleness реплики справочников handbook и рост нерезолвленных гео-ссылок синка (warn-метрика name-match) |
| Runbooks | replay DLQ синка/CRM; ручной release залипшего холда; пересинк проекта из Talent |
| Feature flags | chessboard.talent-sync.enabled (пауза синка при инцидентах источника) |
Background (jobs; детали — background/ по background-job-template, будущие документы)
| Job | Периодичность | Что делает |
|---|---|---|
property-object-hold-expiration | раз в 1 мин | Находит объекты в статусе Reserved/Booked, чей таймер истёк более чем на grace-период (10 мин), и переводит их в Free (источник статуса — ExpirationJob) с публикацией события и warning-логом (страховка от потерянных release-событий CRM; сама таймерная логика брони — CRM) |
project-aggregates-recalc | по доменному событию ProjectAggregatesRecalcRequestedEvent (debounce 30 с) | Пересчёт Project.Price/PropertyObjectsTotalCount/PropertyObjectsFreeCount, Building.PropertyObjects*Count, Layout.PropertyObjectsCount, LayoutGroup.LayoutsCount/Area в одном согласованном изменении |
Безопасность
- Actor types: guest (public, урезанные проекции), investor/agent (public/agents, полные чтения), developer-manager (developers area, scope своей компании), администратор платформы (admin area, ADR-0053), system (consumers/jobs).
- Permission model:
chessboard.developers.manage,chessboard.projects.manage,chessboard.buildings.manage,chessboard.property-objects.manage,chessboard.layouts.manage,chessboard.banks.manage,chessboard.hoteliers.manage,chessboard.references.lookup— каталог и scope-назначения вidentity(../identity/domain/permission.md). - Sensitive data: PII нет; юрданные проектов (
LegalInfo) публичны по 214-ФЗ; точные цены/статусы скрываются от неавторизованных на уровне проекций чтения. - Audit:
Version+ actor-stamping на всех сущностях;StatusSource/StatusChangedAtна объекте недвижимости; история статусов и цен восстанавливается из событий. - Tenant isolation: ADR-0052 —
TenantId = DeveloperId (CompanyId)на мутациях и developer-запросах; public-чтение — контролируемый доступ только кPublished-срезам без ограничения по tenant; справочники Bank/Hotelier и enum-ы — платформенные (не привязаны к застройщику).
Известные Ограничения И Assumptions
- Имена топиков/контракты Talent Chessboard (
talent.chessboard.*, модельPropertyObject) — assumption до подтверждения schema registry Talent; синк проектируется идемпотентным (ReplicaVersion). - Контракты событий CRM (
pin.crm.booking-*.v1,pin.crm.deal-*.v1) — вdocs/06-services/crm/events/; здесь зафиксированы обязательные поля-минимум:PropertyObjectId,DealId,ReservedUntil/BookedUntil/SoldAt. - Таймеры брони — source of truth CRM (программа бронирования); job шахматки — только страховка (grace 10 мин), сообщения «время истекло» в чат — CRM/messenger.
PaybackYearsпроекта — ручной ввод/загрузка; серверный расчёт доходности —invest-analytics.- Медиа-файлы — только
FileId; выдача пресайн-ссылок — storage/CDN. - Гео (страна/регион/город) и валюта — типизированные ссылки на справочник
handbook(CountryId/RegionId/CityId/CurrencyId+ денормализованныеRegionName/CityName, ADR-0063); синк Talent резолвит адресные строки источника name-match-ем по реплике — нерезолвленная ссылка (RegionId/CityId = null+ warn-метрика) не блокирует синк, но блокирует публикацию проекта (INV-PRJ-3) до ручного разрешения.
Связанные Документы
- Домены: developer · project · building · property-object · layout · layout-group · bank · hotelier · reference-data · handbook-replica.
- Решения: ADR-0052 (tenancy), ADR-0056 (simplicity-first), ADR-0057 (dev-stats потребляет измерения), ADR-0063 (справочники handbook, локальная реплика); technical-assignment.md, service-boundaries.md, glossary.md.
- Соседи:
docs/06-services/catalog/(витрина),docs/06-services/crm/(бронирование/статусы),docs/06-services/invest-analytics/(история цен),docs/06-services/dev-stats/(измерения),docs/06-services/rewards/(правила по Layout/LayoutGroup),docs/06-services/handbook/(справочники стран/регионов/городов/валют; snapshot-модели событий —handbook/domain/snapshots.md).