UC-CRM-007. Добавление участника в сделку
Назначение
Описывает сценарий, в котором агентская сторона (агент-исполнитель, руководитель агентства-владельца) или
Менеджер ПИН подключает к сделке дополнительного участника — со-агента, ассистента, юриста сопровождения или
соинвестора. Операция расширяет состав сделки, не меняя исполнителя (получателя комиссии) и основного
инвестора: новый участник получает доступ к сделке по членству и приглашается в чат сделки. Агрегат —
DealEntity; дом полей состава и инвариантов — DealMemberEntity, ParticipantRole,
INV-DEAL-3. Связан с контекстом crm.
Metadata
| Поле | Значение |
|---|---|
| ID | UC-CRM-007 |
| Контекст | crm (см. docs/06-services/crm/) |
| Тип | основной (+ альтернативные потоки A1–A4) |
| Статус | draft |
Актор
| Поле | Значение |
|---|---|
| Роль | Агент (активный участник сделки), Руководитель/администратор агентства-владельца, Менеджер ПИН |
| Permissions / scope | crm.deals.manage — организация (агентство-владелец); Менеджер ПИН — platform-scope (кросс-tenant, ADR-0052) |
| Tenant | Сделка TenantId = DeveloperCompanyId (владелец — застройщик, ADR-0052); агентская сторона идёт по членству, а не по авто-tenant-фильтру; Менеджер ПИН — null (сквозной доступ) |
| Record-level | доступ = актор ∈ активные участники сделки (любая роль ParticipantRole) ИЛИ руководитель/администратор компании-владельца (агентство активного Executor по scope-иерархии ADR-0025; застройщик — свой TenantId) ИЛИ Менеджер ПИН (обход record-level) |
Предусловие
- Актор аутентифицирован и несёт
crm.deals.manage(агентская сторона) либо platform-scope Менеджера ПИН. - Целевая сделка существует (DealEntity) и доступна актору по членству/руководству/ПИН.
- Сделка нетерминальна (
Status ∉ {Completed, Cancelled}, INV-DEAL-9). - Добавляемый
UserIdсуществует в репликеidentityи ещё не является активным участником сделки. - Добавляемая роль — одна из подключаемых через агентский эндпоинт:
CoAgent/Assistant/Lawyer/InvestorSecondary.
Триггер
| Поле | Значение |
|---|---|
| Источник | UI-действие / вызов API |
| Триггерящий элемент | Карточка сделки, блок «Участники» → «Добавить участника»; POST /api/agent/crm/deals/{dealId}/members (add-deal-participant.md) |
Основной Поток
- Актор открывает карточку сделки и в блоке «Участники» выбирает «Добавить участника»: указывает пользователя
(
UserId) и его роль в сделке (CoAgent/Assistant/Lawyer/InvestorSecondary). - Интерфейс отправляет запрос на добавление участника с телом
{ UserId, Role }в маршруте сделки. - Система определяет контекст и доступ актора: активный участник сделки, руководитель компании-владельца или Менеджер ПИН.
- Система проверяет вход и предусловия: формат идентификаторов; роль входит в набор, допустимый для
добавления агентом; сделка существует, доступна и нетерминальна; пользователь есть в реплике
identityи не является активным участником сделки (уникальностьUserIdна сделку). - Система применяет бизнес-правило состава (INV-DEAL-3): роли
CoAgent/Assistant/Lawyer/InvestorSecondaryдопускают произвольное число активных участников — singleton-инвариантыExecutor/InvestorPrimaryне затрагиваются; денормализованные скаляры сделки (ExecutorAgentUserId/PrimaryInvestorUserId) не меняются. - Система заводит нового активного участника (участие с
RemovedAt = null, отметкой «кем добавлен» и моментом добавления), инкрементирует версию сделки и, при желании, пишет строку таймлайна «участник добавлен» — в одном согласованном изменении. - Система фиксирует факт: публикует deal-members-changed.md
(
pin.crm.deal-members-changed.v1, keyDealId) с дельтой (ChangeType = Added) и полным активным составом после изменения. - Система возвращает карточку добавленного участника (HTTP
201); интерфейс обновляет список участников сделки.
Альтернативные Потоки
A1. Добавляется соинвестор (InvestorSecondary)
- Актор добавляет второго/третьего инвестора ролью
InvestorSecondary(созаёмщик/соинвестор). - Singleton-инвариант основного инвестора (
InvestorPrimary, ровно один) не нарушается — числоInvestorSecondaryне ограничено.
Возврат к основному потоку
Возвращается к основному потоку на шаг 6.
A2. Недопустимая для агента роль
- Актор указывает роль
Executor/Responsible/InvestorPrimary(смена исполнителя, назначение куратора, смена основного инвестора) либоSellManager/PinManager(стороны застройщика/ПИН). - Система отклоняет запрос
CRM_PARTICIPANT_ROLE_FORBIDDEN(422): эти роли назначаются иными операциями — передача ведения (UC-CRM-009), смена роли/основного инвестора, либо системно.
Роль недопустима для агентского добавления
Завершается ошибкой; состав не меняется.
A3. Пользователь уже участвует в сделке
- Указанный
UserIdуже является активным участником сделки. - Система отклоняет запрос
CRM_DUPLICATE_PARTICIPANT(409): один и тот же пользователь не дублируется в составе (уникальностьUserIdна сделку, INV-DEAL-3).
Дубликат участника
Завершается ошибкой; повторного участия не создаётся.
A4. Сделка недоступна актору
- Актор не участник сделки и не руководитель/ПИН.
- Система отвечает
CRM_DEAL_NOT_FOUND(404) — существование чужих сделок не раскрывается.
Сделка недоступна актору
Завершается ошибкой.
Постусловие
- В состав сделки добавлено новое активное участие (
RemovedAt = null) с рольюCoAgent/Assistant/Lawyer/InvestorSecondary; версия сделки инкрементирована; денормализованные скаляры исполнителя/основного инвестора не изменены. - Опубликован
DealMembersChangedEvent(ChangeType = Added, полный активный состав). - Окно eventual-consistency: участник виден в сделке сразу; в чате сделки (
messenger) и в уведомлениях (notifications) появляется с лагом консюмеров (< 1 мин). - При отказе — ни участия, ни изменения версии, ни события.
Возможные Ошибки
| Код | HTTP | Условие | Поведение клиента |
|---|---|---|---|
VALIDATION_FAILED | 400 | DealId/UserId = Guid.Empty или роль вне enum ParticipantRole | Подсветить поля формы |
CRM_PARTICIPANT_ROLE_FORBIDDEN | 422 | роль не добавляется через агента (Executor/Responsible/InvestorPrimary/SellManager/PinManager) | Показать «эта роль назначается другим способом» |
CRM_DEAL_NOT_FOUND | 404 | сделки нет или она недоступна актору | Обновить список сделок |
CRM_DEAL_ALREADY_TERMINAL | 409 | сделка Completed/Cancelled (INV-DEAL-9) | Показать «сделка завершена и не редактируется» |
CRM_USER_NOT_FOUND | 404 | UserId не найден в реплике identity | Показать «пользователь не найден» |
CRM_DUPLICATE_PARTICIPANT | 409 | UserId уже активный участник (INV-DEAL-3) | Показать «пользователь уже в сделке» |
Доменные События
| Событие | Когда поднимается | Subscribers |
|---|---|---|
DealMemberAdded | Добавление активного участника | подписчик таймлайна (MemberAdded), сборщик DealMembersChangedEvent |
Kafka Интеграционные События
| Событие | Topic | Когда публикуется | Consumers |
|---|---|---|---|
DealMembersChangedEvent | pin.crm.deal-members-changed.v1 | Добавление участника — контракт | messenger (приглашение в чат сделки, синк состава), notifications (уведомление добавленному участнику) |
Acceptance Criteria
| # | Критерий | Проверка |
|---|---|---|
| AC1 | Добавление CoAgent в нетерминальную доступную сделку → 201, новое активное участие, версия сделки инкрементирована, событие deal-members-changed (Added, полный состав) | Тест операции + проверка outbox |
| AC2 | Добавление InvestorSecondary при существующем InvestorPrimary → 201; singleton-инвариант основного инвестора не нарушен | Тест: несколько InvestorSecondary без конфликта |
| AC3 | Роль Executor/InvestorPrimary/SellManager/PinManager → 422 CRM_PARTICIPANT_ROLE_FORBIDDEN, состав не меняется | Guard-тест роли |
| AC4 | Повторное добавление того же UserId → 409 CRM_DUPLICATE_PARTICIPANT | Тест уникальности участника |
| AC5 | Добавление в терминальную сделку → 409 CRM_DEAL_ALREADY_TERMINAL | Guard-тест INV-DEAL-9 |
| AC6 | Актор не участник/руководитель/ПИН → 404 CRM_DEAL_NOT_FOUND (существование не раскрывается) | Record-level тест |
| AC7 | Через < 1 мин после успеха участник появляется в чате сделки и получает уведомление | Downstream (eventual): проверка синка messenger/notifications |
Обратные ссылки
Автоссылки: где используется этот документ.
- Use Cases (2): UC-CRM-008. Снятие участника со сделки, UC-CRM-009. Передача ведения сделки (смена исполнителя)
- registries (1): Реестр use cases и user stories PIN
Связанные Документы
- API метод: add-deal-participant.md; соседние операции состава — remove-deal-participant.md, reassign-executor.md, change-participant-role.md.
- Domain: deal.md (
DealMemberEntity,ParticipantRole, INV-DEAL-3), deal-timeline-event.md (MemberAdded). - Событие: deal-members-changed.md (
pin.crm.deal-members-changed.v1). - Смежные UC: UC-CRM-008 (снятие участника), UC-CRM-009 (передача ведения), UC-CRM-006 (вмешательство Менеджера ПИН).
- ADR: 0052 tenancy, 0055 мини-мессенджер, 0071 участники и владелец сделки.