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

Rewards Service

Назначение

rewards владеет финансовым контуром вознаграждений платформы PIN: правилами вознаграждений застройщиков (процент от базовой или конечной цены с условиями-предикатами), условиями платформенной комиссии (удержание ПИН в процентных пунктах ставки, ADR-0066), начислениями комиссий по завершённым сделкам CRM (статусы «ожидает подтверждения / подтверждено / деньги получены / выплачено», распределение тремя строками Platform/Agency/Agent), комиссионной политикой агентства (деление пула на агента и агентство), реферальными ставками и реферальными начислениями партнёрам (ADR-0066), актами поступления средств — гейтом всех выплат (ADR-0067), first-class корректировками сумм и долей, платёжными поручениями (агентскими и реферальными) с историей выплат (исполнение платежей — реализация отложена, решение №9) и Excel-выгрузками агентства (ADR-0041). Также отдаёт catalog расчёт «сколько заработает агент на объекте недвижимости» (gross + net после удержания ПИН) и сводки комиссий для ЛК агента/агентства; балансы получателей ведёт смежный контекст wallet по событиям rewards (ADR-0065).

Metadata

ПолеЗначение
Статусdraft
Owning teamPIN Platform (backend)
DomainКаталог и деньги (market, см. service-boundaries.md)
Data classificationSensitive (суммы комиссий/выплат) + Internal (правила)
Runtime criticalitymedium (деньги считаются асинхронно; недоступность не блокирует сделки)

Ownership

ArtifactOwner/Rule
PostgreSQL schemarewards
API areasdeveloper-admin (правила, подтверждение начислений ± корректировка), agency (политика, поручения, сводки, per-deal корректировка долей, Excel-выгрузки), agent (мои комиссии + личная user-centric статистика), partner (мои реферальные начисления), platform (условия платформы, реферальные ставки, акты поступления, gross-корректировки, реферальные поручения — Менеджер/оператор ПИН), internal (расчёт комиссии для catalog). Реестр операций — api/README.md
Owned entitiesRewardRuleEntity, CommissionAccrualEntity (+CommissionDistributionEntity, +CommissionAccrualAdjustmentEntity), AgencyCommissionPolicyEntity, PayoutOrderEntity (+PayoutOrderItemEntity), PlatformCommissionTermsEntity, ReferralRateRuleEntity, ReferralAccrualEntity (+ReferralAccrualAdjustmentEntity), PlatformReceiptEntity (+PlatformReceiptItemEntity), AgentPerformanceEntity (user-centric read-проекция, ADR-0061 п.5); реплика связей rewards.referral_bond_replicas (consumers/referral-bond.md)
Produced eventspin.rewards.commission-rules.v1, pin.rewards.reward-rule-changed.v1, pin.rewards.commission-accrual-created.v1, pin.rewards.commission-accrual-status-changed.v1, pin.rewards.commission-money-received.v1, pin.rewards.referral-accruals.v1, pin.rewards.payout-order-status-changed.v1
Consumed eventspin.crm.deal-completed.v1, pin.crm.deal-cancelled.v1, pin.referral.bonds.v1 (реплика реферальных связей), pin.crm.fixation-approved.v1 (счётчик фиксаций проекции), pin.identity.agent-membership-changed.v1 (состояние членства проекции), pin.chessboard.layout-upserted.v1 + pin.chessboard.layout-group-upserted.v1 (реплика справочника планировок); self-consume pin.rewards.commission-accrual-created.v1 / -status-changed.v1 для наполнения проекции AgentPerformance
Search indexesnone
Analytics factsnone (агрегации сводок — SQL по PostgreSQL, ADR-0056)

