openapi: 3.1.0

info:
    title: Bigscreen Cloud Admin API
    version: "0"
    summary: Internal admin API on cloud_api — rooms, sessions, media servers, social.
    description: |
        Admin endpoints exposed by [`cloud/cloud_api/cloud_api.ts`](../../cloud/cloud_api/cloud_api.ts)
        under the `/admin/*` prefix. These let staff inspect and mutate the live
        multiplayer state — rooms, occupants, media servers, screens, shared
        activities, social profiles, and notifications. Powered by the
        `cloud-admin-api` bearer key and an admin access token.

        > Distinct from the bigger [`Bigscreen Admin API`](./scalar/) on
        > `apps/admin_api`, which covers the rest of the admin surface
        > (factory pipeline, fabricator, shipping, OAuth, etc.). The two share
        > some component schemas (e.g. `AdminAccount`) but are separate
        > deployments with separate API keys.

        ## Auth at a glance

        Every `/admin/*` request needs **two** headers:

        | Header | Value |
        |--------|-------|
        | `Authorization` | `Bearer <cloud-admin-api key>` |
        | `x-access-token` | A JWT obtained from the public auth API |

        The JWT's account must hold one of the access policies the endpoint
        requires (`Moderator`, `Admin`, `SuperUser`). Policies are listed under
        each endpoint's `x-access-policies` extension.

        ## Spec layout

        The OpenAPI source is split per handler module under
        `docs/openapi/cloud-modules/*.yaml`, joined by `$ref` from this root
        file. The bundled artifact at `docs/openapi/cloud-admin-api.bundled.yaml`
        is what the Scalar renderer reads — regenerate it with
        `npx -y @redocly/cli@latest bundle docs/openapi/cloud-admin-api.yaml -o docs/openapi/cloud-admin-api.bundled.yaml`
        after any edit.

servers:
    - url: http://localhost:3002
      description: Local dev (started by `yarn dev` — port `CLOUD_API_SERVER_PORT` defaults to 3002).
    - url: https://cloud-api.internal.bigscreenvr.com
      description: Production.

tags:
    - name: Stats
      description: |
          Realtime counts, schema enumerations, and other readouts that don't
          fit elsewhere.
    - name: Rooms
      description: |
          Room CRUD over the persistent `StoredRoom` table plus realtime
          inspection / control of `LiveRoom` instances. Drives the Arda rooms
          dashboard.
    - name: Accounts
      description: |
          Live-user functions on a Bigscreen account — listing connections,
          messaging, force-disconnect, and a per-account room listing.
    - name: Network
      description: |
          Cluster operations — media-server registry / activation status, plus
          a SuperUser-only Redis introspection toolkit (prefix-allowlisted,
          audit-logged).
    - name: Screens
      description: |
          Screen CRUD — fetch a screen, change its media session, update its
          settings, or delete it.
    - name: Activities
      description: |
          Shared activities (games, co-watching, etc.) — admin CRUD plus
          per-account listing.
    - name: Social
      description: |
          Social graph admin — profile lookup, history, graph (friend / follow /
          block) inspection and mutation, stats, and notifications.

security:
    - cloudAdminApiKey: []
      cloudAdminAccessToken: []

