GET /api/messenger/chats/{chatId}/conferences — История конференций сделки
Постраничная лента групповых звонков в чате сделки: когда, кем, сколько длилась, велась ли запись. Read-only
проекция ConferenceSessionEntity. Дом полей и статусы —
conference-session.md.
Назначение
Отдать участнику Deal-чата историю видеовстреч по сделке для панели «Звонки/встречи» (список сессий, длительности,
пометка «с записью»). Owning-сервис — messenger, feature group conferences, сценарий «групповой звонок по
сделке».
| Поле | Значение |
|---|
| Сервис/контекст | messenger |
| API area | conferences |
| Feature group | conferences |
| Статус | draft |
| Документ | docs/06-services/messenger/api/conferences/list-conferences.md |
Актор и доступ
| Проверка | Значение |
|---|
| Actor type | User — активный участник Deal-чата |
| Auth policy / Permissions | permission messenger.conferences.use |
| Scope (RBAC) | не применяется — доступ по членству в чате |
| Record-level | активный ParticipantEntity чата ChatId (INV-CHAT-4); видны только конференции этого чата |
| Tenant isolation | не применяется (кросс-tenant); срез — по членству |
| Audit | read (не sensitive: список без токенов/медиа) |
HTTP-контракт
| Поле | Значение |
|---|
| Method | GET |
| Route | /api/messenger/chats/{chatId}/conferences |
| Success status | 200 |
| Idempotency header | не применяется (безопасный GET) |
| Correlation | сквозной trace через traceparent |
Входные данные / параметры запроса
| Поле | Источник | Тип | Обязательность | Валидация / Ограничения | Безопасность |
|---|
ChatId | route | Guid | Да | != Empty; существующий Deal-чат, актор — активный участник | — |
ActorUserId | identity claims | Guid | Да | из JWT; активное членство в ChatId | — |
Paging | query | PagingQuery | Нет | Take 1..100 (default 20), Offset >= 0 (default 0) | защита от unbounded |
Status | query | ConferenceStatus? | Нет | enum строкой; unknown → ошибка валидации | — |
RecordedOnly | query | bool? | Нет | true → только конференции с записью | — |
From / To | query | DateTimeOffset? | Нет | окно по StartedAt; From <= To | — |
Фильтры комбинируются AND. Сортировка фиксирована StartedAt desc, tiebreak Id desc.
Модель ответа ConferenceListModel
Постраничный ответ: элементы страницы + метаданные пагинации. Элемент — компактная проекция конференции без
ростера и без дескриптора входа.
| Поле | Тип | Обязательность | Источник | Описание |
|---|
Items | ConferenceEntry[] | Да | проекция ConferenceSessionEntity | Страница истории. |
Total | int | Да | count | Всего по фильтру. |
Take | int | Да | Paging.Take | Размер страницы. |
Offset | int | Да | Paging.Offset | Смещение. |
Вложенная модель ConferenceEntry
| Поле | Тип | Обязательность | Источник | Masking | Описание |
|---|
ConferenceId | Guid | Да | ConferenceSessionEntity.Id | — | Идентификатор конференции. |
ChatId | Guid | Да | .ChatId | — | Deal-чат. |
MediaType | CallMediaType | Да | .MediaType | — | Audio/Video. |
Status | ConferenceStatus | Да | .Status | — | Статус сессии. |
Title | string? | Нет | .Title | — | Название встречи. |
StartedByUserId | Guid | Да | .StartedByUserId | — | Инициатор. |
StartedAt | DateTimeOffset | Да | .StartedAt | — | Момент старта (ключ сортировки). |
EndedAt | DateTimeOffset? | Нет | .EndedAt | — | null для активной. |
DurationSeconds | int? | Нет | .DurationSeconds | — | null до завершения. |
ParticipantCount | int | Да | .PeakParticipantCount | — | Пиковое число участников (для карточки истории). |
RecordingStatus | RecordingStatus? | Нет | CallRecordingEntity.Status | — | Статус записи; null — без записи. |
RecordingId | Guid? | Нет | CallRecordingEntity.Id | — | Идентификатор записи (если велась). |
Алгоритм
- Контекст и доступ. Операцию выполняет активный участник Deal-чата (
User); ActorUserId — из JWT;
требуется право messenger.conferences.use.
- Проверка входа.
ChatId непустой; актор — активный участник чата (INV-CHAT-4), иначе
MSG_CHAT_ACCESS_DENIED. Paging.Take ∈ 1..100, Offset >= 0; Status — известное значение enum (unknown →
ошибка валидации); From <= To.
- Выборка. Конференции чата
ChatId с фильтрами (AND): Status; RecordedOnly → только с привязанной
записью; окно StartedAt ∈ [From, To]. Сортировка StartedAt desc, tiebreak Id desc; индекс по ChatId.
- Маппинг. Каждая сессия проецируется в
ConferenceEntry (без ростера и без Room); ParticipantCount =
PeakParticipantCount; RecordingStatus/RecordingId — из привязанной записи (если есть).
- Результат. Постраничный
ConferenceListModel → HTTP 200; пустая история — 200 с Items = [] (не 404).
Ошибки и failure modes
| Код | HTTP status | Условие | Сообщение | Retry |
|---|
VALIDATION_FAILED | 400 | ChatId = Empty, Take вне 1..100, неизвестный Status, From > To | «Проверьте параметры запроса» | no retry |
MSG_CHAT_ACCESS_DENIED | 403 | актор не активный участник Deal-чата | «Нет доступа к чату» | no retry |
Несуществующий/чужой ChatId без членства скрывается как MSG_CHAT_ACCESS_DENIED (не раскрываем наличие чата).
Acceptance Criteria
- История (happy). Дано: актор — активный участник Deal-чата с несколькими прошедшими конференциями. Когда
запрашивает без фильтров. Тогда
200 со страницей StartedAt desc (tiebreak Id desc), Total по чату,
каждая запись с DurationSeconds/ParticipantCount/пометкой записи.
- Фильтр «только с записью». Дано: часть конференций велась с записью. Когда
RecordedOnly = true. Тогда в
выдаче только конференции с привязанной записью (RecordingId != null).
- Окно по дате. Дано:
From/To заданы. Когда фильтрует. Тогда возвращаются только сессии с
StartedAt ∈ [From, To]; при From > To — 400 VALIDATION_FAILED.
- Пустая история. Дано: в чате не было конференций. Когда запрашивает. Тогда
200 c Items = [], Total = 0
(не 404).
- Не участник / чужой чат. Дано: актор не активный участник чата. Когда запрашивает. Тогда
403 MSG_CHAT_ACCESS_DENIED (наличие чужого чата не раскрывается).
- Некорректная пагинация/enum. Дано:
Take вне 1..100 или неизвестный Status. Когда запрашивает. Тогда
400 VALIDATION_FAILED.
Совместимость и наблюдаемость
- Новые optional поля/фильтры — additive; удаление/переименование/смена типа поля или значения enum — breaking
(migration + rollout). Unknown enum во входе — ошибка валидации (не игнор).
- Logs:
conference log listed (ChatId, набор фильтров, Total); metrics:
messenger_conference_list_total{result}, latency p95 (< 500 мс, SLO списков); traces — сквозной trace
(traceparent); dashboard pin-messenger.
Обратные ссылки
Автоссылки: где используется этот документ.
Связанные документы