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/status: get: tags: - GameLifecycle operationId: getGameStatus 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. 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/init: post: tags: - GameLifecycle operationId: initGame summary: Initialize a new game description: | Generates a new game instance with the supplied list of races. Requires at least 10 race entries. 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/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 `204 No Content` on success. requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CommandRequest" responses: "204": description: All commands applied successfully. "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. Returns `204 No Content` if the order is valid and accepted. requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CommandRequest" responses: "204": description: Order is structurally valid. "400": $ref: "#/components/responses/ValidationError" "500": $ref: "#/components/responses/InternalError" /api/v1/turn: put: tags: - GameLifecycle operationId: generateTurn summary: Advance the game to the next turn description: | Processes the current turn and generates the next one. Returns the updated game state. 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/init`. Used by `Runtime Manager` to probe a freshly started container before `init` runs. Carries no game-state semantics; use `GET /api/v1/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 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 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" 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 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" 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. 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"