feat: game lobby service
This commit is contained in:
@@ -0,0 +1,946 @@
|
||||
openapi: 3.0.3
|
||||
info:
|
||||
title: Galaxy Game Lobby Service Internal REST API
|
||||
version: v1
|
||||
description: |
|
||||
This specification documents the internal trusted REST contract of
|
||||
`galaxy/lobby` served on `LOBBY_INTERNAL_HTTP_ADDR` (default `:8095`).
|
||||
|
||||
This port is not reachable from the public internet. Two caller classes
|
||||
use it:
|
||||
|
||||
**Game Master integration paths** (`/api/v1/internal/…`):
|
||||
- `GET /api/v1/internal/games/{game_id}` — game detail read for
|
||||
`Game Master` and internal tooling
|
||||
- `GET /api/v1/internal/games/{game_id}/memberships` — full membership
|
||||
list for `Game Master` authorization checks
|
||||
|
||||
Note: Lobby calls Game Master synchronously after a successful
|
||||
container start (outgoing). The `register-runtime` endpoint lives on
|
||||
Game Master's surface, not on Lobby's. Lobby does not accept inbound
|
||||
`register-runtime` requests.
|
||||
|
||||
**Admin Service paths** (same `/api/v1/lobby/…` paths as the public port):
|
||||
- `Admin Service` enforces the system-admin role check at the gateway
|
||||
boundary before calling these endpoints
|
||||
- `X-User-ID` is NOT present on calls from `Admin Service`; Lobby treats
|
||||
all callers on this port as trusted and performs no user-level auth
|
||||
|
||||
Transport rules:
|
||||
- request bodies are strict JSON only; unknown fields are rejected
|
||||
- error responses use `{ "error": { "code", "message" } }`
|
||||
- stable error codes match the public contract: `invalid_request`,
|
||||
`conflict`, `subject_not_found`, `forbidden`, `internal_error`,
|
||||
and `service_unavailable`
|
||||
servers:
|
||||
- url: http://localhost:8095
|
||||
description: Default local internal listener for Game Lobby Service.
|
||||
tags:
|
||||
- name: GMIntegration
|
||||
description: Game Master integration paths for runtime binding and membership reads.
|
||||
- name: AdminGames
|
||||
description: Admin-mirrored game lifecycle paths called by Admin Service.
|
||||
- name: AdminApplications
|
||||
description: Admin-mirrored application approval paths called by Admin Service.
|
||||
- name: AdminMemberships
|
||||
description: Admin-mirrored membership operation paths called by Admin Service.
|
||||
- name: Probes
|
||||
description: Health and readiness probes.
|
||||
paths:
|
||||
/healthz:
|
||||
get:
|
||||
tags:
|
||||
- Probes
|
||||
operationId: internalHealthz
|
||||
summary: Internal listener health probe
|
||||
responses:
|
||||
"200":
|
||||
description: Service is alive.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ProbeResponse"
|
||||
examples:
|
||||
ok:
|
||||
value:
|
||||
status: ok
|
||||
/readyz:
|
||||
get:
|
||||
tags:
|
||||
- Probes
|
||||
operationId: internalReadyz
|
||||
summary: Internal listener readiness probe
|
||||
responses:
|
||||
"200":
|
||||
description: Service is ready to serve traffic.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ProbeResponse"
|
||||
examples:
|
||||
ready:
|
||||
value:
|
||||
status: ready
|
||||
/api/v1/internal/games/{game_id}:
|
||||
get:
|
||||
tags:
|
||||
- GMIntegration
|
||||
operationId: internalGetGame
|
||||
summary: Get one game record for Game Master or internal tooling
|
||||
description: |
|
||||
Returns the full game record without visibility restrictions. Intended
|
||||
for use by `Game Master` and internal administrative tooling.
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/GameIDPath"
|
||||
responses:
|
||||
"200":
|
||||
description: Full game record.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/GameRecord"
|
||||
"404":
|
||||
$ref: "#/components/responses/NotFoundError"
|
||||
"500":
|
||||
$ref: "#/components/responses/InternalError"
|
||||
"503":
|
||||
$ref: "#/components/responses/ServiceUnavailableError"
|
||||
/api/v1/internal/games/{game_id}/memberships:
|
||||
get:
|
||||
tags:
|
||||
- GMIntegration
|
||||
operationId: internalListMemberships
|
||||
summary: List all memberships of a game for Game Master
|
||||
description: |
|
||||
Returns all memberships of the game without visibility restrictions.
|
||||
Intended for `Game Master` authorization checks during command routing.
|
||||
Pagination applies.
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/GameIDPath"
|
||||
- $ref: "#/components/parameters/PageSize"
|
||||
- $ref: "#/components/parameters/PageToken"
|
||||
responses:
|
||||
"200":
|
||||
description: One page of membership records.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/MembershipListResponse"
|
||||
"400":
|
||||
$ref: "#/components/responses/InvalidRequestError"
|
||||
"404":
|
||||
$ref: "#/components/responses/NotFoundError"
|
||||
"500":
|
||||
$ref: "#/components/responses/InternalError"
|
||||
"503":
|
||||
$ref: "#/components/responses/ServiceUnavailableError"
|
||||
/api/v1/lobby/games:
|
||||
post:
|
||||
tags:
|
||||
- AdminGames
|
||||
operationId: adminCreateGame
|
||||
summary: Create a new game record (admin)
|
||||
description: |
|
||||
Creates a new game record in `draft` status. Used by `Admin Service`
|
||||
for public game creation. Lobby trusts the caller and does not enforce
|
||||
a user-level eligibility check on this port.
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/CreateGameRequest"
|
||||
responses:
|
||||
"201":
|
||||
description: Game record created in draft status.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/GameRecord"
|
||||
"400":
|
||||
$ref: "#/components/responses/InvalidRequestError"
|
||||
"500":
|
||||
$ref: "#/components/responses/InternalError"
|
||||
"503":
|
||||
$ref: "#/components/responses/ServiceUnavailableError"
|
||||
get:
|
||||
tags:
|
||||
- AdminGames
|
||||
operationId: adminListGames
|
||||
summary: List games (admin, unrestricted)
|
||||
description: |
|
||||
Returns a paginated list of games without visibility restrictions.
|
||||
Used by `Admin Service` for administrative oversight.
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/PageSize"
|
||||
- $ref: "#/components/parameters/PageToken"
|
||||
responses:
|
||||
"200":
|
||||
description: One page of game records.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/GameListResponse"
|
||||
"400":
|
||||
$ref: "#/components/responses/InvalidRequestError"
|
||||
"500":
|
||||
$ref: "#/components/responses/InternalError"
|
||||
"503":
|
||||
$ref: "#/components/responses/ServiceUnavailableError"
|
||||
/api/v1/lobby/games/{game_id}:
|
||||
get:
|
||||
tags:
|
||||
- AdminGames
|
||||
operationId: adminGetGame
|
||||
summary: Get one game record (admin, unrestricted)
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/GameIDPath"
|
||||
responses:
|
||||
"200":
|
||||
description: Full game record without visibility restrictions.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/GameRecord"
|
||||
"404":
|
||||
$ref: "#/components/responses/NotFoundError"
|
||||
"500":
|
||||
$ref: "#/components/responses/InternalError"
|
||||
"503":
|
||||
$ref: "#/components/responses/ServiceUnavailableError"
|
||||
patch:
|
||||
tags:
|
||||
- AdminGames
|
||||
operationId: adminUpdateGame
|
||||
summary: Update mutable fields of a game record (admin)
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/GameIDPath"
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/UpdateGameRequest"
|
||||
responses:
|
||||
"200":
|
||||
description: Updated game record.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/GameRecord"
|
||||
"400":
|
||||
$ref: "#/components/responses/InvalidRequestError"
|
||||
"404":
|
||||
$ref: "#/components/responses/NotFoundError"
|
||||
"409":
|
||||
$ref: "#/components/responses/ConflictError"
|
||||
"500":
|
||||
$ref: "#/components/responses/InternalError"
|
||||
"503":
|
||||
$ref: "#/components/responses/ServiceUnavailableError"
|
||||
/api/v1/lobby/games/{game_id}/open-enrollment:
|
||||
post:
|
||||
tags:
|
||||
- AdminGames
|
||||
operationId: adminOpenEnrollment
|
||||
summary: Transition a draft game to enrollment_open (admin)
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/GameIDPath"
|
||||
responses:
|
||||
"200":
|
||||
description: Updated game record with status enrollment_open.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/GameRecord"
|
||||
"404":
|
||||
$ref: "#/components/responses/NotFoundError"
|
||||
"409":
|
||||
$ref: "#/components/responses/ConflictError"
|
||||
"500":
|
||||
$ref: "#/components/responses/InternalError"
|
||||
"503":
|
||||
$ref: "#/components/responses/ServiceUnavailableError"
|
||||
/api/v1/lobby/games/{game_id}/ready-to-start:
|
||||
post:
|
||||
tags:
|
||||
- AdminGames
|
||||
operationId: adminManualReadyToStart
|
||||
summary: Manually close enrollment and transition to ready_to_start (admin)
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/GameIDPath"
|
||||
responses:
|
||||
"200":
|
||||
description: Updated game record with status ready_to_start.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/GameRecord"
|
||||
"404":
|
||||
$ref: "#/components/responses/NotFoundError"
|
||||
"409":
|
||||
$ref: "#/components/responses/ConflictError"
|
||||
"500":
|
||||
$ref: "#/components/responses/InternalError"
|
||||
"503":
|
||||
$ref: "#/components/responses/ServiceUnavailableError"
|
||||
/api/v1/lobby/games/{game_id}/start:
|
||||
post:
|
||||
tags:
|
||||
- AdminGames
|
||||
operationId: adminStartGame
|
||||
summary: Initiate the game start sequence (admin)
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/GameIDPath"
|
||||
responses:
|
||||
"200":
|
||||
description: Updated game record with status starting.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/GameRecord"
|
||||
"404":
|
||||
$ref: "#/components/responses/NotFoundError"
|
||||
"409":
|
||||
$ref: "#/components/responses/ConflictError"
|
||||
"500":
|
||||
$ref: "#/components/responses/InternalError"
|
||||
"503":
|
||||
$ref: "#/components/responses/ServiceUnavailableError"
|
||||
/api/v1/lobby/games/{game_id}/pause:
|
||||
post:
|
||||
tags:
|
||||
- AdminGames
|
||||
operationId: adminPauseGame
|
||||
summary: Apply a platform-level pause to a running game (admin)
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/GameIDPath"
|
||||
responses:
|
||||
"200":
|
||||
description: Updated game record with status paused.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/GameRecord"
|
||||
"404":
|
||||
$ref: "#/components/responses/NotFoundError"
|
||||
"409":
|
||||
$ref: "#/components/responses/ConflictError"
|
||||
"500":
|
||||
$ref: "#/components/responses/InternalError"
|
||||
"503":
|
||||
$ref: "#/components/responses/ServiceUnavailableError"
|
||||
/api/v1/lobby/games/{game_id}/resume:
|
||||
post:
|
||||
tags:
|
||||
- AdminGames
|
||||
operationId: adminResumeGame
|
||||
summary: Resume a paused game (admin)
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/GameIDPath"
|
||||
responses:
|
||||
"200":
|
||||
description: Updated game record with status running.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/GameRecord"
|
||||
"404":
|
||||
$ref: "#/components/responses/NotFoundError"
|
||||
"409":
|
||||
$ref: "#/components/responses/ConflictError"
|
||||
"500":
|
||||
$ref: "#/components/responses/InternalError"
|
||||
"503":
|
||||
$ref: "#/components/responses/ServiceUnavailableError"
|
||||
/api/v1/lobby/games/{game_id}/cancel:
|
||||
post:
|
||||
tags:
|
||||
- AdminGames
|
||||
operationId: adminCancelGame
|
||||
summary: Cancel a game that has not yet started running (admin)
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/GameIDPath"
|
||||
responses:
|
||||
"200":
|
||||
description: Updated game record with status cancelled.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/GameRecord"
|
||||
"404":
|
||||
$ref: "#/components/responses/NotFoundError"
|
||||
"409":
|
||||
$ref: "#/components/responses/ConflictError"
|
||||
"500":
|
||||
$ref: "#/components/responses/InternalError"
|
||||
"503":
|
||||
$ref: "#/components/responses/ServiceUnavailableError"
|
||||
/api/v1/lobby/games/{game_id}/retry-start:
|
||||
post:
|
||||
tags:
|
||||
- AdminGames
|
||||
operationId: adminRetryStart
|
||||
summary: Retry a failed start attempt (admin)
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/GameIDPath"
|
||||
responses:
|
||||
"200":
|
||||
description: Updated game record with status ready_to_start.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/GameRecord"
|
||||
"404":
|
||||
$ref: "#/components/responses/NotFoundError"
|
||||
"409":
|
||||
$ref: "#/components/responses/ConflictError"
|
||||
"500":
|
||||
$ref: "#/components/responses/InternalError"
|
||||
"503":
|
||||
$ref: "#/components/responses/ServiceUnavailableError"
|
||||
/api/v1/lobby/games/{game_id}/applications/{application_id}/approve:
|
||||
post:
|
||||
tags:
|
||||
- AdminApplications
|
||||
operationId: adminApproveApplication
|
||||
summary: Approve a submitted application (admin)
|
||||
description: |
|
||||
Approves a submitted application, reserves the race name, and creates
|
||||
an active membership. On success, `lobby.membership.approved`
|
||||
notification intent is published to the applicant.
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/GameIDPath"
|
||||
- $ref: "#/components/parameters/ApplicationIDPath"
|
||||
responses:
|
||||
"200":
|
||||
description: Active membership created for the approved applicant.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/MembershipRecord"
|
||||
"404":
|
||||
$ref: "#/components/responses/NotFoundError"
|
||||
"409":
|
||||
$ref: "#/components/responses/ConflictError"
|
||||
"500":
|
||||
$ref: "#/components/responses/InternalError"
|
||||
"503":
|
||||
$ref: "#/components/responses/ServiceUnavailableError"
|
||||
/api/v1/lobby/games/{game_id}/applications/{application_id}/reject:
|
||||
post:
|
||||
tags:
|
||||
- AdminApplications
|
||||
operationId: adminRejectApplication
|
||||
summary: Reject a submitted application (admin)
|
||||
description: |
|
||||
Rejects a submitted application and releases any pending race name
|
||||
reservation. On success, `lobby.membership.rejected` notification
|
||||
intent is published to the applicant.
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/GameIDPath"
|
||||
- $ref: "#/components/parameters/ApplicationIDPath"
|
||||
responses:
|
||||
"200":
|
||||
description: Application record with status rejected.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ApplicationRecord"
|
||||
"404":
|
||||
$ref: "#/components/responses/NotFoundError"
|
||||
"409":
|
||||
$ref: "#/components/responses/ConflictError"
|
||||
"500":
|
||||
$ref: "#/components/responses/InternalError"
|
||||
"503":
|
||||
$ref: "#/components/responses/ServiceUnavailableError"
|
||||
/api/v1/lobby/games/{game_id}/memberships:
|
||||
get:
|
||||
tags:
|
||||
- AdminMemberships
|
||||
operationId: adminListMemberships
|
||||
summary: List memberships of a game (admin, unrestricted)
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/GameIDPath"
|
||||
- $ref: "#/components/parameters/PageSize"
|
||||
- $ref: "#/components/parameters/PageToken"
|
||||
responses:
|
||||
"200":
|
||||
description: One page of membership records.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/MembershipListResponse"
|
||||
"400":
|
||||
$ref: "#/components/responses/InvalidRequestError"
|
||||
"404":
|
||||
$ref: "#/components/responses/NotFoundError"
|
||||
"500":
|
||||
$ref: "#/components/responses/InternalError"
|
||||
"503":
|
||||
$ref: "#/components/responses/ServiceUnavailableError"
|
||||
/api/v1/lobby/games/{game_id}/memberships/{membership_id}/remove:
|
||||
post:
|
||||
tags:
|
||||
- AdminMemberships
|
||||
operationId: adminRemoveMember
|
||||
summary: Remove a member from a game (admin)
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/GameIDPath"
|
||||
- $ref: "#/components/parameters/MembershipIDPath"
|
||||
responses:
|
||||
"200":
|
||||
description: Updated membership record with status removed.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/MembershipRecord"
|
||||
"404":
|
||||
$ref: "#/components/responses/NotFoundError"
|
||||
"409":
|
||||
$ref: "#/components/responses/ConflictError"
|
||||
"500":
|
||||
$ref: "#/components/responses/InternalError"
|
||||
"503":
|
||||
$ref: "#/components/responses/ServiceUnavailableError"
|
||||
/api/v1/lobby/games/{game_id}/memberships/{membership_id}/block:
|
||||
post:
|
||||
tags:
|
||||
- AdminMemberships
|
||||
operationId: adminBlockMember
|
||||
summary: Apply a platform-level block to a member (admin)
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/GameIDPath"
|
||||
- $ref: "#/components/parameters/MembershipIDPath"
|
||||
responses:
|
||||
"200":
|
||||
description: Updated membership record with status blocked.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/MembershipRecord"
|
||||
"404":
|
||||
$ref: "#/components/responses/NotFoundError"
|
||||
"409":
|
||||
$ref: "#/components/responses/ConflictError"
|
||||
"500":
|
||||
$ref: "#/components/responses/InternalError"
|
||||
"503":
|
||||
$ref: "#/components/responses/ServiceUnavailableError"
|
||||
components:
|
||||
parameters:
|
||||
GameIDPath:
|
||||
name: game_id
|
||||
in: path
|
||||
required: true
|
||||
description: Opaque stable game identifier.
|
||||
schema:
|
||||
type: string
|
||||
ApplicationIDPath:
|
||||
name: application_id
|
||||
in: path
|
||||
required: true
|
||||
description: Opaque stable application identifier.
|
||||
schema:
|
||||
type: string
|
||||
MembershipIDPath:
|
||||
name: membership_id
|
||||
in: path
|
||||
required: true
|
||||
description: Opaque stable membership identifier.
|
||||
schema:
|
||||
type: string
|
||||
PageSize:
|
||||
name: page_size
|
||||
in: query
|
||||
required: false
|
||||
description: Maximum number of items to return. Default is `50`; maximum is `200`.
|
||||
schema:
|
||||
type: integer
|
||||
minimum: 1
|
||||
maximum: 200
|
||||
default: 50
|
||||
PageToken:
|
||||
name: page_token
|
||||
in: query
|
||||
required: false
|
||||
description: Opaque continuation token returned as `next_page_token` in a previous response.
|
||||
schema:
|
||||
type: string
|
||||
schemas:
|
||||
GameRecord:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required:
|
||||
- game_id
|
||||
- game_name
|
||||
- game_type
|
||||
- owner_user_id
|
||||
- status
|
||||
- min_players
|
||||
- max_players
|
||||
- start_gap_hours
|
||||
- start_gap_players
|
||||
- enrollment_ends_at
|
||||
- turn_schedule
|
||||
- target_engine_version
|
||||
- created_at
|
||||
- updated_at
|
||||
- current_turn
|
||||
- runtime_status
|
||||
- engine_health_summary
|
||||
properties:
|
||||
game_id:
|
||||
type: string
|
||||
description: Opaque stable game identifier in game-* form.
|
||||
game_name:
|
||||
type: string
|
||||
description: Human-readable game name; mutable in draft status.
|
||||
description:
|
||||
type: string
|
||||
description: Optional game description; mutable in draft and enrollment_open.
|
||||
game_type:
|
||||
type: string
|
||||
enum:
|
||||
- public
|
||||
- private
|
||||
description: Game visibility and enrollment model.
|
||||
owner_user_id:
|
||||
type: string
|
||||
description: Platform user identifier of the private-game owner; empty for public games.
|
||||
status:
|
||||
type: string
|
||||
enum:
|
||||
- draft
|
||||
- enrollment_open
|
||||
- ready_to_start
|
||||
- starting
|
||||
- start_failed
|
||||
- running
|
||||
- paused
|
||||
- finished
|
||||
- cancelled
|
||||
description: Current platform-level lifecycle status.
|
||||
min_players:
|
||||
type: integer
|
||||
description: Minimum approved participants required to proceed to start.
|
||||
max_players:
|
||||
type: integer
|
||||
description: Target roster size that activates the gap window.
|
||||
start_gap_hours:
|
||||
type: integer
|
||||
description: Hours of gap window after max_players is reached.
|
||||
start_gap_players:
|
||||
type: integer
|
||||
description: Additional participants admitted during the gap window.
|
||||
enrollment_ends_at:
|
||||
type: integer
|
||||
format: int64
|
||||
description: UTC Unix seconds; deadline for automatic enrollment close.
|
||||
turn_schedule:
|
||||
type: string
|
||||
description: Five-field cron expression for scheduled turn generation.
|
||||
target_engine_version:
|
||||
type: string
|
||||
description: Semver of the game engine to launch.
|
||||
created_at:
|
||||
type: integer
|
||||
format: int64
|
||||
description: UTC Unix milliseconds; record creation timestamp.
|
||||
updated_at:
|
||||
type: integer
|
||||
format: int64
|
||||
description: UTC Unix milliseconds; last mutation timestamp.
|
||||
started_at:
|
||||
type: integer
|
||||
format: int64
|
||||
description: UTC Unix milliseconds; set when status becomes running.
|
||||
finished_at:
|
||||
type: integer
|
||||
format: int64
|
||||
description: UTC Unix milliseconds; set when status becomes finished.
|
||||
current_turn:
|
||||
type: integer
|
||||
description: Denormalized from Game Master; zero until the game is running.
|
||||
runtime_status:
|
||||
type: string
|
||||
description: Denormalized from Game Master; empty until the game is running.
|
||||
engine_health_summary:
|
||||
type: string
|
||||
description: Denormalized from Game Master; empty until the game is running.
|
||||
runtime_binding:
|
||||
$ref: "#/components/schemas/RuntimeBinding"
|
||||
RuntimeBinding:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
description: |
|
||||
Runtime binding metadata produced by Runtime Manager after a successful
|
||||
container start. Set on the game record only after the start sequence
|
||||
succeeds; absent before then.
|
||||
required:
|
||||
- container_id
|
||||
- engine_endpoint
|
||||
- runtime_job_id
|
||||
- bound_at
|
||||
properties:
|
||||
container_id:
|
||||
type: string
|
||||
description: Engine container identifier assigned by Runtime Manager.
|
||||
engine_endpoint:
|
||||
type: string
|
||||
description: Network address Game Master uses to reach the engine container.
|
||||
runtime_job_id:
|
||||
type: string
|
||||
description: |
|
||||
Source `runtime:job_results` Redis Stream message id (in `<ms>-<seq>`
|
||||
form) that produced this binding. Used for incident investigation.
|
||||
bound_at:
|
||||
type: integer
|
||||
format: int64
|
||||
description: UTC Unix milliseconds when the binding was persisted.
|
||||
ApplicationRecord:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required:
|
||||
- application_id
|
||||
- game_id
|
||||
- applicant_user_id
|
||||
- race_name
|
||||
- status
|
||||
- created_at
|
||||
properties:
|
||||
application_id:
|
||||
type: string
|
||||
game_id:
|
||||
type: string
|
||||
applicant_user_id:
|
||||
type: string
|
||||
race_name:
|
||||
type: string
|
||||
status:
|
||||
type: string
|
||||
enum:
|
||||
- submitted
|
||||
- approved
|
||||
- rejected
|
||||
created_at:
|
||||
type: integer
|
||||
format: int64
|
||||
decided_at:
|
||||
type: integer
|
||||
format: int64
|
||||
MembershipRecord:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required:
|
||||
- membership_id
|
||||
- game_id
|
||||
- user_id
|
||||
- race_name
|
||||
- status
|
||||
- joined_at
|
||||
properties:
|
||||
membership_id:
|
||||
type: string
|
||||
game_id:
|
||||
type: string
|
||||
user_id:
|
||||
type: string
|
||||
race_name:
|
||||
type: string
|
||||
status:
|
||||
type: string
|
||||
enum:
|
||||
- active
|
||||
- removed
|
||||
- blocked
|
||||
joined_at:
|
||||
type: integer
|
||||
format: int64
|
||||
removed_at:
|
||||
type: integer
|
||||
format: int64
|
||||
CreateGameRequest:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required:
|
||||
- game_name
|
||||
- game_type
|
||||
- min_players
|
||||
- max_players
|
||||
- start_gap_hours
|
||||
- start_gap_players
|
||||
- enrollment_ends_at
|
||||
- turn_schedule
|
||||
- target_engine_version
|
||||
properties:
|
||||
game_name:
|
||||
type: string
|
||||
description:
|
||||
type: string
|
||||
game_type:
|
||||
type: string
|
||||
enum:
|
||||
- public
|
||||
- private
|
||||
min_players:
|
||||
type: integer
|
||||
minimum: 1
|
||||
max_players:
|
||||
type: integer
|
||||
minimum: 1
|
||||
start_gap_hours:
|
||||
type: integer
|
||||
minimum: 0
|
||||
start_gap_players:
|
||||
type: integer
|
||||
minimum: 0
|
||||
enrollment_ends_at:
|
||||
type: integer
|
||||
format: int64
|
||||
turn_schedule:
|
||||
type: string
|
||||
target_engine_version:
|
||||
type: string
|
||||
UpdateGameRequest:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
properties:
|
||||
game_name:
|
||||
type: string
|
||||
description:
|
||||
type: string
|
||||
min_players:
|
||||
type: integer
|
||||
minimum: 1
|
||||
max_players:
|
||||
type: integer
|
||||
minimum: 1
|
||||
start_gap_hours:
|
||||
type: integer
|
||||
minimum: 0
|
||||
start_gap_players:
|
||||
type: integer
|
||||
minimum: 0
|
||||
enrollment_ends_at:
|
||||
type: integer
|
||||
format: int64
|
||||
turn_schedule:
|
||||
type: string
|
||||
target_engine_version:
|
||||
type: string
|
||||
GameListResponse:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required:
|
||||
- items
|
||||
properties:
|
||||
items:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/GameRecord"
|
||||
next_page_token:
|
||||
type: string
|
||||
MembershipListResponse:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required:
|
||||
- items
|
||||
properties:
|
||||
items:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/MembershipRecord"
|
||||
next_page_token:
|
||||
type: string
|
||||
ProbeResponse:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required:
|
||||
- status
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
ErrorResponse:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required:
|
||||
- error
|
||||
properties:
|
||||
error:
|
||||
$ref: "#/components/schemas/ErrorBody"
|
||||
ErrorBody:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required:
|
||||
- code
|
||||
- message
|
||||
properties:
|
||||
code:
|
||||
type: string
|
||||
description: Stable internal API error code.
|
||||
message:
|
||||
type: string
|
||||
description: Human-readable trusted error message.
|
||||
responses:
|
||||
InvalidRequestError:
|
||||
description: Request validation failed.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ErrorResponse"
|
||||
examples:
|
||||
invalidRequest:
|
||||
value:
|
||||
error:
|
||||
code: invalid_request
|
||||
message: request is invalid
|
||||
NotFoundError:
|
||||
description: The requested game, application, or membership does not exist.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ErrorResponse"
|
||||
examples:
|
||||
notFound:
|
||||
value:
|
||||
error:
|
||||
code: subject_not_found
|
||||
message: resource not found
|
||||
ConflictError:
|
||||
description: The requested state transition is not allowed from the current status.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ErrorResponse"
|
||||
examples:
|
||||
conflict:
|
||||
value:
|
||||
error:
|
||||
code: conflict
|
||||
message: operation not allowed in current status
|
||||
InternalError:
|
||||
description: Unexpected internal service error.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ErrorResponse"
|
||||
examples:
|
||||
internal:
|
||||
value:
|
||||
error:
|
||||
code: internal_error
|
||||
message: internal server error
|
||||
ServiceUnavailableError:
|
||||
description: An upstream dependency is unavailable.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ErrorResponse"
|
||||
examples:
|
||||
unavailable:
|
||||
value:
|
||||
error:
|
||||
code: service_unavailable
|
||||
message: service is unavailable
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user