Ответственность И Границы

  • Что сервис делает: CRUD и активация правил вознаграждений застройщика; детерминированный подбор правила для объекта недвижимости; условия платформенной комиссии (удержание ПИН 0.25–1.50 п.п., per-agency + глобальный дефолт, asOf-резолюция и снапшот в начисление — ADR-0066); создание начислений по deal-completed (комиссионного и реферального — двумя ветками одного consumer-а); подтверждение начислений застройщиком (± корректировка суммы) с распределением тремя строками Platform/Agency/Agent (пул агентства делит политика); реферальные ставки (4 уровня специфичности, сроки действия) и реферальные начисления партнёрам; акты поступления средств — гейт MoneyReceived всех выплат (ADR-0067); first-class корректировки gross и долей с обязательной причиной и append-only аудитом; формирование/утверждение/отметка выплаты платёжных поручений двух видов (AgencyCommission / ReferralReward); сводки «получим/получили × подтверждено/ожидает/деньги получены» для ЛК агента и агентства; Excel-выгрузки агентства (два отчёта, async job + signed URL, ADR-0041); внутренний расчёт комиссии по объекту недвижимости для catalog (gross + удержание ПИН + пул); личная user-centric статистика агента — перестраиваемая проекция AgentPerformance (агрегация по AgentUserId сквозь все компании: одобренные фиксации, закрытые/сорванные сделки, начислено/выплачено, достижения; сохраняется при смене агентства, ADR-0061 п.5).
  • Что сервис не делает: не проводит платежи (исполнение отложено — ручная отметка MarkPaid); не хранит банковские реквизиты (дом — profile); не ведёт балансы получателей — кошельки и ledger живут в контексте wallet и наполняются событиями rewards (ADR-0065); не владеет фактом реферальной связи «кто кого привёл» (дом — referral; в rewards — реплика и деньги); не владеет сделками (crm), объектами недвижимости/планировками (chessboard), пользователями/компаниями/членством (identity); не пересчитывает исторические снапшоты AgencyCompanyId/AgentUserId сделок/лидов/фиксаций (иммутабельны, дом — crm, ADR-0061 п.4); agency-centric статистика воронки агентства (счётчики сделок в границах текущего агентства) — дом crm (get-statistics.md); здесь денежные сводки и user-centric проекция агента.
  • Source of truth: правила вознаграждений, условия платформы, реферальные ставки, начисления (комиссионные и реферальные) с распределениями и корректировками, акты поступления, политики агентств, платёжные поручения. Проекция AgentPerformanceпроизводна (не source of truth), перестраивается реплеем событий.
  • Реплики/projections: справочник планировок Layout/LayoutGroup (id + принадлежность застройщику, консюмер consumers/chessboard-dimensions.md) — только для валидации условий правил; реферальные связи rewards.referral_bond_replicas (консюмер consumers/referral-bond.md) — основание реферальных начислений.

Зависимости

ЗависимостьТипЗачем НужнаFailure mode
PostgreSQL (schema rewards)dbВсе агрегаты, outboxНедоступность = отказ API/consumer-ов; Kafka-события накапливаются, обработка догоняет
KafkaqueueConsume crm/chessboard; produce события начислений/порученийLag = задержка начислений; идемпотентность по DealId защищает от дублей
crmservice (events)Источник завершённых/отменённых сделок с ценами и участниками; одобренные фиксации (pin.crm.fixation-approved.v1) для счётчика проекции AgentPerformanceНет событий → нет новых начислений/счётчиков; ручное начисление доступно
referralservice (events)Факт реферальной связи «кто кого привёл» (pin.referral.bonds.v1) → реплика связей — основание реферальных начисленийЛаг синка → сделка обработана без рефералки; исправление — replay после догона реплики
walletconsumer наших событийБалансы получателей: кредиты по commission-money-received/referral-accruals (Approved), дебеты по payout-order-status-changed (Paid) (ADR-0065)Лаг consumer-а → баланс отстаёт от статусов rewards (окно секунды); данные rewards не затронуты
chessboardservice (events)Справочник Layout/LayoutGroup для валидации условий правилУстаревшая реплика → активация правила с новой планировкой отклонится до прихода синка
identityservice (JWT/permissions + events)Акторы, tenant, permissions, состав пользователей агентства (валидация оверрайдов политики); события членства агента pin.identity.agent-membership-changed.v1 — текущее состояние членства (в агентстве/независимый) в проекции AgentPerformance (ADR-0061 п.5)Нет авторизации → API недоступно; лаг membership-событий → устаревшее состояние членства в проекции (метрики не затронуты)
catalogconsumer нашего API/событийПоказ комиссии агенту в витринеНедоступность rewards → каталог скрывает блок комиссии (graceful)
notificationsconsumer наших событийУведомления о начислении/подтверждении/выплатеПотеря уведомлений не влияет на данные

Проекты

src/services/rewards/
Pin.Rewards.Api/
Pin.Rewards.Application/
Pin.Rewards.Domain/
Pin.Rewards.Infrastructure/
Pin.Rewards.Background/
Pin.Rewards.Migrator/
Pin.Rewards.Contracts/

Основные Сущности

