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