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

Chessboard Service (Pin.Chessboard)

Назначение

chessboard владеет структурой недвижимости платформы PIN — иерархией Застройщик → Проект (ЖК/отель) → Здание (литер/корпус) → Объект недвижимости плюс планировки (Layout/LayoutGroup) и платформенные справочники (Банки, Отельеры) — и предоставляет шахматку (матрица «этажи × секции» со статусами), CRUD для застройщиков и администраторов и события об изменениях объектов, цен и статусов для остальных контекстов. Статусы продажи объектов недвижимости (Резерв/Бронь/Продан) меняются событиями CRM (модуль бронирования). Часть данных реплицируется из внешней системы Talent Chessboard и дополняется/корректируется собственными полями PIN.

Metadata

ПолеЗначение
Статусdraft
Owning teamPIN Platform Core
DomainReal Estate Catalog Structure
Data classificationInternal/Public (PII нет; юрданные проектов публичны по 214-ФЗ)
Runtime criticalityhigh (без шахматки нет каталога, аналитики, бронирования)

Ownership

ArtifactOwner/Rule
PostgreSQL schemachessboard
API areaspublic (лента/карточки/шахматка, гость+инвестор), agents (чтение для агентов), developers (CRUD своего: застройщик/проекты/здания/объекты недвижимости + lookup справочников), admin (CRUD банков/отельеров, полный доступ — ADR-0053)
Owned entitiesDeveloperEntity, ProjectEntity, BuildingEntity, PropertyObjectEntity, LayoutEntity, LayoutGroupEntity, BankEntity, HotelierEntity; enum-справочники (reference-data)
Produced eventspin.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 eventstalent.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 indexesElasticsearch-проекция ProjectSearchDocument (search/projects.md, ADR-0059) — поиск проектов по name+address (fuzzy/транслитерация); не PostgreSQL-FTS
Analytics factsnone (история цен — 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Полный отказ сервиса
KafkaqueueСинк Talent (in), события CRM (in), события pin.chessboard.* (out, outbox)Чтение/CRUD работают; статусы объектов недвижимости и реплики потребителей отстают (лаг-алерты)
talent.microservices.chessboardexternal 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/CDNexternal 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, Название, Лого)chessboarddomain/bank.md
HotelierEntityСправочник отельеров (Id, Название, Лого)chessboarddomain/hotelier.md
enum-справочникиТипы/классы проектов, статусы строительства, виды из окон и служебные enum-ыchessboard (код)domain/reference-data.md
handbook-реплика (HandbookCountryReplica, HandbookRegionReplica, HandbookCityReplica, HandbookCurrencyReplica)Локальная реплика справочников: валидация ссылок CountryId/RegionId/CityId/CurrencyId (INV-PRJ-10), refresh display-имён RegionName/CityNamehandbook (транзитивно — 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

TypeNameTopicНазначениеLink
ProducedDeveloperUpsertedKafkaEventpin.chessboard.developer-upserted.v1Snapshot застройщика для catalog/dev-stats/crm/rewardsdomain/developer.md
ProducedProjectUpsertedKafkaEventpin.chessboard.project-upserted.v1Snapshot проекта для catalog/dev-stats/identity(scope)/newsdomain/project.md
ProducedBuildingUpsertedKafkaEventpin.chessboard.building-upserted.v1Snapshot здания для catalog/dev-statsdomain/building.md
ProducedPropertyObjectUpsertedKafkaEventpin.chessboard.property-object-upserted.v1Паспортный snapshot объекта недвижимости для catalog/dev-stats/rewardsdomain/property-object.md
ProducedPropertyObjectStatusChangedKafkaEventpin.chessboard.property-object-status-changed.v1Резерв/Бронь/Продан/Скрыт + таймеры для catalog/favorites/selections/notificationsdomain/property-object.md
ProducedPropertyObjectPriceChangedKafkaEventpin.chessboard.property-object-price-changed.v1Append-only история цен (invest-analytics), обновление витриныdomain/property-object.md
ProducedLayoutUpsertedKafkaEventpin.chessboard.layout-upserted.v1Измерение Layout (dev-stats), правила rewards, типы объектов недвижимости invest-analyticsdomain/layout.md
ProducedLayoutGroupUpsertedKafkaEventpin.chessboard.layout-group-upserted.v1Измерение LayoutGroup (dev-stats), правила rewardsdomain/layout-group.md
Consumedсинк Talent Chessboardtalent.chessboard.* (имена — assumption до подтверждения контрактов Talent)Реплика developers/projects/buildings/property-objects/layouts (ReplicaVersion-guard); адресные строки резолвятся в ссылки справочника name-match-ем по репликеconsumers/talent-chessboard-sync.md
ConsumedReserve/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/
ConsumedCompanyUpsertedKafkaEventpin.identity.companies.v1Создание/обновление Developer-профиля для компаний Type=Developer; suspend → Hiddendomain/developer.md
Consumedсправочники handbookpin.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 мин
Dashboardchessboard-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)
Runbooksreplay DLQ синка/CRM; ручной release залипшего холда; пересинк проекта из Talent
Feature flagschessboard.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).