ADR-0061: Независимый агент, отвязка от агентства и приглашения по номеру телефона
Статус
Accepted
Дата
2026-07-14
Контекст
Текущая модель жёстко привязывает агента к компании и не даёт «уйти» из агентства, сохранив наработки:
- Жёсткий INV-2 (identity/domain/user.md):
Type ⇔ CompanyId, дляAgentобязателенCompanyId != null. Агент не существует вне агентства. - Приглашение = сразу учётка (identity/api/company-user/invite-company-user.md):
«invite =
UserEntityв статусеInvited», без отдельной pending-сущности; приглашённый ничего не подтверждает, учётку создаёт руководитель, активация — первым входом. Для добора агента «со стороны» по номеру телефона (который может уже быть учёткой-инвестором или агентом другой компании) этого мало. - Бизнес-требование (аналогия «игрок меняет клан»): агент — самостоятельная фигура; его метрики/статистика/достижения принадлежат агенту, а не агентству, и сохраняются при смене агентства.
- Историческая привязка сделок/лидов/фиксаций уже держится снапшотами
AgencyCompanyId/AgentUserId(crm/domain/deal.md, lead.md, fixation-request.md) — эти поля record-level и не пересчитываются. Статистика агента сегодня считается agency-centric (record-level поAgencyCompanyId+AgentUserId, crm/api/agent/get-statistics.md) — в границах одного агентства.
Решение
1. Независимый агент (развязка членства)
- Вводится независимый агент:
AgentсCompanyId = nullили через отдельную запись членства (AgentMembership) без активной компании. Жёсткий INV-2 ослабляется: типAgentбольше не требуетCompanyId != null— членство в агентстве становится отдельной, развязываемой связью. - Отвязка от агентства (
leave) не удаляет учётку и не трогает историю: агент сохраняетUserId, рольagent(для независимого — в scopePlatform) и все метрики/достижения. Агент может выйти, стать независимым и позже вступить в другое агентство. - Конкретная реализация (nullable
CompanyIdпротив явной membership-сущности) фиксируется в identity-доменных доках; INV-2 иRoleAssignmentscope переоформляются там же. - Множественное членство и active-agency (агент одновременно состоит в нескольких агентствах и выбирает
активное) вводятся отдельно — ADR-0070: там инвариант
единственного активного членства INV-AM1 снят (заменён на
SingleActivePerCompany), появляетсяAgentMembershipEntity,RefreshSession.ActiveCompanyIdи endpoint выбора активного агентства. Настоящий ADR остаётся в силе для развязки членства и независимого агента.
2. Приглашение по номеру телефона — новый агрегат CompanyInvitation
- «Приглашение» отделяется от «создания учётки». Новый агрегат
CompanyInvitation(контекстidentity),Status:Pending/Accepted/Declined/Expired/Revoked. - Руководитель приглашает по номеру телефона (адресат может уже быть инвестором или агентом другой
компании). Агент подтверждает (
accept) или отклоняет (decline); толькоacceptсоздаёт/меняет членство и назначает роль.Revoked— отзыв приглашающей стороной,Expired— по сроку жизни. - Существующий
invite-company-user(invite = сразуInvited-учётка) остаётся для внутренних сотрудников без самоподтверждения; добор агента «со стороны» идёт черезCompanyInvitation.
3. Переходы роли инвестор ↔ агент
- become-agent: инвестор становится агентом (принял приглашение агентства или заявился независимым) —
добавляется роль
agent, при необходимости членство. - become-investor: агент возвращается к роли инвестора (снятие роли
agent, выход из членства). - Переходы меняют роли/членство, но не создают новую учётку — один
UserIdна человека.
4. Историческая привязка: иммутабелен Origin-snapshot, текущий исполнитель — мутабелен
С введением модели участников CRM (ADR-0071) разделяются атрибуция происхождения (иммутабельна) и текущий исполнитель (мутабелен, производный от участников):
- Иммутабелен именно Origin-snapshot сделки/лида/фиксации —
OriginAgencyCompanyId/OriginAgentUserId. Это отпечаток «кто и от какого агентства завёл процесс» на момент создания; он не переписывается при смене агентом агентства и фиксирует происхождение записи. - Текущий исполнитель
ExecutorAgentUserId— мутабелен: это производное поле от активного участникаExecutor(enumParticipantRole), которого руководитель может переназначить (reassign) в ходе процесса. Ровно один активныйExecutor; процесс нельзя оставить без него. - Получатель комиссии = явно назначенный руководителем
Executorна момент завершения (CommissionRecipientUserIdв событияхpin.crm.deal-completed.v1/ fixation-approved), а не тот, кто когда-то завёл сделку. Правила смены получателя — в ADR-0071. - Back-fill, переписывающий
OriginAgencyCompanyId/OriginAgentUserIdисторических записей на новую компанию агента, запрещён: он исказил бы происхождение сделок, воронку агентства и основания комиссий (rewards). Смена агентства меняет только членство и текущего исполнителя (через reassign), но не Origin.
5. Метрики агента — user-centric
- Личные метрики/достижения агента агрегируются по
AgentUserIdсквозь все компании, а не только по текущему агентству. get-statisticsостаётся agency-centric (якорьAgencyCompanyId) — отчётность агентства; личная статистика агента — отдельная user-centric проекция.- Опционально: проекции
AgentPerformance/AgentAchievement(user-scoped сводка достижений), дом —identityлибоrewards; вводятся при появлении экрана личного профиля агента, не обязательны сразу.
Область Действия
| Область | Входит | Не входит |
|---|---|---|
| Сервисы | identity (агрегат/переходы/членство), crm/rewards (user-centric метрики), notifications (уведомления) | chessboard, catalog, messenger |
| Контракты | CompanyInvitation API (invite/accept/decline/revoke), become-agent/become-investor; 2 новых Kafka-топика | контракт invite-company-user не меняется |
| Данные | CompanyInvitation, membership/CompanyId=null, опц. AgentPerformance/AgentAchievement | Origin-snapshot OriginAgencyCompanyId/OriginAgentUserId в crm (иммутабелен, не трогается); ExecutorAgentUserId — производное поле участников (ADR-0071) |
| Эксплуатация | миграция ослабления INV-2; запрет back-fill исторической привязки | — |
Последствия
| Контекст | Последствие |
|---|---|
identity | +агрегат CompanyInvitation, +переходы become-agent/become-investor, ослабление INV-2, модель членства/независимого агента; дорабатываются user.md, role.md, invite-company-user.md. |
crm / rewards | личная статистика агента — user-centric (агрегация по AgentUserId); Origin-snapshot (OriginAgencyCompanyId/OriginAgentUserId) не пересчитывается, back-fill запрещён; текущий исполнитель ExecutorAgentUserId мутабелен (reassign), получатель комиссии — Executor на момент завершения (ADR-0071). |
notifications | новые уведомления по событиям приглашений и членства (пригласили / приняли / отклонили / вышел из агентства). |
Затронутые контракты и совместимость
| Контракт | Версия | Совместимость | Миграция |
|---|---|---|---|
pin.identity.company-invitation-changed.v1 | 1 | новый топик | additive |
pin.identity.agent-membership-changed.v1 | 1 | новый топик | additive |
INV-2 (Type ⇔ CompanyId) в user.md | — | ослабление (breaking для модели) | миграция схемы + переоформление инвариантов в domain-доках |
Обратные ссылки
Автоссылки: где используется этот документ.
- Домен (CQRS) (4): Entity / Aggregate: AgentMembershipEntity, Entity / Aggregate: CompanyInvitationEntity, Entity / Aggregate: NotificationEntity, Entity / Projection: AgentPerformanceEntity
- API (1): POST /api/v1/me/active-agency — Выбор активного агентства
- Use Cases (6): UC-CRM-013. Увольнение агента: каскад отвязки от процессов CRM, UC-CRM-014. Агент выбирает активное агентство перед созданием лида/сделки, UC-RWD-006. Агент смотрит личную статистику за всю карьеру (user-centric), UC-RWD-017. Уволенный агент: судьба заработанных комиссий, UC-WLT-004. Холдер смотрит баланс и историю операций, UC-WLT-006. Компенсирующее начисление отражается в балансе после MoneyReceived
- События (2): Event Contract: pin.identity.agent-membership-changed (AgentMembershipChangedKafkaEvent), Event Contract: pin.identity.company-invitation-changed (CompanyInvitationChangedKafkaEvent)
- Консюмеры (1): Consumer: Identity Events → Notifications (notifications-identity-events)
- adr (4): ADR-0069: Co-broking — расщепление комиссии между несколькими агентами (дизайн, v-next), ADR-0070: Мульти-агентство и контекст активного агентства, ADR-0071: Владение процессами CRM компанией и единая модель участников, ADR-0072: Увольнение/исключение агента и каскад доступа
- scenarios (3): UC-OVR-004. От реферальной ссылки до объекта у собственника, UC-OVR-005. От лида до сделки (4 фазы), UC-OVR-008. Агент выходит из агентства, сохраняя метрики
- index.md (2): Notifications Service, Wallet Service
Связанные документы
- Затрагиваемые доки: identity/domain/user.md, role.md, invite-company-user.md, crm/domain/deal.md, lead.md, fixation-request.md, get-statistics.md.
- ADR-0025 (роли/permissions/scope),
ADR-0052 (tenancy: инвестор вне tenant),
ADR-0053,
ADR-0070 (мульти-членство и active-agency; снятие INV-AM1),
ADR-0071 (участники CRM,
ExecutorAgentUserId, получатель комиссии).