openapi: 3.0.3 info: title: Galaxy Game Service REST API version: v1 description: | This specification documents the REST contract of `galaxy/game`. The service hosts a single game instance and exposes endpoints for game initialization, turn advancement, game-state queries, player reports, and batched player command execution. Transport rules: - request bodies are JSON - `PUT /api/v1/command` is rate-limited to one concurrent execution; requests that cannot acquire the execution slot within 100 ms receive `504 Gateway Timeout` - `501 Not Implemented` is returned without a body when the game has not been initialized - validation errors return `400` with `{"error": "message"}` - game-engine errors return `500` with `{"generic_error": "message", "code": integer}` - other internal errors return `500` with `{"error": "message"}` servers: - url: http://localhost:8080 description: Default local listener for Game Service. tags: - name: GameLifecycle description: Game initialization, state retrieval, and turn advancement. - name: PlayerActions description: Player command execution, order validation, and turn-report retrieval. - name: Health description: Technical liveness probes used by Runtime Manager and operator tooling. paths: /api/v1/admin/status: get: tags: - GameLifecycle operationId: adminGetGameStatus summary: Get the current game state description: | Returns the current game state including turn number, stage, and a summary of all players. Returns `501` if the game has not yet been initialized. Routed only from the trusted network segment that connects `Game Master` to the engine container. responses: "200": description: Current game state. content: application/json: schema: $ref: "#/components/schemas/StateResponse" "501": description: Game has not been initialized yet. "500": $ref: "#/components/responses/InternalError" /api/v1/admin/init: post: tags: - GameLifecycle operationId: adminInitGame summary: Initialize a new game description: | Generates a new game instance with the supplied list of races. Requires at least 10 race entries. Routed only from the trusted network segment that connects `Game Master` to the engine container. requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/InitRequest" responses: "201": description: Game initialized successfully. content: application/json: schema: $ref: "#/components/schemas/StateResponse" "400": $ref: "#/components/responses/ValidationError" "500": $ref: "#/components/responses/InternalError" /api/v1/admin/race/banish: post: tags: - GameLifecycle operationId: adminBanishRace summary: Deactivate a race after a permanent platform-level removal description: | Deactivates the named race in the running engine. Called by `Game Master` after a Lobby-driven permanent membership removal. Routed only from the trusted network segment that connects `Game Master` to the engine container. requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/BanishRequest" responses: "204": description: Race deactivated; no response body. "400": $ref: "#/components/responses/ValidationError" "500": $ref: "#/components/responses/InternalError" /api/v1/report: get: tags: - PlayerActions operationId: getReport summary: Get a player turn report description: | Returns the full game report for the specified player and turn. `player` must be a non-blank race name. `turn` defaults to `0`. parameters: - $ref: "#/components/parameters/PlayerParam" - $ref: "#/components/parameters/TurnParam" responses: "200": description: Player turn report. content: application/json: schema: $ref: "#/components/schemas/Report" "400": $ref: "#/components/responses/ValidationError" "500": $ref: "#/components/responses/InternalError" /api/v1/command: put: tags: - PlayerActions operationId: executeCommands summary: Execute a batch of player commands description: | Applies one or more game commands for the specified actor. Serialized to one concurrent execution; requests that cannot acquire the execution slot within 100 ms return `504 Gateway Timeout`. Returns `202 Accepted` with no body on success. Reserved for future use; player order submissions go through `/api/v1/order`. requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CommandRequest" responses: "202": description: All commands accepted. "400": $ref: "#/components/responses/ValidationError" "504": description: Command execution slot not acquired within 100 ms. "500": $ref: "#/components/responses/InternalError" /api/v1/order: put: tags: - PlayerActions operationId: validateOrder summary: Validate and store a player order without executing it description: | Validates and stores the game commands structurally without executing them. On success returns `202 Accepted` with the stored order, including the engine-assigned `updatedAt` timestamp used by clients to detect stale submissions. requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CommandRequest" responses: "202": description: Order is structurally valid and stored. content: application/json: schema: $ref: "#/components/schemas/UserGamesOrder" "400": $ref: "#/components/responses/ValidationError" "500": $ref: "#/components/responses/InternalError" get: tags: - PlayerActions operationId: getOrder summary: Fetch the stored order for a player and turn description: | Returns the order previously stored by `PUT /api/v1/order` for the specified player and turn. Responds `204 No Content` when no order has been stored for that turn. parameters: - $ref: "#/components/parameters/PlayerParam" - $ref: "#/components/parameters/TurnParam" responses: "200": description: Stored player order for the requested turn. content: application/json: schema: $ref: "#/components/schemas/UserGamesOrder" "204": description: No order has been stored for this player on this turn. "400": $ref: "#/components/responses/ValidationError" "500": $ref: "#/components/responses/InternalError" /api/v1/battle/{turn}/{uuid}: get: tags: - PlayerActions operationId: getBattle summary: Fetch a single battle report description: | Returns the full `BattleReport` for the supplied `turn` and battle identifier. The `turn` segment must be a non-negative integer; the `uuid` segment must be a valid RFC 4122 UUID. Responds with `404 Not Found` when no battle is stored for the supplied pair. parameters: - $ref: "#/components/parameters/BattleTurnParam" - $ref: "#/components/parameters/BattleIDParam" responses: "200": description: Battle report for the supplied turn and identifier. content: application/json: schema: $ref: "#/components/schemas/BattleReport" "400": $ref: "#/components/responses/ValidationError" "404": description: No battle exists for the supplied turn and identifier. "500": $ref: "#/components/responses/InternalError" /api/v1/admin/turn: put: tags: - GameLifecycle operationId: adminGenerateTurn summary: Advance the game to the next turn description: | Processes the current turn and generates the next one. Returns the updated game state. Routed only from the trusted network segment that connects `Game Master` to the engine container. responses: "200": description: Updated game state after turn generation. content: application/json: schema: $ref: "#/components/schemas/StateResponse" "500": $ref: "#/components/responses/InternalError" /healthz: get: tags: - Health operationId: healthz summary: Engine liveness probe description: | Returns `{"status":"ok"}` with HTTP `200` whenever the HTTP server is serving requests, regardless of whether the engine has been initialised through `POST /api/v1/admin/init`. Used by `Runtime Manager` to probe a freshly started container before `init` runs. Carries no game-state semantics; use `GET /api/v1/admin/status` for game-state inspection. responses: "200": description: Engine HTTP server is up. content: application/json: schema: $ref: "#/components/schemas/HealthzResponse" components: parameters: PlayerParam: name: player in: query required: true description: Race name of the player requesting the report. Must be non-blank. schema: type: string minLength: 1 TurnParam: name: turn in: query required: false description: Turn number to load the report for. Defaults to 0. schema: type: integer minimum: 0 default: 0 BattleTurnParam: name: turn in: path required: true description: Turn number the battle was generated on. schema: type: integer minimum: 0 BattleIDParam: name: uuid in: path required: true description: Battle identifier (RFC 4122 UUID). schema: type: string format: uuid schemas: HealthzResponse: type: object description: Engine liveness probe response payload. required: - status properties: status: type: string description: Always "ok" while the engine HTTP server is serving requests. enum: - ok StateResponse: type: object description: Summary game state returned after initialization and at each turn boundary. required: - id - turn - stage - player - finished properties: id: type: string format: uuid description: Unique identifier of this game instance. turn: type: integer minimum: 0 description: Current turn number. stage: type: integer minimum: 0 description: Current stage within the turn for games that support state modification. player: type: array description: Summary state for each player participating in the game. items: $ref: "#/components/schemas/PlayerState" finished: type: boolean description: | True exactly once on the turn-generation response that ends the game; otherwise false. Server default: false. `Game Master` uses this flag as the sole signal to run the platform finish flow. The conditional logic that flips it to true lives in the engine's domain code and is owned by the engine maintainers. PlayerState: type: object description: Brief player state returned as part of the game state response. required: - id - raceName - planets - population - extinct properties: id: type: string format: uuid description: Unique player identifier within this game. raceName: type: string description: Name of the player's race. planets: type: integer minimum: 0 description: Number of planets currently owned by the player. population: type: number description: Total population summed across all player planets. extinct: type: boolean description: True when the race has been eliminated or voluntarily quit. InitRequest: type: object description: Initialization request specifying the race list for a new game. required: - races properties: races: type: array description: List of participating races. Minimum 10 entries required. minItems: 10 items: $ref: "#/components/schemas/InitRace" InitRace: type: object description: A single race entry in an initialization request. required: - raceName properties: raceName: type: string description: Name of the race. Must be non-blank and satisfy the entity-name format. minLength: 1 BanishRequest: type: object description: | Request body for the admin banish endpoint. `race_name` must identify an existing race in the engine roster. required: - race_name properties: race_name: type: string description: Name of the race to banish. Must be non-blank. minLength: 1 CommandRequest: type: object description: | Batch command payload. `actor` identifies the race submitting the commands. Each element of `cmd` is a polymorphic command object discriminated by the `@type` field. At least one command is required. required: - actor - cmd properties: actor: type: string description: Race name of the actor submitting the commands. Must be non-blank. minLength: 1 cmd: type: array description: One or more commands to execute in order. minItems: 1 items: $ref: "#/components/schemas/Command" UserGamesOrder: type: object description: | Stored player order. Returned by `PUT /api/v1/order` after successful validation and by `GET /api/v1/order` when fetching a previously stored batch. `cmd` mirrors the command list submitted by the player; entries carry per-command result fields (`cmdApplied`, `cmdErrorCode`) once the order has been processed during turn generation. required: - game_id - updatedAt - cmd properties: game_id: type: string format: uuid description: Identifier of the game this order belongs to. updatedAt: type: integer format: int64 description: Engine-assigned UTC millisecond timestamp of the last write. cmd: type: array description: Commands stored as part of this order, in submission order. items: $ref: "#/components/schemas/Command" Command: type: object description: | Polymorphic game command. The `@type` field identifies the variant. Each variant extends the base fields with additional type-specific parameters documented in `pkg/model/order/order.go`. required: - "@type" - cmdId properties: "@type": $ref: "#/components/schemas/CommandType" cmdId: type: string format: uuid description: Unique command identifier (RFC 4122 UUID). cmdApplied: type: boolean description: Set in command-result responses; true when the command was applied. cmdErrorCode: type: integer description: Set in command-result responses; non-zero when the command was rejected. CommandType: type: string description: Discriminator identifying the game command variant carried in a `cmd` element. enum: - raceQuit - raceVote - raceRelation - shipClassCreate - shipClassMerge - shipClassRemove - shipGroupBreak - shipGroupLoad - shipGroupUnload - shipGroupSend - shipGroupUpgrade - shipGroupMerge - shipGroupDismantle - shipGroupTransfer - shipGroupJoinFleet - fleetMerge - fleetSend - scienceCreate - scienceRemove - planetRename - planetProduce - planetRouteSet - planetRouteRemove Report: type: object description: | Full game report for one player at one turn boundary. Optional array fields are omitted when empty. required: - version - turn - mapWidth - mapHeight - mapPlanets - race - votes - voteFor - player properties: version: type: integer minimum: 0 description: Report format version. turn: type: integer minimum: 0 description: Turn number this report covers. mapWidth: type: integer minimum: 0 description: Width of the star map. mapHeight: type: integer minimum: 0 description: Height of the star map. mapPlanets: type: integer minimum: 0 description: Total number of planets on the map. race: type: string description: Race name of the report recipient. votes: type: number description: Fraction of alliance votes held by this race. voteFor: type: string description: Race name this player is currently voting for. player: type: array description: Diplomatic and aggregate statistics for each known player. items: $ref: "#/components/schemas/ReportPlayer" localScience: type: array description: Science projects owned by this race. items: $ref: "#/components/schemas/Science" otherScience: type: array description: Science projects owned by other known races. items: $ref: "#/components/schemas/OtherScience" localShipClass: type: array description: Ship classes designed by this race. items: $ref: "#/components/schemas/ShipClass" otherShipClass: type: array description: Ship classes belonging to other known races. items: $ref: "#/components/schemas/OtherShipClass" battle: type: array description: UUIDs of battle reports relevant to this turn. items: type: string format: uuid bombing: type: array description: Bombing events that occurred during this turn. items: $ref: "#/components/schemas/Bombing" incomingGroup: type: array description: Identified ship groups inbound toward this race's planets. items: $ref: "#/components/schemas/IncomingGroup" localPlanet: type: array description: Full state of planets owned by this race. items: $ref: "#/components/schemas/LocalPlanet" shipProduction: type: array description: Active ship construction status on this race's planets. items: $ref: "#/components/schemas/ShipProduction" route: type: array description: Cargo route configuration per planet. items: $ref: "#/components/schemas/Route" otherPlanet: type: array description: Partial state of planets owned by other known races. items: $ref: "#/components/schemas/OtherPlanet" uninhabitedPlanet: type: array description: Uninhabited planets within sensor range. items: $ref: "#/components/schemas/UninhabitedPlanet" unidentifiedPlanet: type: array description: Unidentified planet positions within sensor range. items: $ref: "#/components/schemas/UnidentifiedPlanet" localFleet: type: array description: Named fleets belonging to this race. items: $ref: "#/components/schemas/LocalFleet" localGroup: type: array description: Ship groups belonging to this race. items: $ref: "#/components/schemas/LocalGroup" otherGroup: type: array description: Ship groups belonging to other known races. items: $ref: "#/components/schemas/OtherGroup" unidentifiedGroup: type: array description: Unidentified ship group positions within sensor range. items: $ref: "#/components/schemas/UnidentifiedGroup" ReportPlayer: type: object description: Diplomatic and aggregate statistics for one player as seen in a report. required: - name - drive - weapons - shields - cargo - population - industry - planets - relation - votes - extinct properties: name: type: string description: Race name. drive: type: number description: Current drive technology level. weapons: type: number description: Current weapons technology level. shields: type: number description: Current shields technology level. cargo: type: number description: Current cargo technology level. population: type: number description: Total population across all planets. industry: type: number description: Total industrial output. planets: type: integer minimum: 0 description: Number of planets owned. relation: type: string description: Current diplomatic relation toward this race. votes: type: number description: Fraction of alliance votes held. extinct: type: boolean description: True when the race has been eliminated or quit. Science: type: object description: A science project describing technology investment ratios. required: - name - drive - weapons - shields - cargo properties: name: type: string description: Science project name. drive: type: number description: Investment ratio for drive technology (0–1). weapons: type: number description: Investment ratio for weapons technology (0–1). shields: type: number description: Investment ratio for shields technology (0–1). cargo: type: number description: Investment ratio for cargo technology (0–1). OtherScience: allOf: - $ref: "#/components/schemas/Science" - type: object required: - race properties: race: type: string description: Race that owns this science project. ShipClass: type: object description: Design parameters for one ship class. required: - name - drive - armament - weapons - shields - cargo - mass properties: name: type: string description: Ship class name. drive: type: number description: Drive technology level. armament: type: integer minimum: 0 description: Number of weapon mounts (ammo units). weapons: type: number description: Weapons technology multiplier. shields: type: number description: Shields technology multiplier. cargo: type: number description: Cargo technology multiplier. mass: type: number description: Computed ship mass. OtherShipClass: allOf: - $ref: "#/components/schemas/ShipClass" - type: object required: - race properties: race: type: string description: Race that owns this ship class. Bombing: type: object description: Record of a bombing event that occurred during turn processing. required: - planet - planetName - owner - attacker - production - industry - population - colonists - capital - material - attack - wiped properties: planet: type: integer minimum: 0 description: Global planet number. planetName: type: string description: Planet name. owner: type: string description: Race name of the planet owner. attacker: type: string description: Race name of the attacker. production: type: string description: Production type active on the planet at the time of bombing. industry: type: number description: Industrial capacity remaining after the bombing. population: type: number description: Population remaining after the bombing. colonists: type: number description: Colonist units remaining after the bombing. capital: type: number description: Capital reserves remaining after the bombing. material: type: number description: Material reserves remaining after the bombing. attack: type: number description: Aggregate attack power applied during the bombing. wiped: type: boolean description: True when all population was eliminated by the bombing. BattleReport: type: object description: | Full battle report. `races` and `ships` are JSON objects whose keys are stringified integers used to cross-reference entries from `protocol`: a `BattleActionReport` carries integer indices into both maps. The serialised key is a string because JSON object keys are always strings. required: - id - planet - planetName - races - ships - protocol properties: id: type: string format: uuid description: Battle identifier. planet: type: integer minimum: 0 description: Planet number the battle took place on. planetName: type: string description: Planet name at battle start. races: type: object description: | Participating races keyed by the integer index used in `protocol.a` / `protocol.d`. Values are race identifiers. additionalProperties: type: string format: uuid ships: type: object description: | Participating ship groups keyed by the integer index used in `protocol.sa` / `protocol.sd`. additionalProperties: $ref: "#/components/schemas/BattleReportGroup" protocol: type: array description: Ordered list of shots exchanged during the battle. items: $ref: "#/components/schemas/BattleActionReport" BattleReportGroup: type: object description: One ship group participating in the battle. required: - race - className - tech - num - numLeft - loadType - loadQuantity - inBattle properties: race: type: string description: Race name of the group owner. className: type: string description: Ship class name; resolvable through `LocalShipClass` or `OtherShipClass`. tech: type: object description: Technology levels keyed by tech type name. additionalProperties: type: number num: type: integer minimum: 0 description: Initial number of ships in this group. numLeft: type: integer minimum: 0 description: Number of ships remaining at the end of the battle. loadType: type: string description: Type of cargo loaded. loadQuantity: type: number description: Quantity of cargo loaded. inBattle: type: boolean description: | True when the group actually fights. False groups observe the battle in peace state and never fire or take damage. BattleActionReport: type: object description: | One shot in the battle. Attacker and defender indices reference `BattleReport.races`; ship-class indices reference `BattleReport.ships`. required: - a - sa - d - sd - x properties: a: type: integer description: Index into `BattleReport.races` for the attacker. sa: type: integer description: Index into `BattleReport.ships` for the attacker's group. d: type: integer description: Index into `BattleReport.races` for the defender. sd: type: integer description: Index into `BattleReport.ships` for the defender's group. x: type: boolean description: True when the defender ship was destroyed by this shot. IncomingGroup: type: object description: An identified ship group inbound toward a planet of this race. required: - origin - destination - distance - speed - mass properties: origin: type: integer minimum: 0 description: Planet number where this group originated. destination: type: integer minimum: 0 description: Planet number this group is heading toward. distance: type: number description: Remaining travel distance. speed: type: number description: Travel speed. mass: type: number description: Total mass of the group. UnidentifiedPlanet: type: object description: Minimal sensor reading for an unidentified planet. required: - x - "y" - number properties: x: type: number description: Horizontal map coordinate. "y": type: number description: Vertical map coordinate. number: type: integer minimum: 0 description: Global planet number. UninhabitedPlanet: allOf: - $ref: "#/components/schemas/UnidentifiedPlanet" - type: object description: An uninhabited planet within sensor range. required: - size - name - resources - capital - material properties: size: type: number description: Planet size. name: type: string description: Planet name. resources: type: number description: Natural resource yield (R). capital: type: number description: Capital reserves stored on the planet (CAP). material: type: number description: Material reserves stored on the planet (MAT). LocalPlanet: allOf: - $ref: "#/components/schemas/UninhabitedPlanet" - type: object description: Full state for a planet owned by this race. required: - industry - population - colonists - production - freeIndustry properties: industry: type: number description: Industrial capacity of the planet (I). population: type: number description: Population of the planet (P). colonists: type: number description: Number of colonists on the planet (COL). production: type: string description: Current production assignment. freeIndustry: type: number description: Unused industrial capacity available for new production (L). OtherPlanet: allOf: - $ref: "#/components/schemas/LocalPlanet" - type: object description: Partial planet state for a planet owned by another race. required: - owner properties: owner: type: string description: Race name of the planet owner. Route: type: object description: Cargo route configuration originating from one planet. required: - planet - route properties: planet: type: integer minimum: 0 description: Source planet number. route: type: object description: | Mapping from destination planet number (as a string key) to the cargo load type being routed (MAT, CAP, COL, EMP). additionalProperties: type: string ShipProduction: type: object description: Active ship construction progress on one planet. required: - planet - class - cost - prodUsed - percent - free properties: planet: type: integer minimum: 0 description: Planet number where construction is taking place. class: type: string description: Name of the ship class being built. cost: type: number description: Total production cost for one unit of this class. prodUsed: type: number description: Production units already spent on this build. percent: type: number description: Completion percentage of the current build. free: type: number description: Remaining free industrial capacity on this planet. LocalFleet: type: object description: A named fleet belonging to this race. required: - name - groups - destination - speed - state properties: name: type: string description: Fleet name. groups: type: integer minimum: 0 description: Number of ship groups in this fleet. destination: type: integer minimum: 0 description: Destination planet number. origin: type: integer minimum: 0 description: Origin planet number when the fleet is in transit. range: type: number description: Remaining travel range when the fleet is in transit. speed: type: number description: Travel speed. state: type: string description: Fleet operational state. OtherGroup: type: object description: A ship group visible to this race belonging to another race. required: - number - class - tech - cargo - load - destination - speed - mass properties: number: type: integer minimum: 0 description: Group identifier number. class: type: string description: Ship class name. tech: type: object description: Technology levels of this group keyed by tech type name. additionalProperties: type: number cargo: type: string description: Type of cargo carried by this group. load: type: number description: Current cargo load quantity. destination: type: integer minimum: 0 description: Destination planet number. origin: type: integer minimum: 0 description: Origin planet number when the group is in transit. range: type: number description: Remaining travel range when the group is in transit. speed: type: number description: Travel speed. mass: type: number description: Total mass of the group. LocalGroup: allOf: - $ref: "#/components/schemas/OtherGroup" - type: object description: A ship group belonging to this race with full ownership detail. required: - id - state properties: id: type: string format: uuid description: Unique group identifier. state: type: string description: Group operational state. fleet: type: string nullable: true description: Name of the fleet this group belongs to, or null if ungrouped. UnidentifiedGroup: type: object description: Positional reading for an unidentified ship group. required: - x - "y" properties: x: type: number description: Horizontal map coordinate. "y": type: number description: Vertical map coordinate. ValidationErrorResponse: type: object description: Validation error returned for malformed requests. required: - error properties: error: type: string description: Human-readable validation error message from the binding layer. InternalErrorResponse: type: object description: | Internal server error. The shape depends on the error source: - `{"error": "message"}` for generic runtime errors - `{"generic_error": "message", "code": integer}` for game-engine errors properties: error: type: string description: Generic runtime error message. generic_error: type: string description: Game-engine error message. code: type: integer description: Game-engine error code. responses: ValidationError: description: Request body or query parameters are invalid. content: application/json: schema: $ref: "#/components/schemas/ValidationErrorResponse" examples: validationError: value: error: "Key: 'InitRequest.Races' Error:Field validation for 'Races' failed on the 'gte' tag" InternalError: description: Internal Game Service error. content: application/json: schema: $ref: "#/components/schemas/InternalErrorResponse"