paths:
    /admin/statistics:
        $ref: "./cloud-modules/stats.yaml#/~1admin~1statistics"
    /admin/schemas:
        $ref: "./cloud-modules/stats.yaml#/~1admin~1schemas"

    /admin/room:
        $ref: "./cloud-modules/rooms.yaml#/~1admin~1room"
    /admin/room/{roomId}:
        $ref: "./cloud-modules/rooms.yaml#/~1admin~1room~1{roomId}"
    /admin/room/{roomId}/live:
        $ref: "./cloud-modules/rooms.yaml#/~1admin~1room~1{roomId}~1live"
    /admin/room/{roomId}/history:
        $ref: "./cloud-modules/rooms.yaml#/~1admin~1room~1{roomId}~1history"
    /admin/room/{roomId}/users/{userSessionId}/kick:
        $ref: "./cloud-modules/rooms.yaml#/~1admin~1room~1{roomId}~1users~1{userSessionId}~1kick"
    /admin/room/{roomId}/users/{userSessionId}/eject:
        $ref: "./cloud-modules/rooms.yaml#/~1admin~1room~1{roomId}~1users~1{userSessionId}~1eject"
    /admin/rooms/live:
        $ref: "./cloud-modules/rooms.yaml#/~1admin~1rooms~1live"
    /admin/rooms/environments:
        $ref: "./cloud-modules/rooms.yaml#/~1admin~1rooms~1environments"
    /admin/rooms/all:
        $ref: "./cloud-modules/rooms.yaml#/~1admin~1rooms~1all"

    /admin/account/{bigscreenAccountId}/message:
        $ref: "./cloud-modules/accounts.yaml#/~1admin~1account~1{bigscreenAccountId}~1message"
    /admin/account/{bigscreenAccountId}/connections:
        $ref: "./cloud-modules/accounts.yaml#/~1admin~1account~1{bigscreenAccountId}~1connections"
    /admin/account/{bigscreenAccountId}/rooms:
        $ref: "./cloud-modules/accounts.yaml#/~1admin~1account~1{bigscreenAccountId}~1rooms"
    /admin/account/{bigscreenAccountId}/disconnect:
        $ref: "./cloud-modules/accounts.yaml#/~1admin~1account~1{bigscreenAccountId}~1disconnect"

    /admin/network/media-servers:
        $ref: "./cloud-modules/network.yaml#/~1admin~1network~1media-servers"
    /admin/network/media-server/{mediaServerId}:
        $ref: "./cloud-modules/network.yaml#/~1admin~1network~1media-server~1{mediaServerId}"
    /admin/network/redis:
        $ref: "./cloud-modules/network.yaml#/~1admin~1network~1redis"
    /admin/network/redis-info:
        $ref: "./cloud-modules/network.yaml#/~1admin~1network~1redis-info"

    /admin/screen/{screenId}:
        $ref: "./cloud-modules/screens.yaml#/~1admin~1screen~1{screenId}"
    /admin/screen/{screenId}/session:
        $ref: "./cloud-modules/screens.yaml#/~1admin~1screen~1{screenId}~1session"

    /admin/activity:
        $ref: "./cloud-modules/activities.yaml#/~1admin~1activity"
    /admin/activity/{activityId}:
        $ref: "./cloud-modules/activities.yaml#/~1admin~1activity~1{activityId}"
    /admin/account/{bigscreenAccountId}/activity/{activityId}:
        $ref: "./cloud-modules/activities.yaml#/~1admin~1account~1{bigscreenAccountId}~1activity~1{activityId}"
    /admin/account/{bigscreenAccountId}/activities:
        $ref: "./cloud-modules/activities.yaml#/~1admin~1account~1{bigscreenAccountId}~1activities"

    /admin/account/{bigscreenAccountId}/social/profile:
        $ref: "./cloud-modules/social.yaml#/~1admin~1account~1{bigscreenAccountId}~1social~1profile"
    /admin/account/{bigscreenAccountId}/social_profiles:
        $ref: "./cloud-modules/social.yaml#/~1admin~1account~1{bigscreenAccountId}~1social_profiles"
    /admin/account/{bigscreenAccountId}/social/history/{historyItemType}:
        $ref: "./cloud-modules/social.yaml#/~1admin~1account~1{bigscreenAccountId}~1social~1history~1{historyItemType}"
    /admin/account/{bigscreenAccountId}/social/graph/{socialGraphType}:
        $ref: "./cloud-modules/social.yaml#/~1admin~1account~1{bigscreenAccountId}~1social~1graph~1{socialGraphType}"
    /admin/social/graph/{graphItemId}:
        $ref: "./cloud-modules/social.yaml#/~1admin~1social~1graph~1{graphItemId}"
    /admin/account/{bigscreenAccountId}/social/stats:
        $ref: "./cloud-modules/social.yaml#/~1admin~1account~1{bigscreenAccountId}~1social~1stats"
    /admin/account/{bigscreenAccountId}/social/notifications:
        $ref: "./cloud-modules/social.yaml#/~1admin~1account~1{bigscreenAccountId}~1social~1notifications"
    /admin/account/{bigscreenAccountId}/social/notification:
        $ref: "./cloud-modules/social.yaml#/~1admin~1account~1{bigscreenAccountId}~1social~1notification"
    /admin/social/notification/{notificationId}:
        $ref: "./cloud-modules/social.yaml#/~1admin~1social~1notification~1{notificationId}"
    /admin/social/notification/{notificationId}/accept:
        $ref: "./cloud-modules/social.yaml#/~1admin~1social~1notification~1{notificationId}~1accept"

components:
    securitySchemes:
        cloudAdminApiKey:
            type: http
            scheme: bearer
            bearerFormat: CloudAdminApiKey-or-OAuthJWT
            description: |
                Bearer key registered for the `cloud-admin-api` application. May
                be a 64-character app key or, when OAuth is enabled, an OAuth 2.0
                JWT — admission shape determines which path runs.
        cloudAdminAccessToken:
            type: apiKey
            in: header
            name: x-access-token
            description: |
                JWT for the staff account the request is acting as. Must carry an
                `AccessPolicy` admitted by the per-endpoint `x-access-policies`.

    responses:
        Unauthorized:
            description: Missing or invalid `Authorization` / `x-access-token`.
            content:
                application/json:
                    schema: { $ref: "#/components/schemas/Error" }
        Forbidden:
            description: Authenticated but lacks the required access policy.
            content:
                application/json:
                    schema: { $ref: "#/components/schemas/Error" }

    schemas:
        Error:
            type: object
            required: [error]
            properties:
                error: { type: string }
                details:
                    description: Optional structured details.
            example:
                error: "Forbidden"
                details: { requiredPolicy: "Moderator" }
