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

Event Contract: pin.selections.selection-created (SelectionCreatedKafkaEvent)

Версионируемый контракт интеграционного события «подборка создана». Consumer-документы ссылаются сюда, не переописывая payload. Дом полей-источников — entity: Selection.

Назначение

Фиксирует создание подборки владельцем — вручную (Source = Manual) или из текущего избранного (Source = Favorites) — и даёт user-activity (модуль actions, ADR-0054) факт для ActionEvent «создал подборку», который через поток user-activity → crm виден агенту в карточке лида (создание подборки — сильный сигнал вовлечённости инвестора). Состав (PropertyObjectId-список) и комментарии в событие не входят — потребителю достаточно факта и счётчика, состав читается API по id.

Metadata

ПолеЗначение
Event typepin.selections.selection-created
Topicpin.selections.selection-created.v1
Partitions / key3 партиции (низкий объём: ≤ 100 подборок на владельца, INV-SEL-007; ADR-0056) / key = AggregateId = SelectionId
ContractVersion1
Producerselections: POST /selections и POST /selections/from-favorites
Owning teamPIN Engagement
Статусdraft

Событие публикуется атомарно с созданием подборки (корень + элементы — граница агрегата): пока подборка не зафиксирована, событие не отправляется потребителям; после фиксации — доставляется гарантированно (at-least-once). Ключ агрегата — SelectionId, тип агрегата — Selection.

Payload SelectionCreatedKafkaEvent

Источники полей — entity: Selection (раздел «Доменные и интеграционные события»).

ПолеТипОбязательностьИсточник (поле агрегата)CompatibilityОписание
SelectionIdGuidДаSelection.IdImmutableИдентификатор подборки (= AggregateId, = Kafka key).
OwnerUserIdGuidДаSelection.OwnerUserIdImmutableВладелец (инвестор или агент). Гость подборки не создаёт — поле не nullable (в отличие от избранного).
TitlestringДаSelection.TitleAdditive onlyНазвание (1..256) — для читаемого текста ActionEvent («создал подборку „Видовые у моря“»).
Sourcestring (enum SelectionSource)ДаSelection.SourceAdditive only (новые значения)Manual / Favorites — как создана (текстовая сериализация enum).
ItemsCountintДаSelection.Items.Count после созданияAdditive onlyЧисло объектов недвижимости в подборке на момент создания (0..200, INV-SEL-004).
OccurredAtDateTimeOffsetДаSelection.CreatedAtImmutableМомент создания (дублирует время события).

В payload не входят: PublicCode (публичная ссылка — не дело ленты действий; выдаётся API владельцу), Description, список PropertyObjectId, Comment-ы элементов (объём/приватность — правило selection.md). Вложенных моделей нет.

Когда публикуется

УсловиеПереход состоянияПубликация
POST /selections — подборка создана (лимит INV-SEL-007 пройден, PublicCode сгенерирован INV-SEL-005)Selection: [*] → Activeатомарно с созданием подборки
POST /selections/from-favorites — состав скопирован из internal API favorites (INV-SEL-010), подборка созданаSelection: [*] → Active (Source = Favorites)атомарно с созданием подборки

Событие не публикуется при снятии snapshot-а для поста (news, m2m) — подборка не создаётся, см. README событий и selection-snapshot.md.

Потребители (consumers)

Сверено с ../README.md (Events И Consumers) и service-boundaries.md.

Consumer-контекстConsumerЭффект (событие → что меняется)ИдемпотентностьЗадержка (SLA)
user-activityUserActivitySelectionCreatedConsumer (будущий док: docs/06-services/user-activity/consumers/selections-actions.md)ActionEvent «создал подборку» (Title, Source, ItemsCount) в историю действий OwnerUserId; проброс в карточку лида — поток user-activity → crmMessageId (дубль — skip)< 1 мин

crm и news на топик не подписаны: CRM хранит SelectionId у себя и читает подборку синхронно (GET /internal/selections/{id}); news работает только со snapshot-ами (синхронный m2m).

Доставка и обработка отказов

  • At-least-once через outbox (атомарно с созданием подборки); user-activity дедуплицирует по MessageId — повторная доставка не плодит дублей ActionEvent.
  • Транзиентный сбой консюмера → повторная доставка до ack; неустранимая (malformed payload) → DLQ + alert, без потери (реплей из топика). Отставание консюмера создание подборки не блокирует — сама подборка доступна сразу по API, ActionEvent в карточке лида появляется в пределах SLA (< 1 мин).
  • Общая политика доставки/порядка/DLQ — README.md, раздел «Доставка, идемпотентность и обработка отказов».

Версионирование и совместимость

  • ContractVersion = 1; несовпадение версии события — warn-and-proceed.
  • Additive-only: новые optional-поля — без bump; breaking — ContractVersion = 2 + топик pin.selections.selection-created.v2 + dual-publish + sunset .v1.
  • Unknown enum Source — fallback: consumer записывает исходную строку + warning, не падает.
  • События created/updated/deleted живут в разных топиках — порядок между ними не гарантирован; consumer упорядочивает по OccurredAt и терпит updated, пришедший раньше created (upsert-семантика проекции).

Безопасность

ПолеКласс данныхПравило
SelectionId, Source, ItemsCount, OccurredAtInternalinclude
OwnerUserIdInternal (в публичные ответы API не попадает — но Kafka-контур внутренний)include
TitleInternal (владелец публикует его по ссылке сам)include
Список PropertyObjectId, Comment элементов, PublicCode, DescriptionInternal/приватная зона владельцаexclude

Событие НЕ содержит secrets, tokens, PII-профиля.

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

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

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