EntityНазначениеSource Of TruthДокумент
RewardRuleEntityПравило вознаграждения застройщика: база (базовая/конечная цена), процент, условия-предикаты (тип объекта/Layout/LayoutGroup/комнаты/площадь), приоритет, периодrewardsdomain/reward-rule.md
PlatformCommissionTermsEntityУсловия платформенной комиссии: удержание ПИН 0.25–1.50 п.п. ставки застройщика, per-agency + глобальный дефолт, asOf-резолюция по интервалам действия (ADR-0066)rewardsdomain/platform-commission-terms.md
CommissionAccrualEntity (+ CommissionDistributionEntity, CommissionAccrualAdjustmentEntity)Начисление комиссии по сделке: суммы, снапшоты правила и условий платформы, статусы PendingConfirmation → Confirmed → MoneyReceived → Paid | Cancelled, распределение тремя строками Platform/Agency/Agent, append-only аудит корректировокrewardsdomain/commission-accrual.md
AgencyCommissionPolicyEntityКомиссионная политика агентства: удержание в % или фиксированной суммой от пула (gross − удержание ПИН), персональные оверрайды по агентамrewardsdomain/agency-commission-policy.md
ReferralRateRuleEntityСтавка реферального вознаграждения: 4 уровня специфичности (партнёр×застройщик/партнёр/застройщик/глобально), период действия, непересечение внутри уровня (ADR-0066)rewardsdomain/referral-rate-rule.md
ReferralAccrualEntity (+ ReferralAccrualAdjustmentEntity)Реферальное начисление партнёру: Amount = FinalPrice × %, снапшот ставки, статусы Pending → Approved → Paid | Cancelled; Approved — автоматически по гейту денег родителя; сумма корректируема first-class путём до выплаты (append-only аудит)rewardsdomain/referral-accrual.md
PlatformReceiptEntity (+ PlatformReceiptItemEntity)Акт поступления средств RC-{yyyy}-{seq}: пакетный платёж застройщика ↔ покрытые начисления, Σ позиций = сумме акта; регистрация — атомарный гейт MoneyReceived (ADR-0067)rewardsdomain/platform-receipt.md
PayoutOrderEntity (+ PayoutOrderItemEntity)Платёжное поручение двух видов: AgencyCommission (доли агентов из MoneyReceived-начислений) / ReferralReward (Approved-рефералки, tenant — ПИН); статусы (ожидается/выплачено/отклонено), история выплат; исполнение отложеноrewardsdomain/payout-order.md
AgentPerformanceEntityUser-centric read-проекция личной статистики агента (ключ AgentUserId, вне tenant): пожизненные фиксации/сделки/комиссии + состояние членства + достижения; перестраиваема реплеем событий (ADR-0061 п.5)— (проекция)domain/agent-performance.md

ER-обзор

API

Полный реестр операций (56) и общие контрактные модели — api/README.md. Карта областей:

  • Developer-admin (rewards.rules.manage, rewards.accruals.confirm/manage): правила вознаграждений (create/update/activate/deactivate/archive/list/test), очередь начислений, подтверждение (api/admin/confirm-commission-accrual.md — ± корректировка суммы), отказ, ручное начисление;
  • Agency (rewards.commission-policy.manage, rewards.payouts.manage/approve, rewards.commission.view-all): политика распределения (create/update/activate/archive/list), начисления и сводки «получим/получили × подтверждено/ожидает/деньги получены», per-deal корректировка долей (api/agency/adjust-accrual-distribution.md), платёжные поручения AgencyCommission (create/update-items/approve/mark-paid/reject/cancel/list), Excel-выгрузки (api/agency/create-rewards-export.md + api/agency/get-rewards-export-job.md, ADR-0041);
  • Agent (rewards.commission.view-own, rewards.payouts.view-own, rewards.performance.view-own): мои начисления, моя сводка, мои выплаты, личная user-centric статистика (ADR-0061 п.5);
  • Partner (rewards.referral.view-own): мои реферальные начисления (api/partner/list-my-referral-accruals.md, record-level);
  • Platform (Менеджер/оператор ПИН, платформенный scope): условия платформы (rewards.platform-terms.view/manage), реферальные ставки (rewards.referral-rates.manage), акты поступления средств (rewards.receipts.manageapi/platform/register-platform-receipt.md), gross-корректировки (rewards.accruals.adjustapi/platform/adjust-commission-accrual.md), реестр/отмена реферальных начислений (rewards.accruals.manage) и корректировка их суммы (rewards.referral-rates.manage / rewards.accruals.adjustapi/platform/adjust-referral-accrual.md), реферальные поручения ReferralReward (rewards.payouts.manage/approve);
  • Internal (для catalog, s2s): api/internal/calculate-property-object-commission.md — применимое правило + gross-комиссия + удержание ПИН + пул агентства (net для витрины);
  • Callbacks: not applicable.

