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

Event Contract: pin.rewards.commission-accrual-created

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

Назначение

Фиксирует создание начисления комиссии по завершённой сделке: агент и его агентство узнают, что комиссия начислена и ожидает подтверждения застройщиком, а crm отмечает факт начисления в таймлайне сделки. Producer — rewards; событие публичное, потому что потребителям (notifications, crm) не нужен синхронный запрос в rewards для реакции на факт начисления. Сводки ЛК агента/агентства («получим/получили × подтверждено/ожидает») события не потребляют — они читаются SQL-агрегациями по PostgreSQL rewards (решение №6 ../README.md, ADR-0056).

Metadata

ПолеЗначение
Event typepin.rewards.commission-accrual-created
Topicpin.rewards.commission-accrual-created.v1
Partitions / key3 / key = Id начисления (объём — число завершённых сделок, ADR-0056)
ContractVersion1
Producerrewards: consumer crm-deal-completed.md (автоначисление), admin-API api/admin/create-manual-accrual.md (ручное начисление застройщиком, по конвенции)
Статусdraft

Метаданные события: идентификатор сообщения (MessageId, ключ дедупликации), время (CreatedAt), Version (= ContractVersion), AggregateId = Id, AggregateType = "CommissionAccrual". Событие публикуется атомарно с созданием начисления.

Payload CommissionAccrualCreatedKafkaEvent

Snapshot-поля ссылаются на дом commission-accrual.md — перечисляется только то, что реально в событии. InvestorUserId, цены объекта недвижимости (BasePriceAmount/FinalPriceAmount), CommissionPercent, AppliedRuleSnapshot и AppliedPlatformTermsId в payload не входят (см. «Безопасность»).

ПолеТипОбязательностьИсточник (поле агрегата)CompatibilityОписание
IdGuidДаCommissionAccrualEntity.IdImmutableКлюч агрегата (= Kafka key).
TenantIdGuidДаCommissionAccrualEntity.TenantIdImmutableАгентство-получатель комиссии (tenant boundary, решение №2 README).
DealIdGuidДаCommissionAccrualEntity.DealIdImmutableСделка crm — ключ привязки таймлайна.
DeveloperCompanyIdGuidДаCommissionAccrualEntity.DeveloperCompanyIdImmutableЗастройщик — подтверждающая сторона.
AgentUserIdGuidДаCommissionAccrualEntity.AgentUserIdImmutableАгент — адресат уведомления «комиссия начислена».
PropertyObjectIdGuidДаCommissionAccrualEntity.PropertyObjectIdImmutableОбъект недвижимости (chessboard) — контекст уведомления.
CommissionAmountMoneyModelДаCommissionAccrualEntity.CommissionAmountAdditive onlyНачисленная gross-сумма комиссии.
PlatformFeeAmountMoneyModelДаCommissionAccrualEntity.PlatformFeeAmountAdditive onlyУдержание ПИН (INV-10, ADR-0066); 0 при fallback без условий. Пул агентства = CommissionAmount − PlatformFeeAmount.
PlatformRetentionPercentagePointsdecimalДаCommissionAccrualEntity.PlatformRetentionPercentagePointsAdditive onlyУдержание ПИН в процентных пунктах ставки застройщика (снапшот условий на DealCompletedAt; 0 — fallback).
Statusstring (enum CommissionAccrualStatus)ДаCommissionAccrualEntity.StatusAdditive only (новые значения)Всегда PendingConfirmation в v1 (создание — единственная точка публикации); переходы — соседним событием commission-accrual-status-changed.md.
DealCompletedAtDateTimeOffsetДаCommissionAccrualEntity.DealCompletedAtImmutableМомент завершения сделки (для текста уведомления/сортировки).

Вложенная модель MoneyModel

Проекция VO Money (commission-accrual.md, раздел «Value objects»); валюта всех сумм payload едина (INV-6).

