POST /api/agent/crm/clients/{clientId}/archive — Архивировать клиента
Перевод карточки клиентской базы агента Active → Archived: карточка убирается из рабочего списка
/crm/clients, но история лидов, фиксаций и сделок сохраняется (клиент — «адресная книга + агрегатор»,
client.md). Операция разрешена только для клиента без незакрытых связей (инвариант
INV-CLI-4). Восстановление (Restore, Archived → Active) и полное soft-удаление (SoftDelete) —
companion-операции того же агрегата (см. state-diagram в client.md); здесь не описываются.
Назначение
Дать агенту/руководителю агентства «прибраться» в клиентской базе — скрыть неактуальные карточки (клиент отказался, ушёл к другому агенту, дубль) без потери истории.
Metadata
| Поле | Значение |
|---|---|
| Сервис/контекст | crm |
| API area | agent |
| Feature group | clients |
| Статус | draft |
| Документ | docs/06-services/crm/api/agent/archive-client.md |
Актор и доступ
| Проверка | Значение |
|---|---|
| Actor type | User (Агент — участник процессов клиента; Руководитель агентства; Менеджер ПИН) |
| Auth policy / Permissions | crm.clients.manage |
| Scope (RBAC) | организация (TenantId = AgencyCompanyId); Менеджер ПИН — platform-scope |
| Record-level | агент: активный участник процессов клиента (лид/фиксация/сделка); руководитель агентства: любой клиент своего TenantId; Менеджер ПИН — сквозной доступ (ADR-0052) |
| Tenant isolation | TenantId в каждом запросе; загрузка и проверки связей — строго в рамках TenantId |
| Audit | update (переход статуса Active → Archived, actor-stamping UpdatedByUserId) |
Рядовой агент архивирует только карточки, в процессах которых он — активный участник (лид/фиксация/
сделка); руководитель агентства — любую карточку своего TenantId; Менеджер ПИН — сквозной доступ вне
привязки к TenantId (ADR-0052).
HTTP-контракт
| Поле | Значение |
|---|---|
| Method | POST |
| Route | /api/agent/crm/clients/{clientId}/archive |
| Success status | 204 (No Content); повтор на уже Archived клиенте — идемпотентный 204 |
| Idempotency header | не применяется (идемпотентность по целевому статусу) |
| Correlation | сквозной trace через заголовок traceparent |
Входные данные / параметры запроса
| Поле | Источник | Тип | Обязательность | Валидация / Ограничения | Безопасность |
|---|---|---|---|---|---|
TenantId | identity claims | Guid | Да | Required, != Guid.Empty | Tenant isolation (AgencyCompanyId) |
ClientId | route | Guid | Да | != Guid.Empty; существующая живая карточка | — |
ActorUserId | identity claims | Guid | Да | Required; проверка record-level | стемпится в UpdatedByUserId |
Тело запроса пустое: причина архивации у ClientEntity не хранится (поля Reason в доме карточки нет,
client.md).
Модель ответа
Тела ответа нет: результат — HTTP 204 No Content. Идентификаторы дочерних сущностей наружу не возвращаются
(внутренние данные агентства). Ошибочные исходы — ProblemDetails с кодом из таблицы ниже.
Алгоритм
- Контекст и доступ. Операцию выполняет агент/руководитель агентства/Менеджер ПИН (permission
crm.clients.manage) в рамкахTenantId. - Проверка входа и предусловий.
- формат:
ClientId != Guid.Empty,TenantId != Guid.Empty— иначе ошибка валидации; - карточка существует в
TenantIdи не soft-deleted — иначеCRM_CLIENT_NOT_FOUND; - record-level: если actor не Менеджер ПИН и не руководитель агентства, требуется членство в процессах
клиента (актор — активный участник лида/фиксации/сделки) — иначе
CRM_CLIENT_FORBIDDEN.
- формат:
- Что читаем. Карточку клиента (единственный мутируемый агрегат; на время проверки связей строка блокируется, чтобы конкурентное создание лида/сделки не проскочило между проверкой и записью).
- Бизнес-правила и переходы (INV-CLI-4). Идемпотентность: если уже
Archived— вернуть204, событие не поднимается. Иначе целевой статус только изActive. Проверка «нет незакрытых связей» по клиенту:- активные лиды (
Status = Active, enumLeadStatus, lead.md); - ожидающие фиксации (
Status = Pending, enumFixationStatus, fixation-request.md); - незавершённые сделки (
Status NOT IN {Completed, Cancelled}, enumDealStatus, deal.md). Любая незакрытая связь →CRM_CLIENT_HAS_ACTIVE_RELATIONS. Иначе переходActive → Archived(ActiveLeadIdужеnullпо INV-CLI-2), стемпингUpdatedByUserId = actor.
- активные лиды (
- Что меняется. Статус клиента переводится в
Archived; дочерние строки не изменяются. - События. Доменное
ClientArchived— внутреннее (in-process). Интеграционных (Kafka) событий нет: клиентская база — внутренние данные агентства, внешние контексты реагируют на события лидов/сделок (client.md; список публикуемых топиков — README). - Результат. HTTP
204 No Content. Провалы правил — из таблицы ошибок.
Диаграмма
Предусловия и постусловия
Предусловия. Актор с crm.clients.manage и доступом к карточке по членству агентства (активный участник
процессов клиента / руководитель агентства / Менеджер ПИН). Карточка живая (не soft-deleted). Для перехода — нет незакрытых связей
(INV-CLI-4): активных лидов, Pending-фиксаций, незавершённых сделок.
Постусловие (успех). Status = Archived, UpdatedByUserId = actor; дочерние агрегаты (лиды/фиксации/
сделки) не изменены; карточка выпадает из рабочего списка /crm/clients (фильтр Active). Поднято доменное
ClientArchived (in-process); интеграционных событий нет. Повтор на уже Archived карточке — идемпотентный
204 без события.
Постусловие (отказ по связям/доступу). Статус клиента не изменён, событие не поднято.
Побочные эффекты
| Тип | Детали |
|---|---|
| Интеграционные события | none (Kafka-события клиент не публикует) |
| Доменные события | ClientArchived (in-process; консюмеров-хендлеров в CRM на текущем слое нет) |
| Внешние вызовы | none |
| Проекции / поиск | проекция клиентов (ClientSearchDocument) обновляется (Status = Archived); выпадение из списка /crm/clients — за счёт фильтра Status = Active в query-методах |
| Уведомления | none (архивация — тихая операция агента) |
Ошибки и failure modes
Главный гейт — INV-CLI-4: архивация невозможна, пока у клиента есть незакрытый лид, Pending-фиксация
или незавершённая сделка (CRM_CLIENT_HAS_ACTIVE_RELATIONS).
| Код | HTTP status | Условие | Сообщение | Retry |
|---|---|---|---|---|
VALIDATION_FAILED | 400 | пустой ClientId/TenantId | «Некорректный идентификатор клиента» | no retry |
CRM_CLIENT_NOT_FOUND | 404 | карточки нет в TenantId либо уже soft-deleted | «Клиент не найден» | no retry |
CRM_CLIENT_FORBIDDEN | 403 | actor не участник процессов клиента и не руководитель/Менеджер ПИН | «Нет доступа к карточке клиента» | no retry |
CRM_CLIENT_HAS_ACTIVE_RELATIONS | 409 | есть активный лид, Pending-фиксация или незавершённая сделка (INV-CLI-4) | «Нельзя архивировать клиента с активными лидами, заявками на фиксацию или сделками» | no retry (сначала закрыть связи) |
CONCURRENCY_CONFLICT | 409 | гонка с созданием связи после проверки | «Данные изменились, повторите» | retry (перечитка) |
Уже Archived клиент — не ошибка: идемпотентный 204. Гонка «создание лида/сделки во время архивации»
ограничена блокировкой строки клиента: команды создания связей трогают клиента (LastActivityAt/ActiveLeadId)
и сериализуются с архивацией.
Совместимость и наблюдаемость
- Метод — новый (write-only, тело пустое); аддитивен к карте
agent-области (README). Companion-операцииrestore(Archived → Active) иsoft-deleteдобавляются отдельными endpoint-ами того же агрегата — без breaking change к этому контракту. - Logs:
client archived(ClientId,TenantId,ActorUserId; PII не пишется) иclient archive rejected(reason = has-active-relations); metrics:crm_client_archive_total{result}; traces — сквозной trace черезtraceparent; dashboardpin-crm; runbook —docs/06-services/crm/runbooks/.
Acceptance Criteria
- Happy path. Given
Active-клиент без незакрытых связей; Whenarchive; Then204,Status = Archived, карточка исчезла из рабочего списка. - Идемпотентность. Given клиент уже
Archived; Whenarchive; Then204, событиеClientArchivedне поднимается. - Незакрытые связи (INV-CLI-4). Given активный лид,
Pending-фиксация или незавершённая сделка; Whenarchive; Then409 CRM_CLIENT_HAS_ACTIVE_RELATIONS, статус не меняется. - Гонка. Given параллельное создание лида/сделки во время архивации; When обе операции трогают клиента; Then
побеждает одна; проигравшая —
409 CONCURRENCY_CONFLICT(перечитать состояние). - Доступ. Given клиент, в процессах которого рядовой актор не участвует (и он не руководитель); When
archive; Then403 CRM_CLIENT_FORBIDDEN.
Обратные ссылки
Автоссылки: где используется этот документ.
- registries (1): Реестр API-методов PIN
Связанные документы
- Сущность-дом: client.md (поля,
ClientStatus, INV-CLI-4, событиеClientArchived); дочерние: lead.md, fixation-request.md, deal.md. - Tenancy/record-level: ADR-0052; simplicity-first: ADR-0056.
- Соседние методы клиентской базы: create-booking-request.md (создание клиента/лида); карта области — README контекста.