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

Event Contract: pin.crm.fixation-approved (FixationApprovedEvent)

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

Назначение

Фиксирует одобрение заявки на фиксацию клиента менеджером застройщика (переход Pending → FixedUnique / Pending → FixedNonUnique, fixation-request.md). Одна одобренная фиксация авторизует агенту создать сколько угодно сделок по объектам застройщика (связь 1:N ведётся со стороны сделки, deal.md).

Событие авторизации, а не создания сделки

Одобрение подтверждает право агента вести клиента по объектам застройщика (пара «клиент × застройщик»), но сделку не создаёт, поэтому событие DealId не несёт.

Публичное: даёт downstream-контекстам факт возникновения права/eligibility и повод для уведомления без синхронного запроса в crm. rewards регистрирует eligibility по фиксации (комиссия материализуется позже — при завершении сделки, pin.crm.deal-completed.v1); notifications шлёт агенту пуш/СМС «фиксация одобрена». Отклонение публикуется отдельным событием fixation-rejected.md; отмена агентом (Cancel) интеграционного события не порождает.

Metadata

ПолеЗначение
Event typepin.crm.fixation-approved
Topicpin.crm.fixation-approved.v1
Partitions / key3 (низкообъёмная сущность, ADR-0056) / key = AggregateId = FixationRequestId
ContractVersion1
Producercrm: одобрение заявки на фиксацию менеджером застройщика (область developer)
Статусdraft

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

Payload FixationApprovedEvent

Только Guid-ключи + вид одобрения + отметки решения; raw PII (ФИО/телефон клиента) в событие не входят (см. Безопасность). Snapshot-поля ссылаются на дом сущности (fixation-request.md).

ПолеТипОбязательностьИсточник (поле агрегата)CompatibilityОписание
FixationRequestIdGuidДаFixationRequestEntity.IdImmutableКлюч агрегата (= AggregateId, Kafka key). Одобренная заявка на фиксацию.
TenantIdGuidДаFixationRequestEntity.TenantIdImmutableDeveloperCompanyId застройщика-адресата; tenant boundary (ADR-0052).
OriginAgencyCompanyIdGuidДаFixationRequestEntity.OriginAgencyCompanyIdImmutableАгентство-основатель заявки — сторона иммутабельной атрибуции комиссии (rewards).
OriginAgentUserIdGuidДаFixationRequestEntity.OriginAgentUserIdImmutableАгент-инициатор на момент подачи: историческая атрибуция / антифрод / воронка агентства; основание начисления в rewards. Не переписывается при передаче ведения.
ExecutorAgentUserIdGuidДаFixationRequestEntity.ExecutorAgentUserIdAdditive onlyТекущий участник-исполнитель заявки на момент одобрения — получатель уведомления «фиксация одобрена».
CommissionRecipientUserIdGuidДаderived (= ExecutorAgentUserId на момент одобрения)Additive onlyПолучатель комиссии — Executor на момент одобрения; rewards начисляет комиссию текущему исполнителю, основание — по Origin* (ADR-0071).
InvestorUserIdGuidДаFixationRequestEntity.InvestorUserIdImmutableИнвестор (клиент), закреплённый за агентом.
Uniquenessstring (enum FixationApprovalUniqueness)Даderived from FixationRequestEntity.StatusAdditive only (новые значения)Вид одобрения; влияет на условия комиссии (см. модель).
ApprovedByUserIdGuidДаFixationRequestEntity.DecidedByUserIdImmutableМенеджер застройщика, принявший решение об одобрении.
ApprovedAtDateTimeOffsetДаFixationRequestEntity.DecidedAtImmutableМомент одобрения (UTC-offset).

Вложенный enum FixationApprovalUniqueness

Публичный вид решения об одобрении; выводится из FixationStatus и НЕ равен доменному FixationUniqueness (тот — результат авто-дубль-детекта Unknown|NoDuplicates|HasDuplicates, fixation-request.md).

ЗначениеИсточник (FixationStatus)ОграниченияОписание
UniqueFixedUniqueОдобрено как уникальный клиент (дублей у застройщика нет). Даёт право на комиссию.
NonUniqueFixedNonUniqueОдобрено как не уникальный (дубль есть). Условия комиссии — по правилам застройщика/rewards.

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

УсловиеПереход состоянияПубликация
Менеджер застройщика одобряет заявку Approve(Unique) / Approve(NonUnique) из Pending (INV-FIX-3); сделка при одобрении не создаётся (INV-FIX-6)Pending → FixedUnique / Pending → FixedNonUniqueатомарно со сменой состояния агрегата
Когда событие НЕ публикуется

Событие не публикуется на Reject (см. fixation-rejected.md) и Cancel (отзыв агентом интеграционного события не порождает). Сделка при одобрении не создаётся, поэтому deal-created в этот момент не публикуется; событие фиксации отвечает за право/eligibility и уведомление агенту.

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

Consumer-контекстSide effectsИдемпотентностьЗадержка (SLA)
rewardsИнкремент FixationsApprovedCount user-centric проекции AgentPerformance по ExecutorAgentUserId (текущий исполнитель; ADR-0061 п.5). Право на комиссию/начисление возникает позже — при завершении сделки (pin.crm.deal-completed.v1), не здесьMessageId + business key FixationRequestId (first-seen)< 1 мин
notificationsПуш/СМС исполнителю (ExecutorAgentUserId) «фиксация одобрена» + переход на карточку фиксацииMessageId< 5 мин

