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

ADR-0069: Co-broking — расщепление комиссии между несколькими агентами (дизайн, v-next)

Статус

Proposed

Дата

2026-07-16

Контекст

Модель участников CRM (ADR-0071) уже допускает несколько агентов на процессе: помимо единственного активного Executor в участниках лида/сделки могут состоять CoAgent, Assistant, Lawyer (enum ParticipantRole, additive). Это бизнес-реальность co-broking: сделку могут вести два агента (например, из разных агентств), плюс ассистент и юрист сопровождения. Однако финансовый контур rewards расщепление на несколько агентских получателей не поддерживает:

  • Распределение начисления жёстко трёхстрочное. При подтверждении начисления строится ровно три строки Platform / Agency / Agent — по одной каждого типа (rewards/domain/commission-accrual.md, INV-4/INV-5/INV-9). Строка Agent ровно одна и ссылается на AgentUserId начисления — единственного получателя. CommissionRecipientType = { Platform, Agency, Agent } (ADR-0066).
  • Получатель — один назначенный Executor. Событие pin.crm.deal-completed.v1 несёт единственный CommissionRecipientUserId (= назначенный руководителем Executor на момент завершения, ADR-0068). Пул агентской стороны (CommissionAmount − PlatformFeeAmount) делится политикой агентства между строкой Agency (удержание агентства) и строкой Agent (остаток) — но получатель Agent-остатка один.
  • Прочие агентские участники нефинансовы. Ни CoAgent, ни Assistant, ни Lawyer в распределении не фигурируют — в v1 их вклад не оцифрован в деньги.

Задача — спроектировать (не внедрить сейчас) мультистрочное агентское распределение, зафиксировав контракт и обобщение инвариантов, чтобы будущая версия не ломала уже принятые ADR-0066/0068/0071 и была additive по событиям. Само расщепление относится к v-next: в текущей версии (v1) остаётся один финансовый получатель.

Решение

1. v1 (текущая версия) — один финансовый получатель

  • Комиссию получает только Executor — активный на момент завершения и явно назначенный руководителем получатель (ADR-0068). Распределение — прежние три строки Platform / Agency / Agent; CommissionRecipientType не расширяется.
  • Прочие агентские участники процесса (CoAgent, Assistant, Lawyer) — нефинансовые: они дают доступ к лиду/сделке и чату, отражаются в участниках (ADR-0071), но в строки распределения rewards не попадают и в AgentShares не участвуют. Их вознаграждение — вне платформы (внутренние договорённости агентства).
  • Инварианты начисления (INV-4/INV-5/INV-9) остаются в трёхстрочной формулировке без изменений.

2. v-next — мультистрочное агентское распределение

  • Источник долей — CRM. Расщепление формируется на стороне crm из участников сделки (deal-members): у агентских участников, которым положена доля, появляется доля (share). CRM отдаёт готовый вектор долей в payload завершения сделки — rewards доли не вычисляет, а применяет (единая зона денежной истины — rewards, но основание расщепления — CRM, как и CommissionRecipientUserId сегодня).
  • Payload pin.crm.deal-completed.v1 несёт AgentShares[] — additive-массив (ContractVersion не бампим): по элементу на каждого агента-получателя со ссылкой AgentUserId, его AgencyCompanyId и долей пула. Существующий CommissionRecipientUserId сохраняется для обратной совместимости: при пустом/ отсутствующем AgentShares[] он трактуется как единственная строка Agent (поведение v1); при непустом — источником расщепления становится AgentShares[].
  • Инвариант суммы долей. Σ AgentShares[].Amount = пул − удержание агентства, где пул = CommissionAmount − PlatformFeeAmount (ADR-0066). То есть строка Platform и удержание агентства неприкосновенны — расщепляется только та часть пула, что в v1 достаётся единственному Agent. Строка Platform (удержание ПИН, ADR-0066) и логика удержания агентства не затрагиваются.
  • Обобщение инвариантов на N строк Agent. INV-9 (RecipientConsistency) переоформляется с «ровно три строки, Agent — одна» на «Platform — одна, Agency — одна, Agentодна и более, каждая со своим RecipientUserId». INV-5 (DistributionSum) обобщается: Σ всех строк = CommissionAmount, где Σ Agent-строк = пул − удержание агентства. INV-4 (DistributionOnConfirm) строит N агентских строк из AgentShares[] вместо одной.
  • Co-broking через границы агентств. Агенты-получатели могут принадлежать разным агентствам (у каждого свой AgencyCompanyId в AgentShares[]). Модель удержания агентства при кросс-агентском co-broking (одно удержание vs. по удержанию на агентство) — открытый вопрос v-next, вне scope этого дизайна; фиксируется только контракт долей.

3. Управление правилами и корректировка

  • Ставки/правила расщепления (per-agency доли co-broking, если понадобится их централизовать) выносятся в новый топик pin.rewards.commission-rules.v1 — тем же механизмом scoped+time-bounded правил, что и прочие ставки rewards (ADR-0066). В v1 топик не используется; резервируется под v-next.
  • Корректировка распределения после подтверждения (перераспределение долей между агентскими строками руководителем) публикуется в pin.rewards.commission-distribution-adjusted.v1 (additive). Правила корректировки наследуют ADR-0068: смена получателей/долей разрешена до Confirm застройщиком; после MoneyReceived — только компенсирующим начислением.
  • Чат co-broking. Для совместного ведения вводится новый вид чата ChatKind.Lead (чат лида, ADR-0071), где состоят все агентские участники; изменения состава участников — pin.crm.lead-participants-changed.v1.