Events И Consumers

TypeNameTopicНазначениеLink
ConsumedDealCompletedEventpin.crm.deal-completed.v1Две ветки: комиссионное начисление PendingConfirmation (правило + снапшот условий платформы) и реферальное начисление Pending (активная связь + ставка)consumers/crm-deal-completed.md; контракт — ../crm/events/deal-completed.md
ConsumedDealCancelledEventpin.crm.deal-cancelled.v1Отмена начислений (CancelReason = DealCancelled) до гейта денег; после MoneyReceived — warning + ручная компенсацияconsumers/crm-deal-cancelled.md
ConsumedReferralBondCreatedKafkaEvent / ReferralBondClosedKafkaEventpin.referral.bonds.v1Реплика реферальных связей: создание/закрытие; закрытие прекращает новые начисления (созданные остаются)consumers/referral-bond.md; контракты — ../referral/events/bond-created.md, ../referral/events/bond-closed.md
ConsumedFixationApprovedEventpin.crm.fixation-approved.v1Счётчик FixationsApprovedCount проекции AgentPerformance (user-centric)consumers/crm-fixation-approved.md; контракт — ../crm/events/fixation-approved.md
ConsumedAgentMembershipChangedKafkaEventpin.identity.agent-membership-changed.v1Текущее состояние членства (в агентстве/независимый) в проекции AgentPerformance; метрики не трогает (ADR-0061 п.5)consumers/agent-membership-changed.md; контракт — ../identity/events/agent-membership-changed.md
Consumed (self)CommissionAccrualCreatedKafkaEvent / CommissionAccrualStatusChangedKafkaEventpin.rewards.commission-accrual-created.v1 / -status-changed.v1Наполнение сделочных/денежных счётчиков проекции AgentPerformance (перестраиваемо реплеем; MoneyReceived — no-op)consumers/agent-performance-projection.md
ConsumedLayoutUpsertedKafkaEvent / LayoutGroupUpsertedKafkaEventpin.chessboard.layout-upserted.v1 / pin.chessboard.layout-group-upserted.v1Реплика справочника Layout/LayoutGroup для валидации условий правилconsumers/chessboard-dimensions.md
ProducedCommissionRulesChangedKafkaEventpin.rewards.commission-rules.v1catalog: per-developer снапшот набора активных правил (key = DeveloperCompanyId) → замена набора + батч-пересчёт диапазона комиссии (основной канал, ADR-0068)domain/reward-rule.mdevents/commission-rules.md
ProducedRewardRuleChangedKafkaEventpin.rewards.reward-rule-changed.v1catalog: per-rule дельта того же изменения (key = Id)domain/reward-rule.mdevents/reward-rule-changed.md
ProducedCommissionAccrualCreatedKafkaEventpin.rewards.commission-accrual-created.v1notifications (уведомление агенту/агентству), crm (таймлайн сделки)events/commission-accrual-created.md
ProducedCommissionAccrualStatusChangedKafkaEventpin.rewards.commission-accrual-status-changed.v1notifications: подтверждение/получение денег/выплата/отменаevents/commission-accrual-status-changed.md
ProducedCommissionMoneyReceivedKafkaEventpin.rewards.commission-money-received.v1wallet — кредиты счетов по Distributions[] (Platform/Agency/Agent, ADR-0065); notificationsevents/commission-money-received.md
Produced (условно)CommissionDistributionAdjustedKafkaEventpin.rewards.commission-distribution-adjusted.v1wallet — авто-Adjustment, перенос дельты долей AgencyAgent при корректировке распределения в MoneyReceived (ADR-0065)events/commission-distribution-adjusted.md
ProducedReferralAccrualCreatedKafkaEvent / ReferralAccrualStatusChangedKafkaEventpin.rewards.referral-accruals.v1 (общий топик, key = id начисления)notifications (партнёру); wallet — кредит ReferralCommission по Approved, Correction по отмене после Approvedevents/referral-accrual-created.md, events/referral-accrual-status-changed.md
ProducedPayoutOrderStatusChangedKafkaEventpin.rewards.payout-order-status-changed.v1notifications: статусы выплат получателям и владельцу поручения; wallet — дебет счетов по Paid (Items[])events/payout-order-status-changed.md

