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

Event Contract: pin.crm.lead-created (LeadCreatedEvent)

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

Назначение

Фиксирует появление первой активной связи «инвестор ↔ агент» — создание LeadEntity (глоссарий «Лид»). Публичное: даёт downstream-контекстам факт нового лида без синхронного запроса в crm. Потребители: notifications — уведомляет текущего исполнителя (ExecutorAgentUserId) о новом лиде; referral — подтверждает, что запрошенная реферальным приходом карточка лида создана (закрытие цикла lead-attach-requested → журнал регистраций). Событие НЕ несёт ФИО/телефон: клиентская база агентства — внутренние данные (застройщик о лиде не знает), consumers берут display-данные из собственных реплик pin.identity.users.v1.

Metadata

ПолеЗначение
Event typepin.crm.lead-created
Topicpin.crm.lead-created.v1
Partitions / key6 (ADR-0056) / key = LeadId (= AggregateId)
ContractVersion1
Producercrm: лид-заявки (Source = ConsultationRequest/BookingRequest), обработка реферальной привязки (Source = Referral), автосоздание лида при создании фиксации / ручном добавлении (Source = Manual)
Статусdraft
Атомарность публикации

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

Payload LeadCreatedEvent

Все поля — снимок LeadEntity на момент создания. Дом типов/ограничений — lead.md (раздел «Поля», «Доменные и интеграционные события»); PII-полей нет.

ПолеТипОбязательностьИсточник (поле агрегата)CompatibilityОписание
LeadIdGuidДаLeadEntity.IdImmutableКлюч агрегата (= Kafka key, = AggregateId).
TenantIdGuidДаLeadEntity.TenantIdImmutableTenant boundary = AgencyCompanyId (для лидов «на ПИН», UC-2 — компания ПИН; ADR-0052).
ExecutorAgentUserIdGuidДаLeadEntity.ExecutorAgentUserIdAdditive onlyТекущий участник-исполнитель (активный Executor) пары — получатель уведомления notifications.
OriginAgentUserIdGuidДаLeadEntity.OriginAgentUserIdImmutableАгент, изначально создавший лид: иммутабельная атрибуция (воронка агентства / антифрод).
PrimaryInvestorUserIdGuidДаLeadEntity.PrimaryInvestorUserIdImmutableОсновной инвестор-участник пары (корреляция реф-привязки).
ClientIdGuidДаLeadEntity.ClientIdImmutableКарточка клиента (client.md).
Sourcestring (enum LeadSource)ДаLeadEntity.SourceAdditive only (новые значения)Как появился лид (см. enum ниже). Иммутабельно.
ReferralLinkIdGuid?НетLeadEntity.ReferralLinkIdImmutableРеферальная ссылка-источник; null — лид не из реф-привязки. Заполнен ⇔ Source = Referral.
CreatedAtDateTimeOffsetДаLeadEntity.CreatedAtImmutableМомент создания лида.
ExpiresAtDateTimeOffsetДаLeadEntity.ExpiresAtAdditive onlyСрок жизни лида (CreatedAt + 1 месяц); продление меняет поле, но событие несёт значение на момент создания.

Enum LeadSource (string)

Дом — lead.md; в событии — строкой. Значения: ConsultationRequest (заявка на консультацию/презентацию, UC-1/UC-2), BookingRequest (заявка на бронирование, UC-3), Referral (реферальная привязка), Manual (агент создал лид вручную / автосоздание при фиксации).

Вложенных моделей нет — все поля скалярные. ФИО/телефон/Wishes в payload не входят (правило PII ниже).

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

Единственное срабатывание на лид — при переходе [*] → Active (INV-CRM-001: у пары нет активного лида; иначе создание — идемпотентный no-op, событие не публикуется).

УсловиеПереход состоянияПубликация
Публичная лид-заявка «консультация/презентация» (Source = ConsultationRequest)[*] → Activeатомарно со сменой состояния агрегата
Публичная заявка на бронирование объекта (Source = BookingRequest)[*] → Activeта же
Обработка реферальной привязки по pin.referral.lead-attach-requested.v1 (Source = Referral, ReferralLinkId заполнен)[*] → Activeта же
Автосоздание лида при создании заявки на фиксацию / ручном добавлении, если нет активного лида пары (Source = Manual)[*] → Activeта же
Реактивация — не новый lead-created

Реактивация Expired → Active (Extend) отдельным событием lead-created не сопровождается — это не новый лид. Истечение срока публикуется lead-expired.

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

Consumer-контекстSide effectsИдемпотентностьЗадержка (SLA)
notificationsУведомление исполнителю (ExecutorAgentUserId) «новый лид» (push/in-app/СМС); получатель и ФИО клиента резолвятся из собственных реплик, не из payloadMessageId< 5 мин
referralПодтверждение привязки: отметка в журнале регистраций (флаг LeadRequested → подтверждён) корреляцией по ReferralLinkId + PrimaryInvestorUserId; при Source != Referral / ReferralLinkId = null — no-opMessageId + бизнес-ключ (ReferralLinkId,PrimaryInvestorUserId)< 5 мин

