feat: v0.6.0 — data foundation: Drizzle ORM + SQLite (sql.js/WASM) persistence, first-run seed, read-only GET /api/state snapshot

This commit is contained in:
2026-09-17 11:51:42 +00:00
parent 4d9a1e9fa9
commit 7fdc43bc7e
23 changed files with 1006 additions and 8 deletions
+110 -1
View File
@@ -8,7 +8,7 @@ export const openApiSpec = {
info: {
title: 'Flight Ops API',
description:
'JSON API for Flight Ops — EU airport data for the map, plus app metadata.',
'JSON API for Flight Ops — EU airport data for the map, the live game-state snapshot, and app metadata.',
// Sourced from package.json so it stays in sync with every version bump.
version: pkg.version,
},
@@ -33,6 +33,24 @@ export const openApiSpec = {
},
},
},
'/api/state': {
get: {
summary: 'Game state snapshot',
description:
'Full current game state for client polling — account, sim clock, planes and contracts. Read-only.',
operationId: 'getState',
responses: {
200: {
description: 'Current game state',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/StateSnapshot' },
},
},
},
},
},
},
'/api/version': {
get: {
summary: 'App version',
@@ -104,6 +122,97 @@ export const openApiSpec = {
},
required: ['name', 'icao', 'lat', 'lon'],
},
StateSnapshot: {
type: 'object',
properties: {
account: { $ref: '#/components/schemas/AccountState' },
simState: { $ref: '#/components/schemas/SimState' },
planes: {
type: 'array',
items: { $ref: '#/components/schemas/PlaneState' },
},
contracts: {
type: 'array',
items: { $ref: '#/components/schemas/ContractState' },
},
},
required: ['account', 'simState', 'planes', 'contracts'],
},
AccountState: {
type: 'object',
properties: {
cash: { type: 'number' },
reputation: { type: 'number' },
},
required: ['cash', 'reputation'],
},
SimState: {
type: 'object',
properties: {
clockMs: { type: 'integer', description: 'Sim-clock epoch ms (game time)' },
timeScale: { type: 'number', minimum: 1, maximum: 60 },
paused: { type: 'boolean' },
},
required: ['clockMs', 'timeScale', 'paused'],
},
PlaneState: {
type: 'object',
properties: {
id: { type: 'string' },
model: { type: 'string' },
status: { enum: ['available', 'flying'] },
fuel: { type: 'number' },
maxFuel: { type: 'number' },
locationIcao: { type: 'string' },
locationName: { type: 'string' },
contractId: { type: ['string', 'null'] },
lat: { type: 'number' },
lon: { type: 'number' },
},
required: [
'id',
'model',
'status',
'fuel',
'maxFuel',
'locationIcao',
'locationName',
'contractId',
'lat',
'lon',
],
},
ContractState: {
type: 'object',
properties: {
id: { type: 'string' },
originIcao: { type: 'string' },
originName: { type: 'string' },
destIcao: { type: 'string' },
destName: { type: 'string' },
reward: { type: 'number' },
cargoType: { type: 'string' },
cargoCount: { type: 'integer' },
deadlineSimTime: { type: 'integer', description: 'Sim-clock epoch ms (game time)' },
status: { enum: ['open', 'accepted', 'completed'] },
planeId: { type: ['string', 'null'] },
createdSimTime: { type: 'integer' },
},
required: [
'id',
'originIcao',
'originName',
'destIcao',
'destName',
'reward',
'cargoType',
'cargoCount',
'deadlineSimTime',
'status',
'planeId',
'createdSimTime',
],
},
},
},
};