Event Contract: pin.rewards.referral-accrual-status-changed (ReferralAccrualStatusChangedKafkaEvent)
Версионируемый контракт интеграционного события «статус реферального начисления изменился».
Consumer-документы ссылаются сюда, не переописывая payload. Дом полей —
entity: ReferralAccrualEntity.
Назначение
Фиксирует каждый переход Status реферального начисления: авто-апрув по получению денег
(Pending → Approved — регистрация акта поступления средств по родительскому комиссионному
начислению, гейт ADR-0067),
выплату (Approved → Paid — каскад реферального платёжного поручения) и отмену (→ Cancelled с
причиной). Producer — rewards. Потребители: wallet — кредитует счёт ReferralCommission партнёра
при Approved и компенсирует при отмене после апрува (ADR-0065); notifications — адресные
уведомления партнёру без синхронного запроса в rewards.
Metadata
| Поле | Значение |
|---|---|
| Event type | pin.rewards.referral-accrual-status-changed |
| C# type | ReferralAccrualStatusChangedKafkaEvent |
| Topic | pin.rewards.referral-accruals.v1 (общий с ReferralAccrualCreatedKafkaEvent — общий key = строгий порядок событий per-начисление; прецедент двух контрактов в топике — pin.referral.bonds.v1, ../../referral/events/bond-created.md) |
| Partitions / key | 3 / key = Id начисления — строгий порядок переходов per-начисление |
| ContractVersion | 1 |
| Producer | rewards: регистрация акта поступления средств (авто-апрув, api/platform/register-platform-receipt.md — по конвенции), каскад MarkPaid реферального поручения (payout-order.md, INV-7, Kind = ReferralReward), отмена — consumer crm-deal-cancelled.md (DealCancelled) и platform-API api/platform/cancel-referral-accrual.md (по конвенции; BondRevoked/ManualCorrection) |
| Статус | draft |
Метаданные события: идентификатор сообщения (
MessageId, ключ дедупликации), время (CreatedAt),Version(=ContractVersion),AggregateId = Id,AggregateType = "ReferralAccrual". Событие публикуется атомарно с переходом статуса начисления.
Payload ReferralAccrualStatusChangedKafkaEvent
Snapshot-поля — из дома referral-accrual.md. Amount — дублируется в
каждом переходе (текст уведомления и сумма проводки wallet без lookup в rewards).
| Поле | Тип | Обязательность | Источник (поле агрегата) | Compatibility | Описание |
|---|---|---|---|---|---|
Id | Guid | Да | ReferralAccrualEntity.Id | Immutable | Ключ агрегата (= Kafka key); ключ идемпотентности проводок wallet. |
DealId | Guid | Да | ReferralAccrualEntity.DealId | Immutable | Сделка crm — контекст уведомления и трассировка проводок. |
PartnerUserId | Guid | Да | ReferralAccrualEntity.PartnerUserId | Immutable | Партнёр — адресат уведомления; держатель счёта ReferralCommission. |
FromStatus | string (enum ReferralAccrualStatus) | Да | статус до перехода | Additive only (новые значения) | Pending / Approved. |
ToStatus | string (enum ReferralAccrualStatus) | Да | ReferralAccrualEntity.Status после перехода | Additive only | Approved / Paid / Cancelled. |
Amount | MoneyModel | Да | ReferralAccrualEntity.Amount | Additive only | Сумма вознаграждения — проводка wallet и текст уведомления. |
CancelReason | string? (enum ReferralCancelReason) | Да при ToStatus = Cancelled, иначе null | ReferralAccrualEntity.CancelReason | Additive only | DealCancelled / BondRevoked / ManualCorrection. |
ApprovedAt | DateTimeOffset? | Да при ToStatus = Approved, иначе может быть null | ReferralAccrualEntity.ApprovedAt | Additive only | Момент авто-апрува (= момент регистрации акта родителя). |
PaidAt | DateTimeOffset? | Да при ToStatus = Paid, иначе null | ReferralAccrualEntity.PaidAt | Additive only | Момент выплаты (по реферальному поручению). |
Version | long | Да | ReferralAccrualEntity.Version после перехода | Immutable semantics | Доменная версия — монотонный guard потребителя против out-of-order. |
Вложенная модель MoneyModel
Проекция VO Money (commission-accrual.md, раздел «Value objects»).
| Поле | Тип | Обязательность | Ограничения | Описание |
|---|---|---|---|---|
Value | decimal | Да | > 0, scale 2 | Сумма. |
CurrencyId | short | Да | ссылка на валюту справочника; RUB-only (ADR-0048) | Типизированная ссылка на валюту. |
CurrencySnapshot | CurrencySnapshot | Да | ../../handbook/domain/snapshots.md | Display-снапшот валюты на момент публикации. |
Payload не содержит: InvestorUserId (PII приведённого инвестора), BondId,
CommissionAccrualId, BaseAmount, AppliedRateSnapshot — контекст создания опубликован в
referral-accrual-created.md, условия ставок не раскрываются.
Когда публикуется
Каждый переход Status по stateDiagram referral-accrual.md:
| Условие | Переход состояния | Согласованность |
|---|---|---|
Оператор ПИН зарегистрировал акт поступления средств по родительскому комиссионному начислению (platform-receipt.md, каскад INV-RC-4; INV-RA-3 — прямого API-перевода в Approved нет) | Pending → Approved | Акт, переходы начислений в MoneyReceived, авто-апрув рефералок и публикация — в одном согласованном изменении |
Каскад MarkPaid реферального поручения (payout-order.md, INV-7, Kind = ReferralReward) | Approved → Paid | Поручение, позиции, начисления и публикация — в одном согласованном изменении |
Consumer pin.crm.deal-cancelled.v1 отменил начисление (crm-deal-cancelled.md) | Pending → Cancelled (CancelReason = DealCancelled) | Начисление, отметка идемпотентности и публикация — в одном согласованном изменении |
Оператор ПИН отменил начисление (platform-API api/platform/cancel-referral-accrual.md — по конвенции, permission rewards.accruals.manage) | Pending → Cancelled / Approved → Cancelled (CancelReason = BondRevoked / ManualCorrection; из Approved — только пока начисление свободно, INV-RA-5) | Начисление и публикация — в одном согласованном изменении |
Создание начисления этим контрактом не публикуется — см. referral-accrual-created.md.
Потребители (consumers)
| Потребитель | Эффект (событие → действие) | Идемпотентность | Задержка (SLA) |
|---|---|---|---|
wallet | По ToStatus (ADR-0065): Approved — кредит счёта ReferralCommission партнёра на Amount; Cancelled при FromStatus = Approved — компенсирующая корректировка (Correction) ранее выполненного кредита; Paid — no-op (дебет счёта выполняется по payout-order-status-changed.md); Cancelled из Pending — no-op (кредита не было). Consumer — ../../wallet/consumers/rewards-referral-accrual-status-changed.md (по конвенции) | MessageId + бизнес-ключ операции (вид операции + Id начисления) — повтор не удваивает проводки; порядок — key = Id + Version-guard | < 5 мин |
notifications | Уведомления партнёру (PartnerUserId) по ToStatus: Approved — «вознаграждение подтверждено к выплате (деньги от застройщика получены)»; Paid — «вознаграждение выплачено»; Cancelled — «начисление отменено» (CancelReason маппится в человекочитаемый текст) | MessageId; порядок — key = Id + Version-guard | < 5 мин |
Гарантии доставки и порядка
- Доставка — at-least-once;
walletдедуплицирует поMessageIdи бизнес-ключу операции,notifications— поMessageId. - Порядок внутри топика — строгий per-начисление (общий key =
Idс referral-accrual-created.md): переходы приходят строго послеcreatedи в причинном порядке между собой; monotonic-guard — поVersion(out-of-order переход отбрасывается как устаревший). - Между топиками порядок не гарантирован.
Approvedпубликуется в одном коммите с commission-money-received.md и commission-accrual-status-changed (→ MoneyReceived) — топики разные, взаимного порядка нет; кредит реферального счётаwalletвыполняет только по этому топику (кредиты комиссионных счетов — поcommission-money-received), двойной кредит исключён разными бизнес-ключами операций.Paidпубликуется в одном коммите с payout-order-status-changed.md — дебет выполняется только по топику поручений. - Гонки переходов (авто-апрув vs отмена, отмена vs включение в поручение) разрешаются на стороне агрегата (referral-accrual.md, «Конкурентность») — в топик попадает только победивший переход.
- Неизвестные поля у потребителя игнорируются (additive-политика ниже).
Версионирование и совместимость
- Версия — один
ContractVersion = 1; consumer при несовпадении версии логирует warning и продолжает (upcasting нет). - Additive-only для minor: новые optional-поля с безопасным default и новые значения enum — без bump.
- Breaking (удаление/переименование/смена типа/смысла) —
ContractVersion = 2+ новый топикpin.rewards.referral-accruals.v2(мигрируют оба контракта топика) + dual-publish на период миграции + deadline миграции consumers + sunset старого топика. - Unknown enum
FromStatus/ToStatusу потребителя:wallet— сообщение в DLQ + алерт (проводка по неизвестному переходу не выполняется молча);notifications— уведомление не отправляется, warning + метрика (fail-safe). UnknownCancelReason— уведомление с нейтральным текстом «начисление отменено». - Deprecation — по общему sunset-правилу событийного реестра.
Безопасность
| Поле | Класс данных | Правило |
|---|---|---|
Id, DealId, PartnerUserId, FromStatus, ToStatus, ApprovedAt, PaidAt, Version | Internal | include |
Amount | Sensitive (суммы вознаграждений) | include (внутренний топик, m2m ACL Kafka — wallet/notifications); в логи потребителей не пишется; в уведомлении сумма видна только партнёру |
CancelReason | Internal | include; подробности разбора (комментарии оператора) в payload не входят — остаются в rewards |
InvestorUserId, BondId, CommissionAccrualId, BaseAmount, AppliedRateSnapshot | PII/Sensitive/Internal | exclude |
Событие НЕ содержит secrets, PII (ФИО/телефоны), платёжные реквизиты, unbounded-вложения.
Обратные ссылки
Автоссылки: где используется этот документ.
- Домен (CQRS) (2): Entity / Aggregate: PlatformReceiptEntity, Entity / Aggregate: ReferralAccrualEntity
- API (3): POST /api/v1/platform/receipts/{receiptId}/register — Регистрация акта поступления средств, POST /api/v1/platform/referral-accruals/{accrualId}/cancel — Ручная отмена реферального начисления, POST /api/v1/platform/referral-payout-orders/{orderId}/mark-paid — Отметка о выплате реферального поручения
- Use Cases (4): UC-RWD-009. Жизненный цикл реферального начисления (связь → начисление → гейт → выплата), UC-RWD-014. ПИН корректирует размер реферального вознаграждения партнёра, US-реестр: Реферальный партнёр (US-PRT), US-реестр: Финансовый блок ПИН (US-FIN)
- События (3): Event Contract: pin.rewards.commission-money-received (CommissionMoneyReceivedKafkaEvent), Event Contract: pin.rewards.payout-order-status-changed (PayoutOrderStatusChangedKafkaEvent), Event Contract: pin.rewards.referral-accrual-created (ReferralAccrualCreatedKafkaEvent)
- Консюмеры (1): Consumer: Rewards Referral Accrual Status Changed
- registries (1): Реестр событий PIN
- index.md (1): Rewards Service
Связанные документы
- Сущность: referral-accrual.md (stateDiagram, INV-RA-3/5, конкурентность переходов).
- Создание: referral-accrual-created.md (тот же топик).
- Гейт денег: platform-receipt.md (каскад авто-апрува INV-RC-4), commission-money-received.md.
- Выплата: payout-order.md (
Kind = ReferralReward, каскад INV-7), payout-order-status-changed.md (дебетwallet). - Отмена по сделке: crm-deal-cancelled.md.
- Кошелёк:
../../wallet/consumers/rewards-referral-accrual-status-changed.md(по конвенции), ADR-0065. - Snapshot-модели валюты: ../../handbook/domain/snapshots.md.
- Шаблон: event-contract-template.md.