ПолеТипОбязательностьОграниченияОписание
ValuedecimalДа>= 0, scale 2Сумма.
CurrencyIdshortДассылка на валюту справочника; RUB-only (ADR-0048)Типизированная ссылка на валюту.
CurrencySnapshotCurrencySnapshotДа../../handbook/domain/snapshots.mdDisplay-снапшот валюты на момент публикации.

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

УсловиеПереход состоянияСогласованность
Consumer завершения сделки создал начисление (crm-deal-completed.md)[*] → PendingConfirmationначисление, отметка идемпотентности и событие — в одном согласованном изменении
Менеджер застройщика создал ручное начисление (api/admin/create-manual-accrual.md, по конвенции; AppliedRuleId = null)[*] → PendingConfirmationначисление и событие — в одном согласованном изменении

Skip-ветки consumer-а (нет агента, нет правила, дубль DealId) события не публикуют.

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

Consumer-контекстЭффект (side effects)ИдемпотентностьЗадержка (SLA)
notificationsУведомление агенту (AgentUserId) и руководителю агентства (TenantId, роль с rewards.commission.view-all): «начислена комиссия по сделке, ожидает подтверждения застройщиком»MessageId< 5 мин
crmЗапись в таймлайн сделки DealId (deal-timeline-event, тип «комиссия начислена»)MessageId + business key (DealId, Id)< 5 мин
rewards (self)Наполнение user-centric проекции AgentPerformance (ADR-0061 п.5): DealsWonCount += 1, CommissionAccruedTotal += CommissionAmountMessageId + факт Id< 5 мин

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

  • Доставка — at-least-once; каждый потребитель дедуплицирует по MessageId (плюс бизнес-ключ, где указан), поэтому повторная доставка эффектов не удваивает.
  • Порядок. Событие создаётся один раз на начисление (точка публикации — только [*] → PendingConfirmation), поэтому внутри топика для данного Id оно единственное; между этим топиком и commission-accrual-status-changed.v1 сквозного порядка нет — переход статуса причинно следует за созданием, но технически может прийти раньше. Потребитель, читающий оба топика (self-проекция AgentPerformance), обязан быть к этому устойчив: дельты идемпотентны по Id, а счётчики защищены нижней границей (см. agent-performance.md, раздел о согласованности).
  • Атомарность. Публикация — в одном согласованном изменении с созданием начисления; skip-ветки consumer-а событие не публикуют, поэтому «пустых» уведомлений не бывает.
  • Неизвестные поля у потребителя игнорируются (additive-политика ниже).

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

  • Версия — один ContractVersion = 1; consumer при несовпадении версии логирует warning и продолжает (upcasting нет).
  • Additive-only для minor: новые optional-поля с безопасным default — без bump.
  • Breaking (удаление/переименование/смена типа/смысла) — ContractVersion = 2 + новый топик pin.rewards.commission-accrual-created.v2 + dual-publish на период миграции + deadline миграции consumers + sunset старого топика.
  • Unknown enum Status у потребителя — fallback: трактовать как PendingConfirmation + warning.
  • Deprecation — по общему sunset-правилу событийного реестра.

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

ПолеКласс данныхПравило
Id, TenantId, DealId, DeveloperCompanyId, AgentUserId, PropertyObjectId, Status, DealCompletedAtInternalinclude
CommissionAmount, PlatformFeeAmount, PlatformRetentionPercentagePointsSensitive (суммы комиссий и удержания ПИН, README «Безопасность»)include в payload (внутренний топик, m2m ACL Kafka); потребители не пишут суммы в логи; в уведомлении сумма видна только адресату
InvestorUserIdInternal (маскируется в проекциях агентства)exclude — в payload не входит
Цены объекта недвижимости, CommissionPercent, AppliedRuleSnapshot, AppliedPlatformTermsIdSensitive/Internalexclude — условия правил застройщика и условий платформы не раскрываются потребителям

Событие НЕ содержит secrets, tokens, raw credentials, PII (ФИО/телефоны), платёжные реквизиты, unbounded-вложения.

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

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

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