Event Contract: pin.rewards.commission-distribution-adjusted (CommissionDistributionAdjustedKafkaEvent)
Версионируемый контракт интеграционного события «распределение начисления скорректировано после получения
денег». Compensating-событие: несёт дельту долей Agency/Agent при per-deal корректировке
распределения (adjust-accrual-distribution.md), когда
начисление уже в статусе MoneyReceived и счета получателей в wallet кредитованы. Дом полей —
entity: CommissionAccrualEntity (строки распределения
CommissionDistributionEntity, INV-11).
Назначение
Фиксирует перераспределение пула агентства между строками Agency и Agent после гейта получения
денег (ADR-0067): руководитель
агентства изменил доли по конкретной сделке, а wallet уже кредитовал счета получателей по старому
распределению (событие получения денег, commission-money-received.md).
Producer — rewards (операция корректировки распределения); событие публичное, потому что wallet
автономно переносит дельту между счетами AgentCommission и AgencyCommission без синхронного запроса в
rewards (ADR-0065), выравнивая балансы под новое деление пула. Строка Platform неприкосновенна, gross и
пул агентства не меняются — переносится только дельта между агентом и агентством, поэтому Σ балансов
получателей остаётся неизменной. Событие публикуется только для корректировок в MoneyReceived; в
Confirmed кошелёк ещё не кредитован и событие не нужно.
Metadata
| Поле | Значение |
|---|---|
| Event type | pin.rewards.commission-distribution-adjusted |
| C# type | CommissionDistributionAdjustedKafkaEvent |
| Topic | pin.rewards.commission-distribution-adjusted.v1 |
| Partitions / key | 3 / key = AccrualId (строгий порядок корректировок per-начисление; объём — единичные back-office правки, ADR-0056) |
| ContractVersion | 1 |
| Producer | rewards: per-deal корректировка распределения начисления в статусе MoneyReceived (adjust-accrual-distribution.md) — по одному событию на каждую корректировку |
| Статус | draft |
Метаданные события: идентификатор сообщения (
MessageId, ключ дедупликации), время (CreatedAt),Version(=ContractVersion),AggregateId = AccrualId,AggregateType = "CommissionAccrual". Событие публикуется атомарно с применением новых долей и инкрементом доменной версии начисления.
Payload CommissionDistributionAdjustedKafkaEvent
Несёт доли Agency/Agent до и после корректировки — потребитель вычисляет дельту и переносит её между
счетами. Строка Platform, CommissionAmount, PlatformFeeAmount в payload не входят (не меняются —
INV-11); реквизиты акта, InvestorUserId, цены объекта недвижимости — тоже не входят (см. «Безопасность»).
| Поле | Тип | Обязательность | Источник (поле агрегата) | Compatibility | Описание |
|---|---|---|---|---|---|
AccrualId | Guid | Да | CommissionAccrualEntity.Id | Immutable | Ключ агрегата (= Kafka key); часть ключа идемпотентности проводки wallet. |
TenantId | Guid | Да | CommissionAccrualEntity.TenantId | Immutable | Агентство-получатель — держатель счёта AgencyCommission (строка Agency). |
AgentUserId | Guid | Да | RecipientUserId строки Agent | Immutable | Агент-исполнитель сделки — держатель счёта AgentCommission (строка Agent). |
OldAgencyAmount | MoneyModel | Да | доля Agency до корректировки | Additive only | Сумма строки Agency до правки (= кредит, уже проведённый wallet). |
NewAgencyAmount | MoneyModel | Да | доля Agency после корректировки | Additive only | Сумма строки Agency после правки. |
OldAgentAmount | MoneyModel | Да | доля Agent до корректировки | Additive only | Сумма строки Agent до правки (= кредит, уже проведённый wallet). |
NewAgentAmount | MoneyModel | Да | доля Agent после корректировки | Additive only | Сумма строки Agent после правки. |
Reason | string | Да | Reason строки корректировки (Kind = Distribution) | Additive only | Обязательная причина корректировки (INV-11); фиксируется в аудите проводки wallet. 1..1000. |
Version | long | Да | CommissionAccrualEntity.Version после корректировки | Immutable semantics | Доменная версия начисления после правки — монотонный guard и часть ключа идемпотентности потребителя. |
Инвариант дельты (следствие INV-11, пул сохраняется): (NewAgencyAmount − OldAgencyAmount) + (NewAgentAmount − OldAgentAmount) = 0 — сколько прибавлено одной стороне, столько снято у другой; строка
Platform и Σ балансов получателей не меняются.
Вложенная модель MoneyModel
Проекция VO Money (commission-accrual.md, раздел «Value objects»);
валюта всех сумм payload едина и равна валюте начисления (INV-6).
| Поле | Тип | Обязательность | Ограничения | Описание |
|---|---|---|---|---|
Value | decimal | Да | >= 0, scale 2 | Сумма. |
CurrencyId | short | Да | ссылка на валюту справочника; RUB-only (ADR-0048) | Типизированная ссылка на валюту. |
CurrencySnapshot | CurrencySnapshot | Да | ../../handbook/domain/snapshots.md | Display-снапшот валюты на момент публикации. |
Когда публикуется
| Условие | Переход состояния | Согласованность |
|---|---|---|
Руководитель агентства скорректировал распределение начисления в статусе MoneyReceived (доли Agency/Agent изменены, adjust-accrual-distribution.md) | статус не меняется (MoneyReceived); Version + 1 | Новые доли, строка корректировки (Kind = Distribution) и публикация — в одном согласованном изменении |
Корректировка в статусе Confirmed (кошелёк ещё не кредитован) событие не публикует. Каждая
корректировка в MoneyReceived даёт ровно одно событие с новым Version; на один AccrualId их может
быть несколько (последовательные правки), различаются по Version.
Потребители (consumers)
| Потребитель | Эффект (событие → действие) | Идемпотентность | Задержка (SLA) |
|---|---|---|---|
wallet | Авто-проводка Adjustment: перенос дельты между холдерскими счетами AgentCommission (AgentUserId) и AgencyCommission (TenantId) — списание у стороны, чья доля уменьшилась, зачисление стороне, чья доля выросла. Consumer — ../../wallet/consumers/rewards-commission-distribution-adjusted.md | MessageId + бизнес-ключ (Adjustment, AccrualId + Version) — повтор события не удваивает перенос | < 5 мин |
Гарантии доставки и порядка
- Доставка — at-least-once;
walletдедуплицирует поMessageIdи бизнес-ключу(Adjustment, AccrualId + Version)— повторная доставка не создаёт второй перенос. - Порядок. Key топика =
AccrualId— последовательные корректировки одного начисления приходят в порядке возрастанияVersion; перестановки между разными начислениями безразличны. - Между топиками порядок не гарантирован. Событие получения денег
(commission-money-received.md, первичный кредит) и это событие (перенос
дельты) — разные топики; корректировка возможна только после
MoneyReceived, то есть первичный кредит бизнес-логически предшествует. Если перенос всё же обгонит кредит, недостаток баланса ловится guard-омwallet(INV-WLT-3) → DLQ + алерт + reconciliation, а не молчаливой потерей. - Неизвестные поля у потребителя игнорируются (additive-политика ниже).
Версионирование и совместимость
- Версия — один
ContractVersion = 1; consumer при несовпадении версии логирует warning и продолжает (upcasting нет). - Additive-only для minor: новые optional-поля с безопасным default — без bump.
- Breaking (удаление/переименование/смена типа/смысла) —
ContractVersion = 2+ новый топикpin.rewards.commission-distribution-adjusted.v2+ dual-publish на период миграции + deadline миграции consumers + sunset старого топика. - Deprecation — по общему sunset-правилу событийного реестра.
Безопасность
| Поле | Класс данных | Правило |
|---|---|---|
AccrualId, TenantId, AgentUserId, Version | Internal | include (адресация переноса) |
OldAgencyAmount, NewAgencyAmount, OldAgentAmount, NewAgentAmount | Sensitive (суммы долей) | include (внутренний топик, m2m ACL Kafka — wallet); в логи потребителей не пишутся |
Reason | Internal | include (аудит проводки); текст причины в логи не пишется |
Реквизиты акта, InvestorUserId, CommissionAmount, PlatformFeeAmount, строка Platform, цены объекта недвижимости | Sensitive/Internal | exclude — к переносу дельты не относятся |
Событие НЕ содержит secrets, PII (ФИО/телефоны), платёжные реквизиты, unbounded-вложения.
Обратные ссылки
Автоссылки: где используется этот документ.
- Домен (CQRS) (1): Entity / Aggregate: CommissionAccrualEntity
- API (2): POST /api/v1/agency/commission-accruals/{accrualId}/adjust-distribution — Per-deal корректировка долей внутри пула, POST /api/v1/agency/commission-adjustment-requests/{requestId}/resolve — Решение по заявке агента на корректировку доли
- Use Cases (1): UC-RWD-013. Агент предлагает корректировку своей доли, руководитель одобряет
- Консюмеры (1): Consumer: Rewards Commission Distribution Adjusted
- Саги (1): Saga «Commission Settlement» (финансовый контур вознаграждений)
- registries (1): Реестр событий PIN
- index.md (2): Rewards Service, Wallet Service
Связанные документы
- Операция-источник: adjust-accrual-distribution.md (per-deal корректировка долей, INV-11).
- Сущность: commission-accrual.md (строки распределения, INV-5/9/10/11).
- Первичный кредит: commission-money-received.md (три строки распределения при получении денег).
- Кошелёк: ../../wallet/consumers/rewards-commission-distribution-adjusted.md,
../../wallet/domain/ledger-transaction.md (операция
Adjustment), ADR-0065. - Контур: ../sagas/commission-settlement-saga.md (компенсация после гейта денег — Σ кредитов сходится).
- Snapshot-модели валюты: ../../handbook/domain/snapshots.md.
- ADR-0067 (гейт получения денег, корректировки), ADR-0066 (три строки распределения).
- Шаблон: event-contract-template.md.