947 lines
30 KiB
YAML
947 lines
30 KiB
YAML
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
|