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

UC-IDN-011. Инвестор становится агентом

Назначение

Самостоятельный переход инвестора в агенты (ADR-0061): без приглашения инвестор становится независимым агентом — добавляется роль agent в scope Platform, тип меняется Investor → Agent, членства в агентстве нет. Учётка и UserId сохраняются — новая учётка не создаётся. Если у инвестора есть приглашение (invitationId), сценарий эквивалентен вступлению в агентство (UC-IDN-009, ветка accept). Вызывает сам инвестор. Связан с контекстом identity.

Metadata

ПолеЗначение
IDUC-IDN-011
Контекстidentity (см. docs/06-services/identity/)
Типосновной
Статусdraft

Актор

ПолеЗначение
РольИнвестор (сам)
Permissions / scopeself (UserId из sub); независимый режим выдаёт роль agent в scope Platform (INV-R3)
Tenantне применяется — независимый агент вне tenant (ADR-0052)
Record-levelсобственная учётка

Предусловие

  • UserEntity.Type = Investor, Status = Active.
  • Для независимого режима — приглашение не требуется; для вступления в агентство нужен Pending-инвайт на телефон инвестора.

Триггер

ПолеЗначение
ИсточникUI button
Триггерящий элементЛК инвестора → «Стать агентом»

Основной Поток

  1. Инвестор нажимает «Стать агентом» (без приглашения — независимый режим).
  2. Система принимает запрос (become-agent.md, тело без invitationId).
  3. Проверить: пользователь Status = Active (иначе IDENTITY_USER_BLOCKED); для независимого режима — нет активного членства (INV-AM1; повтор — идемпотентный no-op).
  4. В одном согласованном изменении: повысить пользователя (Type Investor → Agent, зеркало CompanyId = null — INV-2 user.md); создать RoleAssignment (agent, companyId: null, Scope = Platform) (Platform-scope допустим для agent — INV-R3). Зафиксировать факты: user-upserted (Type = Agent, CompanyId = null), user-access-changed. Membership-события в независимом режиме не публикуются (записи членства нет).
  5. Система возвращает { UserId, UserType = Agent, Mode = Independent }.
  6. Инвестор получает интерфейс агента (клиентская база — своя, лиды, реф-инструменты); может позже вступить в агентство по приглашению (UC-IDN-009) или вернуться к инвестору (become-investor).

Альтернативные Потоки

A1. Стать агентом по приглашению (вступить в агентство)

  1. Тело содержит invitationId → делегируется в accept-flow (UC-IDN-009, шаги 6–8): создаётся Active AgentMembership, роль agent в Organization, Mode = JoinedAgency.

A2. Уже агент

  1. Шаг 3: активное членство → IDENTITY_AGENT_ALREADY_IN_AGENCY (409); для независимого повтор — идемпотентный 200 (уже Agent с ролью agent Platform).

A3. Учётка заблокирована

  1. Шаг 3: Status != ActiveIDENTITY_USER_BLOCKED (400).

Постусловие

  • UserEntity.Type = Agent (независимый), зеркало CompanyId = null; UserId не изменился.
  • Создано RoleAssignment (agent, Platform, Active).
  • Опубликованы user-upserted и user-access-changed; membership-события отсутствуют (нет членства).

Возможные Ошибки

КодHTTPУсловиеПоведение клиента
IDENTITY_AGENT_ALREADY_IN_AGENCY409Уже агент с активным членством (INV-AM1, A2)«Вы уже агент агентства»
IDENTITY_USER_BLOCKED400Status != Active (A3)«Учётная запись заблокирована»
IDENTITY_INVITATION_*403/404/409При join-режиме — как accept (A1)см. UC-IDN-009

Доменные События

СобытиеКогда поднимаетсяSubscribers
RoleAssignmentGrantedEventВыдача роли agent (Platform)in-proc аудит
AgentJoinedAgencyEventТолько при join-режиме (A1)in-proc

Kafka Интеграционные События

СобытиеTopicКогда публикуетсяConsumers
UserUpsertedKafkaEvent.v1pin.identity.users.v1Investor → Agentcrm, profile, messenger, notifications
UserAccessChangedKafkaEvent.v1pin.identity.access.v1Выдача роли agentcrm, catalog, chessboard, gateway
AgentMembershipChangedKafkaEvent.v1pin.identity.agent-membership-changed.v1Только при join-режиме (A1)crm, rewards, notifications
Гарантии доставки и согласованность

UserUpsertedKafkaEvent и UserAccessChangedKafkaEvent публикуются с ключом партиционирования UserId, несут Version и применяются потребителями идемпотентно. Тип пользователя меняется в identity сразу (одно согласованное изменение), но интерфейс агента (клиентская база, реф-инструменты) полностью доступен после инвалидации кэшей прав по pin.identity.access.v1 — окно eventual-consistency ≤ TTL (UC-IDN-008); до этого отдельные agent-функции могут краткое время отвечать 403. Повтор независимого become-agent идемпотентен (A2): роль agent в Platform не дублируется. Гонка «независимый become-agent против accept приглашения (A1)» сходится к одному членству — второй путь упирается в INV-AM1.

Acceptance Criteria

#КритерийПроверка
AC1Независимый become-agent выдаёт роль agent в scope Platform (INV-R3)тест эффективных прав
AC2Тип Investor → Agent, зеркало CompanyId = null, UserId не меняетсятест до/после
AC3Membership-запись в независимом режиме не создаётсятест отсутствия AgentMembership
AC4Повторный вызов независимого режима идемпотентен (A2)двойной вызов → один результат
AC5С invitationId — вступление в агентство (A1, membership Active)тест join-ветки
AC6Атомарность (user + assignment + события)сбой между шагами → откат

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

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

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