Все интеграционные события несут версию контракта (ContractVersion) и публикуются через транзакционный outbox — атомарно с изменением агрегата, в одном согласованном изменении.

Сквозные Потоки (интеграционные последовательности)

Жизненный цикл денег проходит через несколько сервисов; ниже — кто кому что шлёт и в каком порядке (sync — синхронный вызов/ответ пользователю, async — событие через шину; окна eventual-consistency — секунды). Сквозная хореография с компенсациями — sagas/commission-settlement-saga.md; детали отказов и кодов — в документах операций/консюмеров.

  1. Начисления по завершённой сделке (async). crm завершает сделку → публикует pin.crm.deal-completed.v1 → консюмер rewards двумя ветками одного коммита: подбирает правило застройщика, считает gross CommissionAmount, резолвит условия платформы на CompletedAt и снимает снапшоты (правило + PlatformRetentionPercentagePoints/PlatformFeeAmount), создаёт начисление PendingConfirmation (идемпотентность по DealId, INV-1); при активной реферальной связи инвестора и применимой ставке — реферальное начисление Pending (INV-RA-1) → публикует pin.rewards.commission-accrual-created.v1 и pin.rewards.referral-accruals.v1 → потребители: notifications, crm (таймлайн сделки), self-consume rewards (проекция AgentPerformance). Правило не найдено — комиссионного начисления нет (warning + rewards_accrual_no_rule_total, ручное начисление доступно); удержание ≥ ставки правила — событие в DLQ (INV-PT-4).
  2. Подтверждение застройщиком (sync + async). Застройщик подтверждает начисление (cross-tenant по DeveloperCompanyId, ADR-0052), опционально скорректировав сумму с причиной (INV-11) → строится распределение тремя строками: Platform (снапшот условий), Agency/Agent (деление пула по активной политике или fallback) → статус Confirmed → публикуется pin.rewards.commission-accrual-status-changed.v1notifications. Выплаты ещё недоступны — гейт денег не пройден. Отказ застройщика ведёт начисление в Cancelled (DeveloperRejected) тем же событием статуса.
  3. Гейт получения денег (sync + async, ADR-0067). Финансовый оператор ПИН заводит акт поступления средств по пакетному платежу застройщика и регистрирует его → атомарный каскад: начисления-позиции Confirmed → MoneyReceived, рефералки родителей Pending → Approved, публикуются pin.rewards.commission-money-received.v1Distributions[]) и статусные события → wallet кредитует счета получателей (AgentCommission/AgencyCommission/PlatformRevenue/ ReferralCommission, ADR-0065), notifications уведомляет стороны. До регистрации акта никакие выплаты недоступны.
  4. Выплата (sync + async). Агентство формирует и утверждает поручение AgencyCommission по свободным Agent-долям начислений в MoneyReceived (оператор ПИН — поручение ReferralReward по Approved-рефералкам) → отметка MarkPaid (исполнение платежа вне системы, решение №5) → строки получают PaidAt, начисления каскадно переходят в Paid (INV-7) → публикуется pin.rewards.payout-order-status-changed.v1 (Items[]) → wallet дебетует счета получателей, notifications уведомляет.
  5. Отмена/расторжение сделки (async). crm публикует pin.crm.deal-cancelled.v1 → консюмер rewards отменяет начисления (CancelReason = DealCancelled), пока гейт денег не пройден; из MoneyReceived/Paid отмена запрещена — warning + алерт, компенсация отдельным ручным корректирующим начислением (финансовая история иммутабельна); Approved-рефералка отменяется с компенсацией кошелька (Correction).
  6. Изменение правила → каталог (async). Активация/деактивация/архивирование/смена EffectiveTo правила → per-developer снапшот набора pin.rewards.commission-rules.v1 (key = DeveloperCompanyId, основной канал, ADR-0068) + per-rule дельта pin.rewards.reward-rule-changed.v1 (key = Id) → catalog атомарно заменяет денормализованный набор правил застройщика и пересчитывает диапазон комиссии в витрине (окно секунды). Внутренний расчёт rewards (api/internal/calculate-property-object-commission.md) отражает новое правило сразу после коммита — в окне рассинхронизации витрина может показывать прежнюю комиссию.
  7. Реферальная связь (async). referral публикует pin.referral.bonds.v1 → консюмер rewards ведёт реплику связей; закрытие связи прекращает новые начисления, созданные остаются (фрод — ручная отмена BondRevoked).
  8. Смена агентства агента (async). identity публикует pin.identity.agent-membership-changed.v1 → консюмер rewards обновляет текущее состояние членства в проекции AgentPerformance; денежные и сделочные метрики проекции не пересчитываются (историческая привязка иммутабельна, ADR-0061 п.4).

