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 type | pin.crm.fixation-approved |
| Topic | pin.crm.fixation-approved.v1 |
| Partitions / key | 3 (низкообъёмная сущность, ADR-0056) / key = AggregateId = FixationRequestId |
| ContractVersion | 1 |
| Producer | crm: одобрение заявки на фиксацию менеджером застройщика (область developer) |
| Статус | draft |
Событие публикуется атомарно с переходом статуса заявки и созданием сделки: пока изменение не
зафиксировано, событие не отправляется; после фиксации — доставляется гарантированно (at-least-once), ключ =
FixationRequestId.
Payload FixationApprovedEvent
Только Guid-ключи + вид одобрения + отметки решения; raw PII (ФИО/телефон клиента) в событие не входят (см. Безопасность). Snapshot-поля ссылаются на дом сущности (fixation-request.md).
| Поле | Тип | Обязательность | Источник (поле агрегата) | Compatibility | Описание |
|---|---|---|---|---|---|
FixationRequestId | Guid | Да | FixationRequestEntity.Id | Immutable | Ключ агрегата (= AggregateId, Kafka key). Одобренная заявка на фиксацию. |
TenantId | Guid | Да | FixationRequestEntity.TenantId | Immutable | DeveloperCompanyId застройщика-адресата; tenant boundary (ADR-0052). |
OriginAgencyCompanyId | Guid | Да | FixationRequestEntity.OriginAgencyCompanyId | Immutable | Агентство-основатель заявки — сторона иммутабельной атрибуции комиссии (rewards). |
OriginAgentUserId | Guid | Да | FixationRequestEntity.OriginAgentUserId | Immutable | Агент-инициатор на момент подачи: историческая атрибуция / антифрод / воронка агентства; основание начисления в rewards. Не переписывается при передаче ведения. |
ExecutorAgentUserId | Guid | Да | FixationRequestEntity.ExecutorAgentUserId | Additive only | Текущий участник-исполнитель заявки на момент одобрения — получатель уведомления «фиксация одобрена». |
CommissionRecipientUserId | Guid | Да | derived (= ExecutorAgentUserId на момент одобрения) | Additive only | Получатель комиссии — Executor на момент одобрения; rewards начисляет комиссию текущему исполнителю, основание — по Origin* (ADR-0071). |
InvestorUserId | Guid | Да | FixationRequestEntity.InvestorUserId | Immutable | Инвестор (клиент), закреплённый за агентом. |
Uniqueness | string (enum FixationApprovalUniqueness) | Да | derived from FixationRequestEntity.Status | Additive only (новые значения) | Вид одобрения; влияет на условия комиссии (см. модель). |
ApprovedByUserId | Guid | Да | FixationRequestEntity.DecidedByUserId | Immutable | Менеджер застройщика, принявший решение об одобрении. |
ApprovedAt | DateTimeOffset | Да | FixationRequestEntity.DecidedAt | Immutable | Момент одобрения (UTC-offset). |
Вложенный enum FixationApprovalUniqueness
Публичный вид решения об одобрении; выводится из FixationStatus и НЕ равен доменному
FixationUniqueness (тот — результат авто-дубль-детекта Unknown|NoDuplicates|HasDuplicates,
fixation-request.md).
| Значение | Источник (FixationStatus) | Ограничения | Описание |
|---|---|---|---|
Unique | FixedUnique | — | Одобрено как уникальный клиент (дублей у застройщика нет). Даёт право на комиссию. |
NonUnique | FixedNonUnique | — | Одобрено как не уникальный (дубль есть). Условия комиссии — по правилам застройщика/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 keyFixationRequestId(+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 — менее выгодный вариант, без ложного начисления).
UniquenessConsumers, встретившие незнакомое значение Uniqueness, сохраняют строку как есть и логируют warning; для
расчёта права на комиссию значение трактуется как NonUnique — менее выгодный вариант, исключающий ложное
начисление.
Безопасность
| Поле | Класс данных | Правило |
|---|---|---|
FixationRequestId, TenantId, OriginAgencyCompanyId, OriginAgentUserId, ExecutorAgentUserId, CommissionRecipientUserId, InvestorUserId, Uniqueness, ApprovedByUserId, ApprovedAt | Internal | include |
ClientName (ФИО), ClientPhoneNumber (телефон) | PII | exclude — в payload не входят; consumers резолвят по своей реплике identity |
Событие НЕ содержит 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), ThenPending → FixedNonUnique, событие сUniqueness = NonUnique. - Given решение
Rejectили отзыв агентомCancel, When обрабатывается, Thenfixation-approvedне публикуется (отклонение — fixation-rejected;Cancel— без события). - Given повторная доставка события, When
rewardsобрабатывает, ThenFixationsApprovedCountинкрементируется один раз (first-seen поFixationRequestId). - Given неизвестное значение
Uniqueness, Whenrewardsрассчитывает право на комиссию, Then трактует его какNonUnique(fail-closed) + warning. - Given breaking-изменение payload, When новый контракт, Then
pin.crm.fixation-approved.v2+ dual-publish + sunset.v1.
Обратные ссылки
Автоссылки: где используется этот документ.
- Домен (CQRS) (2): Entity / Aggregate: NotificationEntity, Entity / Projection: AgentPerformanceEntity
- API (9): GET /api/agent/crm/fixations — Список фиксаций агентства (+ поиск), GET /api/agent/crm/statistics — Статистика агентства/агента, GET /api/developer/crm/fixations — Список фиксаций застройщика (+ FTS), GET /api/pin-manager/crm/fixations — Сквозной список всех фиксаций платформы, GET /api/pin-manager/crm/fixations/{fixationId} — Карточка любой фиксации (Менеджер ПИН), POST /api/agent/crm/fixations — Отправить заявку на фиксацию, POST /api/agent/crm/fixations/{fixationId}/cancel — Отозвать фиксацию, POST /api/developer/crm/fixations/{fixationId}/approve — Одобрить фиксацию (уникальная / не уникальная), POST /api/developer/crm/fixations/{fixationId}/reject — Отклонить фиксацию
- Use Cases (3): UC-FIX-001. Агент отправляет заявку на фиксацию, UC-FIX-002. Застройщик одобряет фиксацию (авторизация работы с клиентом, без создания сделки), UC-FIX-003. Застройщик отклоняет фиксацию
- События (1): Event Contract: pin.crm.fixation-rejected (FixationRejectedEvent)
- Консюмеры (4): Consumer: Chessboard Dimensions Sync (pin-rewards-chessboard-dimensions), Consumer: CRM Deal Completed, Consumer: CRM Fixation Approved, Consumer: DevStatsFunnelDealCompletedConsumer
- scenarios (2): UC-OVR-004. От реферальной ссылки до объекта у собственника, UC-OVR-005. От лида до сделки (4 фазы)
- registries (1): Реестр событий PIN
Связанные документы
- Сущность-дом: fixation-request.md (агрегат,
FixationStatus, INV-FIX-3/6); сделки, авторизованные фиксацией (связь 1:N) — deal.md. - Соседние контракты топиков
crm: fixation-rejected.md, deal-created.md (публикуется при создании сделки агентом, не при одобрении фиксации). - Консюмеры (пути по конвенции): rewards/consumers/crm-fixation-approved.md, notifications/consumers/crm-fixation-approved.md; комиссия по фиксации — rewards/README.md.