deadhead-space-freight-tycoon/memory-bank/architecture.md

2.8 KiB

Architecture

Living reference for how the code is organised. Update it after any database schema or API change (implementation plan rule 0.1.9). Decisions and their reasons live in DECISIONS.md.

Packages

Package Role Depends on
packages/content Static game data (locations, ship models, cargo, skills, GameConfig) as Zod-validated TypeScript, plus the content bundle with id lookups. zod
packages/sim Pure, deterministic game rules: clock, seeded RNG, positions, distances, travel, fuel, eligibility, contract boards, dispatch validation/records, flight progress, XP, resolution. No I/O, no Date.now(), no Math.random(). content, astronomy-engine
packages/schema Zod schemas for every API request, response and error. Shared by server and client. sim (error codes), zod
apps/server Fastify API, Postgres via Drizzle, pg-boss workers. The authority on outcomes. content, sim, schema
apps/web React client. Predicts with sim, never decides outcomes. content, sim, schema

Conventions

  • Times are Unix milliseconds (numbers). A real time is a wall-clock instant; a game time is the instant of the in-game date (realToGame / gameToReal in sim).
  • Ids are non-empty strings. Content ids are kebab-case (earth, bulk-hauler).
  • Credits are whole numbers.
  • Static vs. player data: the API never sends static data. The client imports @deadhead/content and joins by id.

API data model (packages/schema)

Shape Fields
ServerTime realTime, gameTime
Company id, name, credits
Ship id, modelId, name, status (idle / in-flight), locationId (null in flight), dispatchId (null when idle), pilotId
Pilot id, name, isAvatar, xp, level, skills ({ skillId: level }), skillPointsAvailable, assignedShipId, status, locationId (null in flight)
Bay id, locationId
LocationState id, discovered
Contract mirrors sim Contract
Dispatch mirrors sim DispatchRecord + status (in-flight / resolved), resolvedAt
ResolutionSummary dispatchId, shipId, pilotId, originId, destinationId, tutorial, credits, pilotXp, discoveredLocationId, resolvedAt
TutorialState loanerLocationId (earth / moon), runInFlight
PlayerState company, ships, pilots, bays, locations, tutorial (null once over), activeDispatches, summaries

Errors

Every non-2xx response has the body { error: { code, message } }. code is one of ERROR_CODES: every sim dispatch and reposition validation reason (DISPATCH_FAILURES, REPOSITION_FAILURES), unchanged, plus the server codes in SERVER_ERROR_CODES (validation-error, unauthorized, not-found, insufficient-funds, ...).