Runtime И Эксплуатация

ОбластьТребование
Health checks/health/live, /health/ready (PostgreSQL + Kafka), /health/startup — стандарт Pin.Kernel
SLO/SLAAPI p95 < 300 мс; лаг consumer-а deal-completed < 1 мин; расчёт комиссии для catalog p95 < 100 мс
DashboardGrafana rewards-overview (создаётся при внедрении)
Alertslag consumer-group > 5 мин; рост rewards_accrual_no_rule_total (сделки без правила); rewards_platform_terms_missing_total (fallback 0 п.п. — платформа теряет доход); rewards_accrual_awaiting_receipt_max_age_minutes выше порога (оператор ПИН — узкое место гейта, ADR-0067); DLQ > 0 (в т.ч. REWARDS_PLATFORM_RETENTION_EXCEEDS_RULE); ошибки outbox
Runbooksrunbooks/rewards-accrual-replay.md (по конвенции — повторная обработка deal-completed)
Feature flagsnone

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

  • Основные actor types: менеджер застройщика (правила, подтверждение ± корректировка), руководитель/администратор агентства (политика, поручения, сводки, корректировка долей, выгрузки), агент (свои комиссии), реферальный партнёр (свои начисления), Менеджер ПИН (условия платформы, ставки, gross-корректировки), финансовый оператор ПИН (акты поступления, реферальные поручения), system-actor consumer-ов.
  • Permission model: rewards.rules.{view,manage}, rewards.accruals.{confirm,manage,adjust}, rewards.commission-policy.{view,manage}, rewards.payouts.{view-own,manage,approve}, rewards.commission.{view-own,view-all,view-property-object}, rewards.platform-terms.{view,manage}, rewards.referral-rates.manage, rewards.receipts.manage, rewards.referral.view-own, rewards.performance.view-own (личная user-centric статистика агента) — каталог permissions: ../identity/domain/permission.md.
  • Sensitive data classes: суммы комиссий/выплат/удержаний (не логируются, доступ по ролям); InvestorUserId маскируется в проекциях агентства и не отдаётся партнёру; условия платформы и ставки видны только платформенному scope (агентству/партнёру — применённые снапшоты); банковские реквизиты не хранятся; выгрузки — audit ExportSensitive (ADR-0041).
  • Audit requirements: версионирование (Version) + actor-stamping на всех агрегатах; финансовые переходы — события статусов; корректировки сумм и долей — append-only строки CommissionAccrualAdjustmentEntity с обязательной причиной; Registered-акт неизменяем; начисления, акты и поручения не удаляются (отмена — статус).
  • Tenant isolation rule (ADR-0052): правила — tenant застройщика; начисления/политики/агентские поручения — tenant агентства с явным DeveloperCompanyId для cross-tenant доступа застройщика (подтверждение) через отдельный permission-фильтрованный query-path; условия платформы, ставки, акты, реферальные начисления — платформенные сущности вне tenant-модели (реферальные поручения — tenant компании ПИН); агент — record-level по AgentUserId, партнёр — по PartnerUserId.

Принятые Решения

