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

DELETE /api/messenger/blacklist/{blockedUserId} — Разблокировать пользователя

Удалить пользователя из чёрного списка актора: снимается запрет писать и звонить, политика пары восстанавливается по существующему контакту. Удаляет запись BlacklistEntity пары Owner → Blockedhard delete (INV-BL-4; статуса нет, состояние = наличие строки). Идемпотентно: отсутствие записи — no-op. Владелец — контекст messenger, feature group blacklist.

Назначение

Принять от авторизованного пользователя команду разблокировки собеседника и удалить запись чёрного списка; восстановить CommunicationPolicy пары.

Metadata

ПолеЗначение
Сервис/контекстmessenger
API areapublic
Feature groupblacklist
Статусdraft
Документdocs/06-services/messenger/api/blacklist/unblock-user.md

Актор и доступ

ПроверкаЗначение
Actor typeUser
Auth policy / Permissionsmessenger.blacklist.manage (JWT)
Scope (RBAC)платформа (person-level, вне tenant, ADR-0052)
Record-levelOwnerUserId = actor — удаляется только своя запись
Tenant isolationЗапрос не tenanted (blacklist — вне tenant)
Auditdelete (hard); след разблокировки — в аудите операции UnblockUser (INV-BL-4), не soft-delete-полями

HTTP-контракт

ПолеЗначение
MethodDELETE
Route/api/messenger/blacklist/{blockedUserId}
Success status204 (разблокировано или уже не было — идемпотентно)
Idempotency headerне применяется (DELETE идемпотентен по природе)
Correlationсквозной trace через traceparent

Входные данные / параметры запроса

ПолеИсточникТипОбязательностьВалидация / ОграниченияБезопасность
OwnerUserIdidentity claimsGuidДаRequired (= actor)Record-level (own-only)
BlockedUserIdrouteGuidДа!= Guid.Empty

Модель ответа

Тело успеха отсутствует (204 No Content). Ошибки — ProblemDetails (см. «Ошибки и failure modes»).

Алгоритм

  1. Контекст и доступ. Операцию выполняет авторизованный пользователь (User); OwnerUserId = актор; требуется право messenger.blacklist.manage (иначе MESSENGER_BLACKLIST_FORBIDDEN).
  2. Проверка входа. BlockedUserId непустой, иначе ошибка валидации. Существование заблокированного пользователя отдельно не проверяется — операция целится в запись блокировки, а не в пользователя.
  3. Загрузка записи. Запись блокировки пары Owner → Blocked (уникальность ux_blacklist_owner_blocked); отсутствие допустимо.
  4. Удаление или no-op. Запись не найдена → идемпотентный no-op: сразу успех (204). Найдена → удалить (hard delete, INV-BL-4; soft-delete-полей у агрегата нет). Политика пары CommunicationPolicy после удаления восстанавливается по существующему ContactEntity: если контакт был Accepted — вновь доступны сообщения и звонки.
  5. Реалтайм-уведомление. В той же согласованной операции только инициатору (Owner) уходит realtime- сигнал BlacklistChanged через SignalR-hub (UI возвращает кнопки «написать»/«позвонить»). Интеграционных Kafka-событий нет (приватность, локальный эффект).
  6. Согласованность. Удаление и реалтайм-эффект фиксируются атомарно.
  7. Результат. HTTP 204 — и при реальном удалении, и при идемпотентном no-op.

Диаграмма

Побочные эффекты

ТипДетали
Integration eventsnone (blacklist приватен; Kafka/outbox не используется)
External callsnone
Cache / projections / searchCommunicationPolicy пары пересчитывается на чтении (deny снят, если не блокирует и обратная сторона)
Notificationsrealtime BlacklistChanged в SignalR-hub — только Owner

Ошибки и failure modes

КодHTTP statusУсловиеСообщениеRetry
VALIDATION_FAILED400пустой BlockedUserId«Некорректный идентификатор»no retry
UNAUTHORIZED401нет/просрочен JWT«Требуется авторизация»no retry
MESSENGER_BLACKLIST_FORBIDDEN403нет permission messenger.blacklist.manage«Недостаточно прав»no retry

Отсутствие записи блокировки — не ошибка (204, идемпотентность INV-BL-4). Обратная блокировка Blocked → Owner, если существует, снятием этой записи не затрагивается — общение остаётся deny, пока живёт хотя бы одна запись пары (INV-BL-3).

Совместимость и наблюдаемость

  • Контракт стабилен (route + 204); изменение семантики удаления — breaking. Идемпотентность гарантирует безопасный retry клиента.
  • Logs: user unblocked (OwnerUserId, BlockedUserId, existed); metrics: messenger_blacklist_unblock_total{result}, latency p95; traces — сквозной trace (traceparent); dashboard pin-messenger.

Acceptance Criteria

  • Happy path. Given запись Owner → Blocked существует; When DELETE /{blockedUserId}; Then 204, запись удалена hard delete (INV-BL-4), CommunicationPolicy пары восстановлена по существующему контакту, realtime BlacklistChanged только Owner.
  • Идемпотентный no-op. Given записи блокировки нет; When DELETE; Then 204 (no-op), без события.
  • Встречная блокировка. Given существует обратная запись Blocked → Owner; When DELETE Owner → Blocked; Then 204, но общение остаётся deny, пока жива хотя бы одна запись пары (INV-BL-3).
  • Восстановление по контакту. Given Accepted-контакт пары и нет встречной блокировки; When DELETE; Then CanMessage/CanCall снова allow.
  • Валидация. Given BlockedUserId = Guid.Empty; When DELETE; Then 400 VALIDATION_FAILED.
  • Доступ. Given нет messenger.blacklist.manage; When DELETE; Then 403 MESSENGER_BLACKLIST_FORBIDDEN; удаляется только своя запись (record-level).

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

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

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