Event Contract: pin.rewards.referral-accrual-created (ReferralAccrualCreatedKafkaEvent)
Версионируемый контракт интеграционного события «реферальное вознаграждение начислено».
Consumer-документы ссылаются сюда, не переописывая payload. Дом полей —
entity: ReferralAccrualEntity.
Назначение
Фиксирует создание реферального начисления (referral-accrual.md,
[*] → Pending) по завершённой сделке приведённого инвестора: партнёр узнаёт, что вознаграждение
начислено и ожидает получения денег от застройщика (гейт
ADR-0067). Producer — rewards
(реферальная ветка consumer-а завершения сделки); событие публичное, потому что notifications
уведомляет партнёра без синхронного запроса в rewards. Переходы статуса — соседним контрактом
referral-accrual-status-changed.md того же топика.
Metadata
| Поле | Значение |
|---|---|
| Event type | pin.rewards.referral-accrual-created |
| C# type | ReferralAccrualCreatedKafkaEvent |
| Topic | pin.rewards.referral-accruals.v1 (общий с ReferralAccrualStatusChangedKafkaEvent — общий key = строгий порядок событий per-начисление; прецедент двух контрактов в топике — pin.referral.bonds.v1, ../../referral/events/bond-created.md) |
| Partitions / key | 3 / key = Id начисления (объём — доли завершённых сделок, ADR-0056) |
| ContractVersion | 1 |
| Producer | rewards: реферальная ветка consumer-а crm-deal-completed.md (активная связь + резолвленная ставка, referral-rate-rule.md) |
| Статус | draft |
Метаданные события: идентификатор сообщения (
MessageId, ключ дедупликации), время (CreatedAt),Version(=ContractVersion),AggregateId = Id,AggregateType = "ReferralAccrual". Событие публикуется атомарно с созданием начисления.
Payload ReferralAccrualCreatedKafkaEvent
Snapshot-поля ссылаются на дом referral-accrual.md — перечисляется
только то, что реально в событии. InvestorUserId, CommissionAccrualId, BaseAmount и
AppliedRateSnapshot в payload не входят (см. «Безопасность»).
| Поле | Тип | Обязательность | Источник (поле агрегата) | Compatibility | Описание |
|---|---|---|---|---|---|
Id | Guid | Да | ReferralAccrualEntity.Id | Immutable | Ключ агрегата (= Kafka key). |
DealId | Guid | Да | ReferralAccrualEntity.DealId | Immutable | Сделка crm — основание начисления (одно начисление на сделку, INV-RA-1). |
BondId | Guid | Да | ReferralAccrualEntity.BondId | Immutable | Реферальная связь — основание начисления (../../referral/domain/referral-bond.md). |
PartnerUserId | Guid | Да | ReferralAccrualEntity.PartnerUserId | Immutable | Партнёр — получатель вознаграждения; адресат уведомления. |
DeveloperCompanyId | Guid | Да | ReferralAccrualEntity.DeveloperCompanyId | Immutable | Застройщик сделки (измерение резолюции ставки). |
Amount | MoneyModel | Да | ReferralAccrualEntity.Amount | Additive only | Сумма вознаграждения (FinalPrice × Percent / 100, INV-RA-2). |
Status | string (enum ReferralAccrualStatus) | Да | ReferralAccrualEntity.Status | Additive only (новые значения) | Всегда Pending в v1 (создание — единственная точка публикации); переходы — соседним контрактом referral-accrual-status-changed.md. |
DealCompletedAt | DateTimeOffset | Да | ReferralAccrualEntity.DealCompletedAt | Immutable | Момент завершения сделки (= asOf резолюции ставки). |
Version | long | Да | ReferralAccrualEntity.Version | Immutable semantics | Доменная версия — монотонный guard потребителя (события created и status-changed одного топика упорядочены key-ом). |
Вложенная модель 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-снапшот валюты на момент публикации. |
Когда публикуется
| Условие | Переход состояния | Согласованность |
|---|---|---|
Реферальная ветка consumer-а завершения сделки создала начисление (crm-deal-completed.md): у инвестора активная связь, guard самореферала пройден (INV-RA-4), ставка резолвлена на CompletedAt | [*] → Pending | начисление, отметка идемпотентности и событие — в одном согласованном изменении |
Skip-ветки consumer-а (нет активной связи, самореферал, ставка не найдена, дубль DealId) события
не публикуют.
Потребители (consumers)
| Потребитель | Эффект (событие → действие) | Идемпотентность | Задержка (SLA) |
|---|---|---|---|
notifications | Уведомление партнёру (PartnerUserId): «начислено реферальное вознаграждение по сделке приведённого клиента, ожидает поступления денег» | MessageId | < 5 мин |
wallet этот контракт не потребляет: кредит счёта ReferralCommission выполняется только по
переходу Approved соседнего контракта
(referral-accrual-status-changed.md, ADR-0065) — до прохождения
гейта денег начисление балансов не меняет.
Гарантии доставки и порядка
- Доставка — at-least-once; потребитель дедуплицирует по
MessageId. - Порядок внутри топика — строгий per-начисление (общий key =
Idс referral-accrual-status-changed.md):createdприходит строго раньше любых переходов того же начисления; дополнительный monotonic-guard — поVersion. - Единственность. На один
Id— ровно одноcreated(единственная точка публикации — создание; повтор события-источника упирается в идемпотентность поDealId, INV-RA-1). - Неизвестные поля у потребителя игнорируются (additive-политика ниже).
Версионирование и совместимость
- Версия — один
ContractVersion = 1; consumer при несовпадении версии логирует warning и продолжает (upcasting нет). - Additive-only для minor: новые optional-поля с безопасным default — без bump.
- Breaking (удаление/переименование/смена типа/смысла) —
ContractVersion = 2+ новый топикpin.rewards.referral-accruals.v2(мигрируют оба контракта топика) + dual-publish на период миграции + deadline миграции consumers + sunset старого топика. - Unknown enum
Statusу потребителя — fallback: трактовать какPending+ warning. - Deprecation — по общему sunset-правилу событийного реестра.
Безопасность
| Поле | Класс данных | Правило |
|---|---|---|
Id, DealId, BondId, PartnerUserId, DeveloperCompanyId, Status, DealCompletedAt, Version | Internal | include |
Amount | Sensitive (суммы вознаграждений) | include (внутренний топик, m2m ACL Kafka); в логи потребителей не пишется; в уведомлении сумма видна только партнёру |
InvestorUserId | PII (приведённый инвестор, referral-accrual.md) | exclude — в payload не входит |
BaseAmount (цена сделки), AppliedRateSnapshot, CommissionAccrualId | Sensitive/Internal | exclude — условия ставок и связка с комиссионным начислением не раскрываются потребителям |
Событие НЕ содержит secrets, tokens, PII (ФИО/телефоны), платёжные реквизиты, unbounded-вложения.
Обратные ссылки
Автоссылки: где используется этот документ.
- Домен (CQRS) (1): Entity / Aggregate: ReferralAccrualEntity
- Use Cases (2): UC-RWD-009. Жизненный цикл реферального начисления (связь → начисление → гейт → выплата), US-реестр: Реферальный партнёр (US-PRT)
- События (1): Event Contract: pin.rewards.referral-accrual-status-changed (ReferralAccrualStatusChangedKafkaEvent)
- Консюмеры (1): Consumer: Rewards Referral Accrual Status Changed
- registries (1): Реестр событий PIN
- index.md (1): Rewards Service
Связанные документы
- Сущность: referral-accrual.md (дом полей, stateDiagram, INV-RA-1..5); ставка: referral-rate-rule.md.
- Источник: crm-deal-completed.md (реферальная ветка);
основание — ../../referral/events/bond-created.md, реплика
связей — consumer
../consumers/referral-bond.md(по конвенции). - Соседний контракт топика:
referral-accrual-status-changed.md (переходы
Approved/Paid/Cancelled). - Гейт денег: platform-receipt.md, commission-money-received.md.
- Snapshot-модели валюты: ../../handbook/domain/snapshots.md.
- Шаблон: event-contract-template.md.