#ВопросРешение
1Конфликт правил при пересечении условийПересечение допустимо; выигрывает наибольший Priority, уникальный среди активных правил застройщика (partial-unique index) — детерминированно без проверки непересечения предикатов
2Tenant начисления (двусторонняя сущность)TenantId = агентство (владелец процесса получения/распределения/выплаты); застройщик — явный DeveloperCompanyId + cross-tenant permission (ADR-0052)
3Сделка завершена, правило не найденоНачисление не создаётся: warning + метрика rewards_accrual_no_rule_total; доступно ручное начисление застройщиком
4Воспроизводимость расчётаSnapshot правила (typed jsonb AppliedRuleSnapshotDocument) и AppliedPolicyId фиксируются в начислении; правила/политики иммутабельны в Active
5Исполнение платежейОтложено (решение №9 ТЗ): полная структура поручений + ручной MarkPaid; реквизиты — из profile при будущей интеграции
6ХранилищаPostgreSQL-only, без Redis/ClickHouse (ADR-0056); сводки ЛК — SQL-агрегации по индексам (tenant_id, agent_user_id, status, deal_completed_at)
7Дом личной статистики агента (ADR-0061 п.5)rewards — здесь агрегируются деньги/сделки/фиксации. User-centric проекция AgentPerformance (ключ AgentUserId, вне tenant, платформенный scope агента), перестраиваемая реплеем; членство — из событий identity. Agency-centric отчёт воронки остаётся в crm (get-statistics, якорь AgencyCompanyId)
8Иммутабельность исторической привязки (ADR-0061 п.4)rewards не пересчитывает и не back-fill-ит снапшоты AgencyCompanyId/AgentUserId сделок/фиксаций при смене агентом агентства: основание комиссии — компания-владелец на момент события; проекция считает по AgentUserId, не переписывая историю crm
9Модель удержания ПИН (ADR-0066)Только процентные пункты ставки застройщика (0.25–1.50 п.п.), не процент от суммы комиссии; условия per-agency + глобальный дефолт, asOf-резолюция по CompletedAt, снапшот в начисление; третья строка распределения Platform, политика агентства делит пул (gross − удержание)
10Реферальные ставки и начисления (ADR-0066)Ставки — 4 уровня специфичности (PartnerDeveloper > Partner > Developer > Global) со сроками действия и непересечением внутри уровня; реферальное начисление — отдельная сущность (не kind-дискриминатор): другой получатель, свой жизненный цикл, база — FinalPrice; владелец денег — rewards, referral — только факт связи
11Гейт получения денег (ADR-0067)Статус MoneyReceived — гейт всех выплат (агентских и реферальных); переход — только регистрацией батчевого «Акта поступления средств» (RC-{yyyy}-{seq}, Σ позиций = сумме акта, атомарный каскад + авто-Approve рефералок); Registered-акт неизменяем, откатов нет — только компенсирующие начисления
12Корректировки — first-class (ADR-0067 п.4)Три вида: застройщик при подтверждении / ПИН-админ gross до гейта денег / агентство — доли пула per-deal; каждая — с обязательной причиной и append-only аудит-строкой; строка Platform неприкосновенна; после MoneyReceived gross неизменяем
13Excel-выгрузки агентства (ADR-0041)Два отчёта (по сотрудникам-сделкам / сводный за период) асинхронной задачей: лимиты (период ≤ 1 года, 100k строк, 2 активные задачи), XLSX в приватном хранилище (retention 7 дней), скачивание по signed URL (TTL 1 час), audit ExportSensitive

Известные Ограничения И Assumptions

  • Событие pin.crm.deal-completed.v1 обязано нести: DealId, DeveloperCompanyId, AgencyCompanyId, AgentUserId?, InvestorUserId, PropertyObjectId, атрибуты объекта недвижимости (PropertyType, LayoutId?, LayoutGroupId?, Rooms?, AreaTotalM2), BasePrice и FinalPrice (Amount + CurrencyId + CurrencySnapshot../handbook/domain/snapshots.md), CompletedAt — контракт ../crm/events/deal-completed.md.
  • Сделка без агента (инвестор напрямую) комиссионного начисления не порождает (consumer пропускает по отсутствию AgentUserId); реферальная ветка при этом выполняется.
  • Валюта платформы — RUB (ADR-0048); CurrencyId — типизированная ссылка на справочник валют, не мультивалютность (guard REWARDS_CURRENCY_MISMATCH).
  • Пересчёт подтверждённых начислений при смене политики агентства, условий платформы или реферальных ставок не выполняется (применённые значения зафиксированы снапшотами).
  • Fixed-удержание больше пула срезается до пула (доля агента = 0) — задокументированный edge-case, не ошибка.
  • Частичные оплаты акта поступления — вне scope v1: акт формируется только на полностью покрытые начисления; частичное покрытие одного начисления не моделируется (ADR-0067).
  • Исполнение платежей — вне scope (решение №9 ТЗ): полная структура поручений + ручной MarkPaid; интеграция с банком/эквайрингом отложена, реквизиты при её включении — из profile.
  • Обход guard-а самореферала через вторую учётку — осознанное ограничение v1 (INV-RA-4); инструмент разбора — admin-коррекции связей в referral.

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