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

Event Contract: pin.messenger.deal-chat-status-changed (DealChatStatusChangedEvent)

Версионируемый контракт интеграционного события «изменилась готовность чата сделки». Consumer-документы (crm) ссылаются сюда, не переописывая payload. Событие фиксирует факт перехода провизии Deal-чата (Provisioning/Ready/Failed) и несёт корреляционные id — crm обновляет проекцию Deal.ChatStatus без синхронного запроса в messenger. Дом провизии чата — chat.md; проекция потребителя — deal.md.

Назначение

Оркестрация чат ↔ сделка идёт через события crm (ADR-0055): crm публикует pin.crm.deal-created.v1, консюмер messenger (deal-created.md) провизионирует чат и возвращает готовность этим событием. crm держит лишь проекцию Deal.ChatStatus (Pending — свой default до первого события) — источник истины чата остаётся в messenger. Событие публичное для корреляции воронки сделки; PII не несёт (только id + enum-статус).

Metadata

ПолеЗначение
Event typepin.messenger.deal-chat-status-changed
Класс событияDealChatStatusChangedEvent
Topicpin.messenger.deal-chat-status-changed.v1
Partitions / key3 / key = DealId (порядок смен статуса per-deal)
ContractVersion1
Producermessenger: провизия Deal-чата (deal-created.md) + воркер chat-provision-retry
Статусdraft

Событие публикуется атомарно (в одном согласованном изменении) с провизией/синком чата через транзакционный outbox. Партиционирование по ключу DealId даёт per-deal порядок смен статуса.

Payload DealChatStatusChangedEvent

Корреляционные поля; snapshot состояния переписки не входит. Дом полей чата — chat.md; дом проекции DealChatStatusdeal.md.

ПолеТипОбязательностьИсточник (поле агрегата)CompatibilityОписание
DealIdGuidДаChat.DealIdImmutableСделка (Kafka key). Ключ проекции у crm.
TenantIdGuidДаChat.DealTenantIdImmutableDeveloperCompanyId сделки (ADR-0052); crm сверяет с deal.TenantId (fail-closed).
ChatIdGuid?Нет (для Ready — да)Chat.IdImmutableId созданного чата messenger; null при Provisioning/Failed до создания строки чата.
Statusstring (enum DealChatStatus)Даход провизииAdditive only (новые значения)Provisioning / Ready / Failed (Pending — CRM-side default, продюсером не шлётся).
FailureReasonstring?Нет (только при Status = Failed)ошибка провизииAdditive onlyКраткая диагностика провала (без PII/стектрейса); crm пишет в лог, не хранит.
ChangedAtDateTimeOffsetДамомент сменыImmutable semanticsМомент смены статуса в messenger (диагностика лага; авторитет порядка — partition key DealId).

DealId/TenantId иммутабельны; Status/ChatId/FailureReason переиздаются при каждом переходе провизии.

Enum DealChatStatus

Дом — deal.md («Enum DealChatStatus»). messenger — producer подмножества.

ЗначениеКто эмититОписание
Pending— (CRM default)До первого события consumer-а; продюсером messenger не публикуется.
ProvisioningmessengerНачато создание чата/синк состава по deal-created.
ReadymessengerЧат создан, участники синхронизированы (ChatId заполнен).
FailedmessengerПровизия упала; воркер chat-provision-retry повторит и re-emit.

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

УсловиеПереход состоянияСогласованность
Начата провизия по deal-created (до создания строки чата)Pending → Provisioningприём события и факт начала — в одном согласованном изменении
Чат создан и состав синхронизирован (INV-CHAT-2/6)Provisioning → Readyчат (+участники) и факт готовности — атомарно
Провизия упала (ошибка создания/синка)→ Failedотметка обработки и факт провала — атомарно
Воркер chat-provision-retry успешно повторилFailed → Readyчат и факт готовности — атомарно

Идемпотентная повторная доставка deal-created (INV-CHAT-2) не плодит чат и не меняет Ready — регресс из терминального Ready producer не публикует (у crm Ready поглощающий). Источник провизии — deal-created.md; статус чата пользователя (Active/Closed) — ортогонален (дом chat.md).

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

Consumer-контекстЭффект (событие → что меняется)ИдемпотентностьЗадержка (SLA)
crmПроекция Deal.ChatStatus (монотонный rank-guard: Ready терминален) — deal-chat-status.mdдедуп по идентификатору сообщения + монотонный rank-guard< 30 с

Событие несёт ChatId только для лога/трейса — crm его не хранит на сделке (ADR-0055).

Гарантии доставки, порядок и обработка отказов

  • At-least-once + монотонная проекция. Доставка хотя бы раз; crm дедуплицирует по идентификатору сообщения и держит монотонный rank-guard Provisioning < Ready, Failed < Ready: Ready поглощающий, назад не откатывается. Повтор Ready (в т.ч. re-emit воркером chat-provision-retry после Failed) — идемпотентный no-op проекции.
  • Порядок per-DealId. Ключ DealId даёт per-deal порядок смен статуса; между сделками порядка нет.
  • Fail-closed по tenant. crm сверяет TenantId события с deal.TenantId своей сделки; при расхождении событие отбрасывается (не своя сделка) — проекция не обновляется, инцидент логируется.
  • Unknown Status — критично. В отличие от прочих топиков сервиса, неизвестное значение Status не деградирует тихо: CRM_CHAT_STATUS_UNKNOWN → DLQ + алерт (готовность чата — часть воронки сделки).

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

  • ContractVersion = 1; при несовпадении версии входящего события с текущей consumer логирует warning и продолжает (апкаст/миграция схемы не выполняется). Топик кодирует версию суффиксом .v1 по конвенции.
  • Additive-only для minor: новые поля — optional с безопасным default, без bump.
  • Breaking (удаление/переименование/смена типа/смысла) — новый ContractVersion = 2 + новый топик pin.messenger.deal-chat-status-changed.v2 + dual-publish + deadline миграции consumers + sunset .v1.
  • Unknown enum Status у consumer-а — CRM_CHAT_STATUS_UNKNOWN → DLQ + алерт (не тихий fallback: проекция готовности критична).
  • Порядок смен per-deal гарантирован ключом DealId; consumer держит монотонный rank-guard (Ready не регрессирует).

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

ПолеКласс данныхПравило
DealId, TenantId, ChatId, Status, ChangedAtInternalinclude (корреляция сделки/чата; не публичный контент)
FailureReasonInternalinclude (без PII/стектрейса/секретов; только краткая причина)

Событие НЕ содержит тел сообщений, ФИО/телефонов участников, IP/UA, secrets, tokens, платёжных данных.

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

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

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