GET /api/messenger/recordings/{recordingId} — Карточка записи
Метаданные одной записи по её идентификатору — проекция CallRecordingEntity
(дом полей, статусы, инварианты — там). Возвращает состояние и характеристики файла, но не ссылку на
скачивание: ссылка выдаётся отдельным методом get-recording-download.md.
Назначение
Дать участнику сессии-владельца (1:1-звонка или конференции) карточку записи: статус жизненного цикла,
модальность, длительность/размер/формат готового файла. Метод универсален по типу сессии — авторизация
различается по SessionKind. Owning-сервис — messenger, feature group recordings.
| Поле | Значение |
|---|
| Сервис/контекст | messenger |
| API area | recordings |
| Feature group | recordings |
| Статус | draft |
| Документ | docs/06-services/messenger/api/recordings/get-recording.md |
Актор и доступ
| Проверка | Значение |
|---|
| Actor type | User — участник сессии-владельца записи |
| Auth policy / Permissions | permission messenger.recordings.view |
| Scope (RBAC) | не применяется (доступ — по участию в сессии) |
| Record-level | Direct: actor.UserId ∈ {CallerUserId, CalleeUserId} звонка; Conference: активное членство в ChatId конференции (INV-CHAT-4) |
| Tenant isolation | нет (кросс-tenant); изоляция — по участию/членству |
| Audit | read (нечувствительный): карточка без FileId-ссылки/URL; скачивание — отдельный аудируемый метод |
HTTP-контракт
| Поле | Значение |
|---|
| Method | GET |
| Route | /api/messenger/recordings/{recordingId} |
| Success status | 200 (OK) |
| Idempotency header | не применяется (чтение) |
| Correlation | сквозной trace через traceparent |
Входные данные / параметры запроса
| Поле | Источник | Тип | Обязательность | Валидация / Ограничения | Безопасность |
|---|
RecordingId | route | Guid | Да | != Empty; существующая запись, актор — участник её сессии (шаги 3–4) | — |
ActorUserId | identity claims | Guid | Да | из JWT; участник сессии-владельца | — |
Модель ответа RecordingModel
Проекция CallRecordingEntity (дом — сущность). FileId присутствует
только при Status == Available (INV-REC-6); ссылки/URL модель не несёт.
| Поле | Тип | Обязательность | Источник | Masking | Описание |
|---|
RecordingId | Guid | Да | CallRecordingEntity.Id | — | Идентификатор записи. |
SessionKind | SessionKind | Да | .SessionKind | — | Direct / Conference. |
SessionId | Guid | Да | .CallSessionId / .ConferenceSessionId | — | Сессия-владелец. |
ChatId | Guid? | Нет | .ChatId | — | Deal-чат (для конференций); null для 1:1. |
DealId | Guid? | Нет | .DealId | — | Сделка (для конференций). |
Status | RecordingStatus | Да | .Status | — | Pending/Recording/Uploading/Available/Failed/Deleted. |
Trigger | RecordingTrigger | Да | .Trigger | — | AutoPolicy/Manual. |
MediaType | CallMediaType | Да | .MediaType | — | Audio/Video. |
FileId | Guid? | Нет | .FileId | — | Ссылка на бинарь; задан только при Available. |
DurationSeconds | int? | Нет | .DurationSeconds | — | Длительность; null до Available. |
SizeBytes | long? | Нет | .SizeBytes | — | Размер файла; null до Available. |
Format | RecordingFormat? | Нет | .Format | — | Контейнер (Mp4/Webm/Mkv/Mp3); null до Available. |
StartedAt | DateTimeOffset? | Нет | .StartedAt | — | Подтверждённый старт захвата. |
EndedAt | DateTimeOffset? | Нет | .StoppedAt | — | Остановка захвата. |
CreatedAt | DateTimeOffset | Да | .CreatedAt | — | Момент провизии записи. |
Скачивание бинаря — через get-recording-download.md (короткоживущий пресайн,
аудит ReadSensitive).
Алгоритм
- Контекст и доступ. Операцию выполняет участник сессии-владельца (
User); ActorUserId — из JWT;
требуется право messenger.recordings.view. Запись включена флагом RECORDINGS_ENABLED, иначе
MSG_RECORDINGS_DISABLED.
- Проверка входа.
RecordingId непустой; иначе ошибка валидации.
- Загрузка записи. Запись по
RecordingId; нет → MSG_RECORDING_NOT_FOUND. Читаем SessionKind и
ссылку на сессию-владельца.
- Право (по типу сессии).
Direct — актор ∈ {Caller, Callee} звонка; Conference — актор активный
член ChatId конференции (INV-CHAT-4). Иначе → MSG_RECORDING_FORBIDDEN (либо MSG_RECORDING_NOT_FOUND
для сокрытия чужой записи). Для Conference право проверяется по актуальному членству: участник,
исключённый из Deal-чата (RemovedAt проставлен), доступ к карточке теряет, даже если присутствовал на
встрече; новый член чата, добавленный после встречи, карточку видит (история команды сделки).
- Результат.
RecordingModel; FileId отдаётся только при Status == Available; в неконечных
(Pending/Recording/Uploading) и терминальных Failed/Deleted — null (INV-REC-6), ссылки/URL
нет → HTTP 200 OK. Терминалы возвращаются как есть (статус Failed/Deleted), а не как 404, — UI
показывает «запись не удалась»/«запись удалена». Снимок — на момент чтения: если запись конкурентно
переходит в Available, новое состояние (с FileId) актор увидит при следующем запросе (freshness — по
факту чтения, не подписка).
Ошибки и failure modes
| Код | HTTP status | Условие | Сообщение | Retry |
|---|
VALIDATION_FAILED | 400 | RecordingId = Empty | «Проверьте параметры запроса» | no retry |
MSG_RECORDING_NOT_FOUND | 404 | записи нет или актор не участник сессии (сокрытие) | «Запись не найдена» | no retry |
MSG_RECORDING_FORBIDDEN | 403 | актор не участник сессии-владельца | «Недостаточно прав» | no retry |
MSG_RECORDINGS_DISABLED | 503 | RECORDINGS_ENABLED = false | «Записи временно недоступны» | retry позже |
Acceptance Criteria
- Given запись
Available и актор — участник её сессии, When запрашивает карточку, Then 200 с
RecordingModel, где заполнены FileId, DurationSeconds, SizeBytes, Format; ссылки на скачивание в
ответе нет (скачивание — отдельным методом).
- Given запись в неконечном статусе (
Pending/Recording/Uploading), When участник запрашивает
карточку, Then 200 со статусом текущего этапа и FileId = null.
- Given запись в терминале
Failed/Deleted, When участник запрашивает карточку, Then 200 с
соответствующим статусом и FileId = null (не 404) — клиент отражает исход.
- Given актор не участник сессии-владельца, When запрашивает карточку, Then
404 MSG_RECORDING_NOT_FOUND (чужая запись неотличима от несуществующей).
- Given актор был участником встречи, но исключён из Deal-чата конференции, When запрашивает карточку,
Then
403 MSG_RECORDING_FORBIDDEN/404 MSG_RECORDING_NOT_FOUND (доступ — по актуальному членству).
- Given
RECORDINGS_ENABLED = false, When любой запрос, Then 503 MSG_RECORDINGS_DISABLED.
Совместимость и наблюдаемость
- Новые optional-поля — additive; удаление/смена типа — breaking. Kafka-контракта нет.
- Logs:
recording fetched (RecordingId, Status, участник); metrics: messenger_recording_get_total{result},
latency p95; correlation через traceparent; FileId/URL/бинарь в логи не пишутся.
Обратные ссылки
Автоссылки: где используется этот документ.
Связанные документы