12 KiB
12 KiB
Changelog
v0.6.0 — 2026-09-28 23:46
- SHIP SYSTEMS tab — expand / upgrade / build ship systems + save backfill plumbing (issue #8): the first spend-side game loop on top of issue #7's crew, plus a root-cause fix for saves created by older code lacking data newer code seeds. Single-player, no auth, by design.
- Backfill plumbing:
schema_versionINTEGER added tosaves(NULL = v1).ensureSavenow runs ordered IDEMPOTENT backfill steps for anything below current — v2: every system without planets gets its generated bodies (same(seed, systemId)derivation as fresh generation), v3: starting crew if no rows. New games get the current version directly.lib/db/client.tsopen() carries an idempotentALTER TABLE ... ADD COLUMNguard for files created before the column existed — old saves open fine and backfill on first read, so DB wipes are no longer needed when deploying new versions. - New table (
lib/db/schema.ts+ DDL):ship_systems(id/save_id/type/level/capacity, UNIQUE(save_id,type)).builtis derived, not stored — level > 0 means built; unbuilt rows sit at level/capacity 0. Starting ship seeded on new game AND as backfill step v4: core types (HULL, REACTOR, LIFE SUPPORT, NAV COMPUTER, COMMS ARRAY) built at base values, WEAPONS unbuilt until a build action. - Cost model (
lib/game/ship-costs.ts, pure — imported by both the API and the UI so affordability can't drift): UPGRADE costslevelunits of any resource (capped at MAX_LEVEL 5), EXPAND costscapacityunits of any resource (capped at MAX_CAPACITY 10), BUILD costs a flat 3 parts. Consumption takes from the oldest cargo row of the required kind first, deleting rows that hit zero; an unaffordable action mutates nothing. - Ship actions (
lib/game/ship.ts):upgradeSystem/expandSystem/buildSystem— validate (404 unknown id/type, 409 not built / already built / at cap, 422 insufficient inventory), spend the cost, bump level/capacity or build at base values, cost one turn and write an event each. - New endpoints:
GET /api/ship→{systems:[{id,type,level,capacity,built}],inventory,turn};POST /api/ship/upgrade {systemId},POST /api/ship/expand {systemId},POST /api/ship/build {type}— each returns the fresh ship state. OpenAPI spec in code updated (10 paths). - SHIP SYSTEMS tab now renders REAL data: cards show type + level/capacity with UPGRADE / EXPAND buttons per built card and BUILD NEW for unbuilt types, disabled when unaffordable or capped; each action's response is applied directly (no polling). Left column mirrors live state too — the SHIP SYSTEMS panel lists every system with its status/level/capacity + an N ONLINE badge, and VESSEL METRICS bars are driven by real values (hull/reactor from system levels, crew roster vs a cap of 6). Placeholder constants for both removed; other tabs keep theirs until their issues land.
- Tests: unit — backfill upgrades a hand-built v1 save in place (deterministic vs fresh generation, idempotent), starting ship seeding, cost validation with no mutation on failure, exact oldest-first inventory deduction, level/capacity caps, build-once, turn + event per action; e2e — SHIP SYSTEMS tab performs one affordable UPGRADE/BUILD via the UI after a bounded scan loop until something is affordable (asserting card + left column reflect it), and ship state survives the mid-run container restart.
v0.5.0 — 2026-09-28 22:51
- CREW tab — crew roster with good/bad traits (issue #7): the ship's people on top of issue #6's exploration loop. Single-player, no auth, by design. Display + arrival only — no dismiss/assign actions yet.
- New table (
lib/db/schema.ts+ DDL inlib/db/client.ts):crew(id/save_id/name/role/trait_good/trait_bad/origin). Origin is 'STARTING CREW' for the seeded crew or ', ' for members found while exploring. - Pure seeded crew generation (
lib/game/crew.ts, same pattern as world.ts): name pools (16 first × 22 last, unique per roster), role pool of 8, good/bad trait pools of 10 each.generateStartingCrewgives a new game 2–3 members with unique names and roles;rollCrewMemberfinds a joining member on ~18% of scans (CREW_CHANCE = 0.18). - Starting crew is seeded in
ensureSavefrom the save seed viastartingCrewRng(seed)— same per-save derivation pattern as bodies/exploration, so a given seed always starts with the same crew. - Exploration extended: the crew roll draws from the SAME per-planet rng stream as the resource/part haul (called after it in
explorePlanet), so outcomes stay deterministic per save+planet and existing hauls are unchanged. Found members join the roster with origin = ', '; each body can only be scanned once, so no duplicate joins. - New endpoint:
GET /api/crew→[{id,name,role,trait_good,trait_bad,origin}]in join order (auto-initializes like the others).POST /api/exploreresponses now also carrycrewFound(the joining member or null). OpenAPI spec in code (lib/openapi.ts) updated for both. - CREW tab now renders REAL data: fetches
/api/crewon mount (Radix unmounts inactive tabs, so opening the tab always refetches — no polling), cards show name + role, the good (+) and bad (−) traits and an ORIGIN line. Placeholder crew constants removed for this tab only — other tabs keep theirs until their issues land.
v0.4.0 — 2026-09-28 22:17
- LOCAL SYSTEM tab — planet list + exploration to find things (issue #6): the first in-system game loop on top of issue #5's save/world foundation. Single-player, no auth, by design.
- New tables (
lib/db/schema.ts+ DDL inlib/db/client.ts):planets(id/system_id/parent_id/name/type/hazard/explored — planets have parent_id NULL, moons point at their planet) andinventory_items(id/save_id/kind[name]/qty — the dumb-simple cargo hold SHIP SYSTEMS (#8) will spend from later). - Planet generation hooks into world gen (
lib/game/world.ts, pure + seeded): each system gets 2–5 planets, some with 1–3 moons, generated when the system is inserted viabodyRng(seed, systemId)— so a given system always has the same bodies regardless of order. Bodies are stored in display order (a moon follows its parent row). - Exploration (
lib/game/save.ts):explorePlanetrolls a deterministic haul fromexplorationRng(seed, planetId)— a resource and/or a part (qty), or nothing (~21% of scans) — marks the body explored (each once), costs a turn, accumulates finds into inventory (same kind+name bumps qty) and writes an explore event. - New endpoints:
GET /api/system→{ systemId, systemName, planets[{id,name,type,hazard,explored,parent}], inventory, turn };POST /api/explore {planetId}→ fresh system state +outcome(400 malformed body, 404 unknown planet, 409 already explored). OpenAPI spec in code (lib/openapi.ts) updated for both. - LOCAL SYSTEM tab now renders REAL data: fetches
/api/systemon mount, draws the staggered body list (planets base level, moons indented + dimmed with their parent's name), badges reflect real state (UNEXPLORED / SCANNED / HAZARD) and an EXPLORE button per unexplored row; explore responses apply directly (no polling). A CARGO HOLD panel shows the live inventory. Placeholder constants removed for this tab only — other tabs keep theirs until their issues land.
v0.3.0 — 2026-09-28 21:35
- World generation + jump between solar systems (issue #5): the game save, DB schema, turn counter and event writing that all later tabs build on. Single-player by design — one save row, no auth/accounts.
- New tables (
lib/db/schema.ts+ DDL inlib/db/client.ts):saves(id/seed/turn/created_at),solar_systems(name, x/y chart position, discovered, is_current),jump_routes(directed pairs, both directions stored for single-row adjacency lookups),events(append-only log: new-game + jump events so far). - Seeded world generation (
lib/game/world.ts, pure functions): a save's seed deterministically generates the starting system plus a ring of six undiscovered neighbours with jump routes; jumping into an undiscovered system grows the chart with four more neighbours around it, so there is always somewhere to jump and a route back. - Save lifecycle (
lib/game/save.ts): auto-initializes on first API hit when no save exists, exposes world state, validates jumps (adjacency required — non-adjacent/unknown rejected), sets current, increments the turn counter, writes events, persists durably. - New endpoints:
GET /api/world→{ systems, edges, turn };POST /api/jump { systemId }→ fresh world state (400 malformed body, 404 unknown system, 409 not adjacent). OpenAPI spec in code (lib/openapi.ts) updated for both. - WORLD MAP tab now renders REAL data: fetches
/api/worldon mount, draws the live NodeGraph (current = ACTIVE/CURRENT, discovered = NEUTRAL/DISCOVERED, unknown = OFFLINE/UNKNOWN) with a jump button per adjacent system; placeholder map constants removed for this tab only — other tabs keep their placeholders until their own issues land.
v0.2.2 — 2026-09-28 21:02
- LOCAL SYSTEM tab: explorable-worlds list now staggers moons under their parent planet (indented rows) — ASHFALL attached under BRIMSTONE, new PALEMOON moon under AURELLE; badges unchanged.
v0.2.1 — 2026-09-28 20:22
- LOCAL SYSTEM tab: removed the system node graph (star/planets/moons) — the tab now shows only the explorable-worlds list at full panel width. WORLD MAP keeps its node graph;
components/ui/node-graph.tsxunchanged and still in use there.
v0.2.0 — 2026-09-28 19:19
- Game interface template (visual only, zero game logic): the operations panel in
components/mission-control.tsxis now seven tabs — WORLD MAP (NodeGraph of 10 placeholder solar systems linked by jump routes), LOCAL SYSTEM (NodeGraph of star + planets/moons plus an explorable-worlds list), CREW (crew cards with name/role and good/bad trait placeholders), SHIP SYSTEMS (system cards with inert EXPAND / UPGRADE / BUILD NEW affordances), SKILL TREE (tech cards unlocking new system builds/upgrades), MISSIONS (previous NEXT MISSION content), EVENT LOG (ship log terminal). All data is local placeholder constants. - Left column: VESSEL METRICS progress rings replaced with scificn Progress bracket bars; SHIP SYSTEMS status panel, header stat cards and right column unchanged.
- New scificn-ui components copied into
components/ui/: NodeGraph, Progress (+@radix-ui/react-progressdependency).
v0.1.0 — 2026-09-28 15:47
- Initial scaffold (stack proof): base stack copied/adapted from Flight-Ops (
../flight) — Next.js 16 App Router + React 19 + TypeScript strict, bun package manager, Node 22 in CI/Docker. - Single-player only by design: NO auth/accounts/multiplayer anywhere (Flight-Ops's users/sessions/admin/leaderboard patterns deliberately not copied).
- Frontend component layer: scificn-ui v0.1.0 integrated copy-paste (Radix + Tailwind v4, SCI-FI theme) — Button, Panel, Badge, Card, Alert in
components/ui/; theme tokens inapp/globals.csswith a brightened--text-mutedoverride (#4A4A40→#6B6B5C). - Interface base: the scificn-ui Mission Control showcase (https://www.scificn.dev/showcase/mission-control) rebuilt as the app's main UI —
app/page.tsxrenderscomponents/mission-control.tsx(client dashboard: sticky header, stat-card row, 3-column grid of Panel/Tabs/StatusGrid/ProgressRing/BarChart/LineChart/Terminal panels, sticky footer), placeholder ship content only, no game logic; additional upstream components copied intocomponents/ui/(Tabs, StatCard, Terminal, StatusGrid, ProgressRing, BarChart, LineChart) +@radix-ui/react-tabsdependency. - DB plumbing: SQLite via Drizzle ORM + sql.js (WASM) at
db/space-wanderer.db, volume-mounted; empty schema placeholder — game tables land with the first game systems. - API pattern established:
/api/version+ OpenAPI 3.x spec generated in code (lib/openapi.ts) served at/api/openapi. - CI/e2e/docker pipeline: single "build + unit + e2e" job on the dind runner, isolated stack
space-wanderer-ciwith static IP 172.39.0.10 (fresh DB volume per run), Playwright e2e (smoke.spec.ts,state.spec.ts) CI-only against that stack; prod compose behind Traefik athttps://space-wanderer.dev.kkhost.pl(not deployed yet).