API

Обзор

Слой API с самого начала служит границей между runtime (веб-клиентом), состоянием комнаты и медиасервисами. Контракты M0 намеренно узкие, а их версии задаёт схема манифеста.

Эндпоинты

GET /health

Возвращает признак того, что сервис работает (liveness). Нужен для smoke-проверок локально и на staging.

Ответ:

{
  "status": "ok",
  "service": "api",
  "port": 4000
}

GET /api/rooms/:roomId/manifest

Возвращает манифест комнаты, который runtime читает при запуске.

Структура ответа:

{
  "schemaVersion": 1,
  "tenantId": "demo-tenant",
  "roomId": "demo-room",
  "template": "meeting-room-basic",
  "features": {
    "voice": true,
    "spatialAudio": true,
    "screenShare": false
  },
  "quality": {
    "default": "desktop-standard",
    "mobile": "mobile-lite",
    "xr": "xr"
  },
  "access": {
    "joinMode": "link",
    "guestAllowed": true
  }
}

POST /api/tokens/state

Возвращает короткоживущий подписанный токен сессии комнаты. Его используют runtime, apps/room-state и выдача медиатокенов.

Запрос:

{
  "roomId": "demo-room",
  "participantId": "p1",
  "displayName": "Guest",
  "requestedRole": "guest"
}

Ответ:

{
  "token": "base64url-payload.hmac-signature",
  "expiresInSeconds": 900,
  "sessionId": "session-id",
  "role": "guest",
  "permissions": ["room.join", "audio.join", "surface.view"]
}

Подписанная полезная нагрузка содержит claims tenantId, roomId, participantId, displayName, role, необязательный roleSource, permissions, sessionId, iat, exp и jti. При проверке токена сервер приводит права в соответствие с подписанной ролью.

POST /api/tokens/media

Возвращает данные токена для подключения к медиаплоскости LiveKit.

Требует заголовок Authorization: Bearer <room-session-token>. Токен сессии должен относиться к запрошенным комнате и участнику. Разрешения на публикацию API выводит из подписанных прав комнаты и не доверяет ролям, которые передал вызывающий.

Запрос:

{
  "roomId": "demo-room",
  "participantId": "p1",
  "canPublishAudio": true,
  "canPublishVideo": false
}

Тот же токен сессии нужен и эндпоинтам, которые меняют данные runtime:

Ответ:

{
  "token": "base64url-encoded-payload",
  "expiresInSeconds": 900,
  "livekitUrl": "ws://localhost:7880"
}

Аутентификация и авторизация в control plane

Защищённые действия control plane по умолчанию запрещены. Для них нужен либо x-vrata-admin-token: <CONTROL_PLANE_ADMIN_TOKEN>, либо Authorization: Bearer <room-session-token>.

Оператора или администратора удостоверяет только заголовок с CONTROL_PLANE_ADMIN_TOKEN. Подписанные токены сессии комнаты разрешают лишь явно допущенные действия в пределах комнаты; роль admin в сессии комнаты не считается администратором control plane.

Действия ведущего в control plane требуют доверенного источника роли в сессии комнаты. Токены, выпущенные в режиме dev-ролей через query-параметр, годятся для runtime, но для действий ведущего в control plane отклоняются.

Если идентификация не передана, возвращается 401 с reason: "missing_identity". Если идентификация верна, но заявленного права нет, возвращается 403 с reason: "permission_denied".

Текущая матрица прав описана в docs/security/permissions.md. Защищены такие группы эндпоинтов:

Каждое решение об авторизации защищённого действия попадает в аудит control plane с полями requestId, actor, action, object, permission и result. Операторы могут просмотреть журнал в памяти ограниченного размера через GET /api/audit/control-plane, если передадут идентификацию администратора.

Документы комнаты и медиа для показа

Право document.present есть у ролей presenter, host и у операторской роли admin. Участники и гости могут только смотреть показ, но не управлять им. Изображения ограничены 16 384 пикселями по каждой стороне и 67 млн пикселей в сумме, видео — четырьмя часами. Общий предел размера загрузки для PDF, изображений и видео задаёт DOCUMENT_UPLOAD_MAX_BYTES, а число страниц — PDF_PRESENTATION_MAX_PAGES. Видео намеренно отдаётся из того же blob загрузки ограниченного размера: адаптивного стриминга и перекодирования нет.

Примечания

Права control plane

Способы идентификации

Защищённые действия control plane принимают один из двух способов идентификации:

Без идентификации возвращается 401. Недействительный токен тоже даёт 401. Верная идентификация без нужного права даёт 403.

Права ведущего в сессии комнаты требуют доверенного источника роли в подписанном токене. Токены, выпущенные в режиме dev-ролей через query-параметр (?role=host / requestedRole=host), годятся для runtime, но для действий ведущего в control plane не считаются доверенными.

Матрица прав

Право Группа эндпоинтов Токен администратора Сессия ведущего в комнате Участник Гость
tenant.write POST/PATCH/DELETE /api/tenants да нет нет нет
room.create POST /api/rooms да нет нет нет
room.update PATCH /api/rooms/:roomId да нет нет нет
room.bind-scene-bundle POST /api/rooms/:roomId/bind-scene-bundle да только своя комната нет нет
room.delete DELETE /api/rooms/:roomId да нет нет нет
asset.write POST/PATCH/DELETE /api/assets да нет нет нет
scene-bundle.write эндпоинты пакетов сцен: создание, версии, статус, текущая версия да нет нет нет
xr-telemetry.read GET /api/rooms/:roomId/xr-telemetry да только своя комната нет нет
audit.read GET /api/audit/control-plane да нет нет нет

Подписанные роли сессии комнаты не удостоверяют оператора. Токен сессии комнаты с ролью admin всё равно не получает административных прав control plane, если в запросе нет заголовка CONTROL_PLANE_ADMIN_TOKEN.

Эндпоинтов для жизненного цикла ссылок-приглашений в текущем API нет. Закрытый доступ к комнатам, а также создание, отзыв и использование приглашений относятся к VRATA-FEAT-014. Когда эти эндпоинты появятся, они должны объявлять явные права и писать записи в аудит control plane.

Публичные эндпоинты runtime

Эндпоинты для запуска runtime и чтения данных публичны намеренно и не должны менять состояние тенантов или комнат:

Журнал аудита

Каждое решение об авторизации защищённого действия control plane записывается структурированным событием аудита в stdout и в журнал в памяти ограниченного размера, доступный для просмотра.

Записи аудита содержат:

Чтобы сопоставить запросы клиента с записями аудита, используйте x-request-id.

Источник: docs/api-contracts.md, docs/security/permissions.md в vrata-labs/platform на ревизии 380b2e7ff1dd, лицензия Apache-2.0. GitHub