DELETE /api/agent/crm/deals/{dealId}/members/{memberId} — Удалить участника сделки
Агент (или руководитель агентства / Менеджер ПИН) снимает участника со сделки: со-агента, ассистента, юриста
сопровождения, куратора (Responsible) или соинвестора (InvestorSecondary). Удаление — soft-remove
(проставляется RemovedAt), история участия сохраняется для аудита и чата. Дом полей состава и инвариантов —
в deal.md (DealMemberEntity, INV-DEAL-3).
Назначение
Дать агентской стороне убрать из сделки участника, чьё участие больше не нужно, не разрушая обязательный
каркас сделки. Операция снимает одного активного участника и поднимает событие для реконсиляции участников
чата (messenger).
Исполнителя (Executor) удалить нельзя — процесс не может остаться без исполнителя (INV-DEAL-3): смена
исполнителя выполняется передачей ведения
(change-participant-role.md), а не удалением. Основной инвестор
(InvestorPrimary) обязателен и через этот эндпоинт не снимается; стороны застройщика (SellManager) и
авто-участник ПИН (PinManager) агентом не удаляются.
Metadata
| Поле | Значение |
|---|---|
| Сервис/контекст | crm |
| API area | agent |
| Feature group | deals |
| Статус | draft |
| Документ | docs/06-services/crm/api/agent/remove-deal-participant.md |
Актор и доступ
| Проверка | Значение |
|---|---|
| Actor type | User — активный участник сделки (агентская сторона), руководитель компании-владельца или Менеджер ПИН |
| Auth policy / Permissions | crm.deals.manage (агентская сторона); Менеджер ПИН — platform-scope |
| Scope (RBAC) | организация (агентство-владелец); сделка живёт в tenant застройщика (кросс-tenant по ADR-0052) |
| Record-level | доступ = актор ∈ активные участники сделки (любая роль ParticipantRole) ИЛИ администратор/руководитель компании-владельца (агентство активного Executor по scope-иерархии ADR-0025; застройщик — свой TenantId) ИЛИ Менеджер ПИН (platform-scope, обход record-level) |
| Tenant isolation | Сделка TenantId = DeveloperCompanyId (владелец — застройщик, ADR-0052); агентская сторона идёт по членству |
| Audit | update состава: RemovedAt = now, RemovedByUserId = actor на DealMemberEntity; Version++ сделки |
HTTP-контракт
| Поле | Значение |
|---|---|
| Method | DELETE |
| Success status | 204 (участие снято) |
| Idempotency header | не применяется — повтор по уже снятому участнику → CRM_DEAL_MEMBER_NOT_FOUND (активного участия нет) |
| Correlation | сквозной trace через заголовок traceparent |
Route: /api/agent/crm/deals/{dealId}/members/{memberId}.
Входные данные / параметры запроса
| Поле | Источник | Тип | Обязательность | Валидация / Ограничения | Безопасность |
|---|---|---|---|---|---|
DealId | route | Guid | Да | != Guid.Empty; существующая сделка, доступная актору по членству | — |
MemberId | route | Guid | Да | != Guid.Empty; активное участие (RemovedAt is null) этой сделки | — |
ActorUserId | identity claims | Guid | Да | из JWT | — |
ActorCompanyId | identity claims | Guid | Да | компания актора — record-level предикат | — |
IsCompanyManager | identity claims | bool | Да | администратор/руководитель компании-владельца | — |
IsPinManager | identity claims | bool | Да | platform-scope Менеджера ПИН (обход record-level) | — |
Тело запроса пустое (идентификация участия — по MemberId в маршруте).
Модель ответа
Успех — 204 No Content (тело не возвращается). Актуальный состав клиент перечитывает картой сделки либо
получает через событие (чат/уведомления).
Алгоритм
- Контекст и доступ. Операцию выполняет активный участник сделки (permission
crm.deals.manage), руководитель компании-владельца или Менеджер ПИН (platform-scope). - Проверка входа и предусловий.
- формат:
DealId/MemberId!= Guid.Empty— иначе ошибка валидации; - сделка существует и доступна актору по членству/руководству/ПИН — иначе
CRM_DEAL_NOT_FOUND(404); - сделка нетерминальна (
Status ∉ {Completed, Cancelled}, INV-DEAL-9) — иначеCRM_DEAL_ALREADY_TERMINAL; - участие
MemberIdсуществует, принадлежит этой сделке и активно (RemovedAt is null) — иначеCRM_DEAL_MEMBER_NOT_FOUND(404); - роль участия допускает снятие через агентский эндпоинт (
CoAgent/Assistant/Lawyer/Responsible/InvestorSecondary) — иначе:- активный
Executor(единственный) →CRM_LAST_EXECUTOR_REQUIRED(снятие/замена исполнителя — только атомарной передачей ведения, INV-DEAL-3); InvestorPrimary(обязателен, ровно один),SellManager/PinManager(управляются иначе) →CRM_PARTICIPANT_ROLE_FORBIDDEN.
- активный
- формат:
- Что читаем. Сделку (доступ/статус) и целевое участие (
MemberId) с его ролью и признаком активности. - Бизнес-правила и переходы (INV-DEAL-3). Снятие активного участника не должно нарушить обязательный
каркас: ровно один активный
Executorи ровно одинInvestorPrimaryсохраняются (их удаление заблокировано выше). Для допустимых ролей — soft-remove:RemovedAt = now,RemovedByUserId = actor; денормализованные скаляры сделки не затрагиваются (снимаемые роли — не singleton-скаляры сделки). При снятииResponsibleденормализованныйResponsibleAgentUserIdсбрасывается вnull.Version++. - Что меняется. Участие
DealMemberEntityпомечается снятым (RemovedAt) — в одном согласованном изменении сVersion++сделки (при желании — запись в таймлайнMemberRemoved, deal-timeline-event.md). - События.
DealMembersChangedEvent→ топикpin.crm.deal-members-changed.v1(ContractVersion = 1,AggregateId = DealId) с дельтойMembers = [{UserId, Role, ChangeType = Removed}](для снятогоResponsible—ResponsibleChanged) и полным активным составомActiveMembersпосле изменения — transactional outbox; контракт — deal-members-changed.md. - Результат. HTTP
204(тело пустое).
Диаграмма
Предусловия и постусловия
Предусловия. Актор — активный участник сделки / руководитель компании-владельца / Менеджер ПИН с
crm.deals.manage. Сделка существует, доступна актору и нетерминальна (INV-DEAL-9). MemberId — активное
участие этой сделки с ролью, допускающей снятие агентом (не Executor/InvestorPrimary/SellManager/
PinManager).
Постусловие (успех). Участие помечено снятым (RemovedAt = now, RemovedByUserId = actor); при снятии
Responsible — ResponsibleAgentUserId = null; Version сделки инкрементирован. Обязательный каркас сохранён
(ровно один активный Executor и InvestorPrimary). Опубликован DealMembersChangedEvent
(pin.crm.deal-members-changed.v1, key DealId) с ChangeType = Removed/ResponsibleChanged и полным
ActiveMembers.
Участник исчезает из сделки сразу, из чата (messenger) и уведомлений (notifications) — с лагом консюмеров
(< 1 мин).
Постусловие (отказ). Ни снятия участия, ни изменения Version, ни интеграционного события.
Побочные эффекты
| Тип | Детали |
|---|---|
| Интеграционные события | DealMembersChangedEvent → pin.crm.deal-members-changed.v1 (ChangeType = Removed + полный ActiveMembers), outbox |
| Уведомления | опосредованно: консюмер deal-members-changed в notifications; messenger — исключение участника из чата сделки (set-реконсиляция по ActiveMembers) |
Ошибки и failure modes
| Код | HTTP status | Условие | Сообщение | Retry |
|---|---|---|---|---|
VALIDATION_FAILED | 400 | DealId/MemberId = Guid.Empty | «Проверьте корректность запроса» | no retry |
CRM_DEAL_NOT_FOUND | 404 | сделки нет или она недоступна актору (record-level скрывает существование) | «Сделка не найдена» | no retry |
CRM_DEAL_ALREADY_TERMINAL | 409 | сделка Completed/Cancelled (INV-DEAL-9) | «Сделка завершена и не редактируется» | no retry |
CRM_DEAL_MEMBER_NOT_FOUND | 404 | участия нет, оно чужой сделки или уже снято (RemovedAt проставлен) | «Участник не найден» | no retry |
CRM_LAST_EXECUTOR_REQUIRED | 409 | попытка снять единственного активного Executor (INV-DEAL-3) | «Нельзя оставить сделку без исполнителя — передайте ведение» | no retry |
CRM_PARTICIPANT_ROLE_FORBIDDEN | 422 | попытка снять InvestorPrimary/SellManager/PinManager через агентский эндпоинт | «Эта роль снимается другим способом» | no retry |
Совместимость и наблюдаемость
- Контракт: route →
204. Смена маршрута/семантики удаления — breaking (migration + rollout). Новые значенияParticipantRole— additive (см. deal-members-changed.md). - Logs:
deal-member removed(DealId,TenantId,MemberId,Role,ActorUserId; ФИО/телефон не пишутся); metricscrm_deal_member_removed_total{role}, latency p95; traces — сквозной trace черезtraceparent; dashboardpin-crm; runbook —docs/06-services/crm/runbooks/.
Acceptance Criteria
- Happy path. Given активный участник
CoAgent/Assistant/Lawyer/InvestorSecondary; WhenDELETE; Then204, участие помеченоRemovedAt,Version++, опубликованdeal-members-changed(ChangeType = Removed, полныйActiveMembers). - Снятие куратора. Given активный
Responsible; WhenDELETE; Then204,ResponsibleAgentUserId = null, событие сChangeType = ResponsibleChanged. - Нельзя убрать исполнителя. Given единственный активный
Executor; WhenDELETEэтого участия; Then409 CRM_LAST_EXECUTOR_REQUIRED(сменить исполнителя — передачей ведения). - Нельзя убрать основного инвестора / системные роли. Given
InvestorPrimary/SellManager/PinManager; WhenDELETE; Then422 CRM_PARTICIPANT_ROLE_FORBIDDEN. - Повторное удаление. Given участие уже снято (
RemovedAtпроставлен); WhenDELETE; Then404 CRM_DEAL_MEMBER_NOT_FOUND. - Терминальная сделка. Given сделка
Completed/Cancelled; WhenDELETE; Then409 CRM_DEAL_ALREADY_TERMINAL. - Нет доступа. Given сделка, где актор не участник и не руководитель/ПИН; When
DELETE; Then404 CRM_DEAL_NOT_FOUND. - Downstream (eventual). Given успешное снятие; When проходит < 1 мин; Then участник исключается из чата
сделки (
messenger, set-реконсиляция поActiveMembers).
Обратные ссылки
Автоссылки: где используется этот документ.
- API (2): POST /api/agent/crm/deals/{dealId}/members — Добавить участника сделки, PUT /api/agent/crm/deals/{dealId}/members/{memberId}/role — Сменить роль участника сделки
- Use Cases (4): UC-CRM-007. Добавление участника в сделку, UC-CRM-008. Снятие участника со сделки, UC-CRM-009. Передача ведения сделки (смена исполнителя), US-реестр «Участники и владение процессами» (US-CRM-PART / US-AG-ADMIN / US-AGT-MULTI / US-INV-CO)
- registries (1): Реестр API-методов PIN
Связанные документы
- Сущность (дом полей
DealMemberEntity,ParticipantRole, INV-DEAL-3): deal.md; таймлайн: deal-timeline-event.md. - Событие: deal-members-changed.md (
pin.crm.deal-members-changed.v1). - Соседние операции состава: add-deal-participant.md,
change-participant-role.md (передача ведения
Executor). - ADR: 0052 tenancy, 0055 мини-мессенджер, 0071 участники и владелец сделки.