Кросс-сервисные контракты

  • Ожидает (upstream). Для Source = Referral карточка лида создаётся в ответ на pin.referral.lead-attach-requested.v1: crm ожидает в нём ReferralLinkId и InvestorUserId, по которым лид корреллируется с журналом привязки. Отсутствие/ устаревание этих полей → лид не создаётся по реф-пути (обрабатывается другой Source).
  • Предоставляет (downstream). Публикует lead-created с ключом партиционирования LeadId, ContractVersion = 1. Для закрытия реф-цикла гарантирует наличие ReferralLinkId + PrimaryInvestorUserId при Source = Referral, по которым referral подтверждает привязку (флаг LeadRequested). Для Source != Referral ReferralLinkId = null, и referral трактует событие как no-op.

Доставка, порядок и обработка сбоев

  • Гарантия публикации. Событие уходит только после фиксации перехода [*] → Active; при откате не публикуется. Доставка — at-least-once, ключ LeadId.
  • Порядок. События одного лида упорядочены ключом LeadId. Событие — append-only факт создания, version-guard потребителю не нужен.
  • Идемпотентность потребителя. notifications — дедуп по MessageId; referral — по MessageId + business key (ReferralLinkId, PrimaryInvestorUserId) (повторная доставка не задваивает флаг журнала). На уровне продюсера: у пары без активного лида — идемпотентность создания (INV-CRM-001: повтор — no-op без события).
  • Retry. Транзиентный сбой потребителя → повтор обработки с backoff; событие доступно до успешной обработки.
  • DLQ. Неустранимый сбой после исчерпания попыток → dead-letter c алертом; проигрывание безопасно (дедуп/business key). Неизвестный LeadSource — уведомление/подтверждение всё равно обрабатываются (fail-safe), в DLQ не уходит.

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

  • Версия — один ContractVersion = 1; при несовпадении версии контракта потребитель логирует предупреждение и продолжает обработку. Топик кодирует версию суффиксом .v1 по конвенции.
  • Additive-only для minor: новые поля добавляются как optional с безопасным default — без bump.
  • Breaking (удаление/переименование/смена типа/смысла) — новый ContractVersion = 2 + новый топик pin.crm.lead-created.v2 + dual-publish на период миграции + deadline миграции consumers + sunset .v1.
  • Unknown enum LeadSource — fallback: сохранить строку как есть + warning (карточка/уведомление всё равно обрабатываются). Событие — факт создания (append-only), version-guard потребителю не нужен, только дедуп по MessageId (+ бизнес-ключ у referral).

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

ПолеКласс данныхПравило
LeadId, TenantId, OriginAgentUserId, ExecutorAgentUserId, PrimaryInvestorUserId, ClientIdInternalinclude
Source, ReferralLinkId, CreatedAt, ExpiresAtInternalinclude
PII осознанно исключён

ФИО и телефоны клиента/инвестора в payload не передаются (клиентская база — внутренние данные агентства). Consumers, которым нужны display-данные, берут их из собственной реплики pin.identity.users.v1 и в логах маскируют телефон +7***1234, ФИО — по правилу PII owning-домена.

  • Доступ к топику pin.crm.lead-created.v1 — m2m ACL Kafka (только notifications, referral).
  • Tenant-правило (ADR-0052): лид принадлежит TenantId = AgencyCompanyId; consumers не раскрывают лид другим компаниям. Событие НЕ содержит secrets, tokens, платёжных реквизитов, Wishes, unbounded вложений.

Наблюдаемость

  • Логи (без PII): факт публикации lead-created с LeadId/TenantId/ExecutorAgentUserId/ OriginAgentUserId/Source/ReferralLinkId (идентификаторы, не PII); ФИО/телефон клиента в payload и логах отсутствуют.
  • Метрики: число созданных лидов по топику в разрезе Source; сквозная задержка до notifications/ referral (< 5 мин); доля реф-привязок, подтверждённых referral (закрытие цикла); глубина DLQ (порог алерта > 0); доля повторных доставок.
  • Доступ: топик — m2m ACL Kafka (notifications/referral); лид не раскрывается другим компаниям (TenantId = AgencyCompanyId); Wishes в событие не входит.

Acceptance Criteria

  • Given у пары «инвестор ↔ агент» нет активного лида (INV-CRM-001), When приходит лид-заявка (ConsultationRequest/BookingRequest) / реф-привязка / ручное добавление, Then переход [*] → Active, ровно одно lead-created публикуется с соответствующим Source.
  • Given Source = Referral, When событие обработано, Then ReferralLinkId заполнен, и referral выставляет флаг LeadRequested подтверждённым (корреляция по ReferralLinkId + PrimaryInvestorUserId).
  • Given у пары уже есть активный лид, When повторная попытка создания, Then это идемпотентный no-op — событие не публикуется.
  • Given реактивация Expired → Active (Extend), When лид продлён, Then lead-created не публикуется (это не новый лид).
  • Given повторная доставка события, When referral обрабатывает, Then флаг журнала выставляется один раз (business key ReferralLinkId, PrimaryInvestorUserId).
  • Given неизвестное значение LeadSource, When потребитель обрабатывает, Then строка сохраняется как есть + warning (уведомление/подтверждение всё равно обрабатываются).
  • Given breaking-изменение payload, When новый контракт, Then pin.crm.lead-created.v2 + dual-publish + sunset .v1.

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

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

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