Область Действия

ОбластьВходитНе входит
Сервисыcrm (доли участников, AgentShares[] в payload завершения), rewards (N агентских строк распределения, обобщение INV-4/5/9)wallet (кредитует те же счета получателей, механика не меняется), identity, chessboard, catalog
КонтрактыAgentShares[] в pin.crm.deal-completed.v1 (additive); резерв топиков pin.rewards.commission-rules.v1, pin.rewards.commission-distribution-adjusted.v1CommissionRecipientType не меняется; PlatformFeeAmount/удержание агентства не затрагиваются
Данныеобобщение строк распределения Agent (1..N) в модели начисления; доли на deal-members в crmпересчёт исторических начислений; кросс-агентское удержание
Эксплуатация— (дизайн; операционные метрики вводятся при реализации v-next)

Рассмотренные альтернативы

ВариантОписаниеПричина отклонения
Расщепление сразу в v1Ввести N агентских строк и AgentShares[] немедленноОтклонено: ломает трёхстрочные инварианты INV-5/INV-9 и потребителей Distributions[] до того, как есть бизнес-спрос и UI назначения долей; усложняет уже принятую модель получателя (ADR-0068). v1 закрывает базовый кейс «один Executor», co-broking-деньги откладываются без потери контракта.
Финансовые CoAgent/Assistant/Lawyer в v1Каждая агентская роль участника получает автоматическую долюОтклонено: роли CoAgent/Assistant/Lawyer — про доступ и сопровождение, а не про фиксированную денежную долю; автоматическое начисление им исказило бы пул и потребовало политик долей, которых нет. В v1 они нефинансовы; деньги — только явно назначенному Executor.
Доли считает rewards из участников напрямуюrewards подписывается на участников сделки и сам раскладывает пулОтклонено: основание расщепления (кто и с какой долей) — доменное решение CRM/руководителя, как и назначение CommissionRecipientUserId (ADR-0068); rewards остаётся исполнителем денежной раскладки. Дублировать логику участников в rewards — вторая зона истины.
Отдельная сущность-распределение вместо строкCo-broking-раскладка как новый агрегат рядом с начислениемОтклонено: раскладка — неотъемлемая часть начисления (Σ строк = CommissionAmount, единый жизненный цикл с Confirm/MoneyReceived); вынос в отдельный агрегат разорвал бы инвариант суммы и confirm-гейт. Обобщение существующих строк на 1..N проще и честнее.

Последствия

КонтекстПоследствие
crmv-next: у deal-members появляется доля; pin.crm.deal-completed.v1 обогащается AgentShares[] (additive). v1: без изменений — один CommissionRecipientUserId.
rewardsv-next: INV-4/INV-5/INV-9 обобщаются на 1..N строк Agent; Σ Agent-строк = пул − удержание агентства; строка Platform и удержание агентства неприкосновенны. v1: трёхстрочное распределение без изменений.
walletКредиты по каждой строке Agent — на счёт соответствующего получателя; механика та же, меняется только число строк.
СовместимостьПустой AgentShares[] ⇒ поведение v1 (единственная строка Agent по CommissionRecipientUserId); переход на co-broking не требует пересчёта исторических начислений.

Затронутые контракты и совместимость

КонтрактВерсияСовместимостьМиграция
pin.crm.deal-completed.v1 (+AgentShares[])1additive (ContractVersion не бампим)пустой/отсутствующий массив ⇒ поведение v1
INV-5 (DistributionSum), INV-9 (RecipientConsistency) в начисленииобобщение на 1..N строк Agent (в v-next)переоформление инвариантов в domain-доках при реализации
pin.rewards.commission-rules.v11новый топик (резерв под v-next)additive
pin.rewards.commission-distribution-adjusted.v11новый топик (резерв под v-next)additive
CommissionRecipientType1не меняется

Риски

РискМитигация
Σ долей AgentShares[] не сходится с пулом (ошибка на стороне CRM)guard при построении распределения: Σ Agent-строк = пул − удержание агентства, нарушение → DLQ/ручной разбор (детализируется при реализации v-next)
Потребители Distributions[], рассчитанные на ровно одну Agent-строку, ломаютсяобобщение вводится только в v-next и одновременно с переоформлением потребителей; в v1 контракт трёхстрочный
Кросс-агентское co-broking: удержание агентства при разных AgencyCompanyIdявно вынесено в открытые вопросы v-next; в дизайне фиксируется только контракт долей
Скрытая финансовая роль CoAgent/Assistant/Lawyer (ожидание доли)зафиксировано: в v1 эти роли нефинансовы; деньги — только явно назначенному Executor

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

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

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

  • rewards: commission-accrual.md (строки распределения, INV-4/5/9), agency-commission-policy.md (деление пула).
  • ADR: ADR-0066 (удержание ПИН, три строки распределения, scoped-ставки — обобщается), ADR-0068 (получатель = назначенный Executor, CommissionRecipientUserId, окно смены получателя), ADR-0071 (модель участников, ParticipantRole, множественные агенты, ChatKind.Lead).
  • Смежные: ADR-0048 (денежная арифметика, RUB-only), ADR-0052 (tenancy), ADR-0056 (simplicity-first), ADR-0061 (независимый агент).