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

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 typepin.rewards.referral-accrual-status-changed
C# typeReferralAccrualStatusChangedKafkaEvent
Topicpin.rewards.referral-accruals.v1 (общий с ReferralAccrualCreatedKafkaEvent — общий key = строгий порядок событий per-начисление; прецедент двух контрактов в топике — pin.referral.bonds.v1, ../../referral/events/bond-created.md)
Partitions / key3 / key = Id начисления — строгий порядок переходов per-начисление
ContractVersion1
Producerrewards: регистрация акта поступления средств (авто-апрув, 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Описание
IdGuidДаReferralAccrualEntity.IdImmutableКлюч агрегата (= Kafka key); ключ идемпотентности проводок wallet.
DealIdGuidДаReferralAccrualEntity.DealIdImmutableСделка crm — контекст уведомления и трассировка проводок.
PartnerUserIdGuidДаReferralAccrualEntity.PartnerUserIdImmutableПартнёр — адресат уведомления; держатель счёта ReferralCommission.
FromStatusstring (enum ReferralAccrualStatus)Дастатус до переходаAdditive only (новые значения)Pending / Approved.
ToStatusstring (enum ReferralAccrualStatus)ДаReferralAccrualEntity.Status после переходаAdditive onlyApproved / Paid / Cancelled.
AmountMoneyModelДаReferralAccrualEntity.AmountAdditive onlyСумма вознаграждения — проводка wallet и текст уведомления.
CancelReasonstring? (enum ReferralCancelReason)Да при ToStatus = Cancelled, иначе nullReferralAccrualEntity.CancelReasonAdditive onlyDealCancelled / BondRevoked / ManualCorrection.
ApprovedAtDateTimeOffset?Да при ToStatus = Approved, иначе может быть nullReferralAccrualEntity.ApprovedAtAdditive onlyМомент авто-апрува (= момент регистрации акта родителя).
PaidAtDateTimeOffset?Да при ToStatus = Paid, иначе nullReferralAccrualEntity.PaidAtAdditive onlyМомент выплаты (по реферальному поручению).
VersionlongДаReferralAccrualEntity.Version после переходаImmutable semanticsДоменная версия — монотонный guard потребителя против out-of-order.

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

Проекция VO Money (commission-accrual.md, раздел «Value objects»).

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

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). Unknown CancelReason — уведомление с нейтральным текстом «начисление отменено».
  • Deprecation — по общему sunset-правилу событийного реестра.

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

ПолеКласс данныхПравило
Id, DealId, PartnerUserId, FromStatus, ToStatus, ApprovedAt, PaidAt, VersionInternalinclude
AmountSensitive (суммы вознаграждений)include (внутренний топик, m2m ACL Kafka — wallet/notifications); в логи потребителей не пишется; в уведомлении сумма видна только партнёру
CancelReasonInternalinclude; подробности разбора (комментарии оператора) в payload не входят — остаются в rewards
InvestorUserId, BondId, CommissionAccrualId, BaseAmount, AppliedRateSnapshotPII/Sensitive/Internalexclude

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

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

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

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