rewards/notifications резолвят ФИО/контакты по собственной реплике pin.identity.users.v1 — raw PII в этом событии не передаётся. Если исполнитель менялся до одобрения (reassign ExecutorAgentUserId), CommissionRecipientUserId несёт нового исполнителя, а OriginAgentUserId/OriginAgencyCompanyId — иммутабельную атрибуцию основателя; rewards начисляет комиссию CommissionRecipientUserId.

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

  • Гарантия публикации. Событие уходит только после фиксации перехода заявки в FixedUnique/ FixedNonUnique (INV-FIX-6); при откате не публикуется. Доставка — at-least-once, ключ FixationRequestId.
  • Один топик на одобрение. Сделка при одобрении не создаётся, поэтому deal-created в этот момент не публикуется; потребители обрабатывают только fixation-approved.
  • Идемпотентность потребителя. rewards — first-seen по business key FixationRequestId (+ MessageId): повторная доставка не задваивает инкремент FixationsApprovedCount; notifications — по MessageId.
  • Retry. Транзиентный сбой потребителя → повтор обработки с backoff; событие доступно до успешной обработки.
  • DLQ. Неустранимый сбой после исчерпания попыток → dead-letter c алертом; проигрывание безопасно (first-seen). При неизвестном Uniqueness право на комиссию трактуется как NonUnique (fail-closed) — без ложного начисления, в DLQ не уходит.

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

  • ContractVersion = 1; при несовпадении версии контракта потребитель логирует предупреждение и продолжает обработку. Топик кодирует версию по конвенции — суффикс .v1.
  • Additive-only для minor: новые поля — optional с безопасным default, без bump.
  • Breaking (удаление/переименование/смена типа/смысла) — ContractVersion = 2 + топик pin.crm.fixation-approved.v2 + dual-publish на период миграции + deadline миграции consumers + sunset .v1.
  • Unknown enum Uniqueness — fallback: сохранить строку как есть, warning; для расчёта права на комиссию трактовать как NonUnique (fail-closed — менее выгодный вариант, без ложного начисления).
подсказка
Fail-closed для неизвестного Uniqueness

Consumers, встретившие незнакомое значение Uniqueness, сохраняют строку как есть и логируют warning; для расчёта права на комиссию значение трактуется как NonUnique — менее выгодный вариант, исключающий ложное начисление.

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

ПолеКласс данныхПравило
FixationRequestId, TenantId, OriginAgencyCompanyId, OriginAgentUserId, ExecutorAgentUserId, CommissionRecipientUserId, InvestorUserId, Uniqueness, ApprovedByUserId, ApprovedAtInternalinclude
ClientName (ФИО), ClientPhoneNumber (телефон)PIIexclude — в payload не входят; consumers резолвят по своей реплике identity
PII в payload отсутствует

Событие НЕ содержит raw PII (ФИО/телефон клиента), secrets, tokens, платёжных данных. Доступ к топику — m2m ACL Kafka (только rewards/notifications). Если ФИО/телефон появятся в связанном логировании producer/consumer — маскирование (ФИО инициалами, телефон +7***1234); в логах события — только Id-поля.

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

  • Логи (без PII): факт публикации fixation-approved с FixationRequestId/ ExecutorAgentUserId/CommissionRecipientUserId/OriginAgentUserId/OriginAgencyCompanyId/Uniqueness/ ApprovedAt (идентификаторы, не PII); ФИО/телефон клиента в payload и логах отсутствуют.
  • Метрики: число одобрений по топику в разрезе Uniqueness; сквозная задержка до rewards (< 1 мин) и notifications (< 5 мин); глубина DLQ (порог алерта > 0); доля повторных доставок.
  • Доступ: топик — m2m ACL Kafka (rewards/notifications); raw PII клиента наружу не покидает домен.

Acceptance Criteria

  • Given заявка на фиксацию в Pending, When менеджер застройщика одобряет Approve(Unique), Then переход Pending → FixedUnique, сделка не создаётся (INV-FIX-6), ровно одно fixation-approved публикуется без DealId с Uniqueness = Unique, CommissionRecipientUserId (= ExecutorAgentUserId на момент одобрения) и атрибуцией OriginAgentUserId/OriginAgencyCompanyId.
  • Given заявка в Pending, When одобрено Approve(NonUnique), Then Pending → FixedNonUnique, событие с Uniqueness = NonUnique.
  • Given решение Reject или отзыв агентом Cancel, When обрабатывается, Then fixation-approved не публикуется (отклонение — fixation-rejected; Cancel — без события).
  • Given повторная доставка события, When rewards обрабатывает, Then FixationsApprovedCount инкрементируется один раз (first-seen по FixationRequestId).
  • Given неизвестное значение Uniqueness, When rewards рассчитывает право на комиссию, Then трактует его как NonUnique (fail-closed) + warning.
  • Given breaking-изменение payload, When новый контракт, Then pin.crm.fixation-approved.v2 + dual-publish + sunset .v1.

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

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

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