docs: add comprehensive README with testing and deployment instructions

Includes development setup, Docker deployment, API reference, WebSocket events,
troubleshooting guide, and curl-based test script. Updates App plan.md with
implementation completion status.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Bas van Rossem
2026-02-19 16:31:42 +01:00
parent 9ef1199324
commit 047d4e9776
3 changed files with 565 additions and 6 deletions

314
App plan.md Normal file
View File

@@ -0,0 +1,314 @@
Heres a concrete, **handoff-ready plan** you can give to another AI to implement a first version (v1) of a **Spelljammer Ship Tracker** with **multi-ship CRUD, constrained editing, SQLite persistence, and <1s live updates**.
---
## 0) Product goal (v1)
A small phone-friendly web app where your group can:
* Create/select/delete ships (delete requires confirm modal)
* View & edit **core ship stats** + **current weapons on the ship**
* See changes propagate to all connected clients within ~1s
* Persist “real data” server-side in **SQLite** (ship data + weapons + optional reference content)
* Show a **read-only Rules/Reference** screen for battle lookups
No authentication. Anyone can edit anything.
---
## 1) Recommended stack (simple + robust)
**Option A (recommended): Node.js + Fastify + Socket.IO + SQLite (better-sqlite3) + React (Vite)**
* Fast to implement, great websocket support, easy Docker build.
* Socket.IO simplifies reconnects & room-based updates (per ship).
* better-sqlite3 is reliable and fast for low-concurrency apps.
**Option B:** Node.js + Express + ws + SQLite
(also fine, but more manual reconnection & rooms logic)
Either way: **single Docker Compose** with one container; SQLite is a mounted file.
---
## 2) Architecture
### Backend
* REST API for CRUD and initial state fetch.
* WebSocket (Socket.IO) for real-time updates:
* Clients join a “ship room” when viewing a ship.
* When any field changes, server:
1. validates & persists to SQLite
2. broadcasts an update event to that room
### Frontend
Phone-first layout, 34 screens:
1. **Ship List** (create/select/delete)
2. **Ship Dashboard** (core stats + weapons list)
3. **Edit Weapon** (or inline editing)
4. **Rules/Reference** (read-only)
Use constrained controls:
* numeric steppers/sliders for numbers
* dropdowns for enums (size category, maneuverability class, etc.)
* toggles for booleans
* “Add weapon” form with select + numeric inputs
---
## 3) Data model (SQLite)
Implement migrations on startup.
### Tables
**ships**
* `id` TEXT (uuid, PK)
* `name` TEXT (unique-ish, not required but recommended)
* Core stats (examples; adjust to your desired fields):
* `hull_current` INTEGER NOT NULL
* `hull_max` INTEGER NOT NULL
* `armor_current` INTEGER NOT NULL
* `armor_max` INTEGER NOT NULL
* `ac` INTEGER NOT NULL
* `con_save` INTEGER NULL (or `con_score`)
* `speed` INTEGER NULL
* `maneuver_class` TEXT NULL (enum: A/B/C/D/E/F/S per your rules)
* `size_category` TEXT NULL
* `notes` TEXT NULL
* `updated_at` INTEGER (unix ms)
**weapons**
* `id` TEXT (uuid, PK)
* `ship_id` TEXT (FK -> ships.id, indexed)
* `name` TEXT NOT NULL
* `type` TEXT NULL (optional enum: siege/arcane/etc.)
* `attack_mod` INTEGER NULL
* `damage` TEXT NULL (freeform like “3d10”)
* `range` TEXT NULL
* `ammo_current` INTEGER NULL
* `ammo_max` INTEGER NULL
* `status` TEXT NULL (enum: ok/damaged/disabled)
* `notes` TEXT NULL
* `sort_order` INTEGER NOT NULL default 0
* `updated_at` INTEGER
**rules_pages** (optional; for read-only reference)
* `id` TEXT PK (e.g., “battle”, “ship-stats”)
* `title` TEXT
* `content_markdown` TEXT
* `updated_at` INTEGER
> Keep rules content as markdown stored in DB **or** ship it as static markdown files in the frontend. For v1, static markdown is simplest.
---
## 4) API design (REST)
### Ships
* `GET /api/ships` → list ships `{id, name, updated_at}`
* `POST /api/ships` → create `{name, initialStats...}` → returns full ship
* `GET /api/ships/:id` → full ship + weapons
* `PATCH /api/ships/:id` → update core stats (validated + constrained)
* `DELETE /api/ships/:id` → delete ship + weapons
### Weapons
* `POST /api/ships/:id/weapons` → add weapon
* `PATCH /api/weapons/:weaponId` → update weapon fields
* `DELETE /api/weapons/:weaponId` → delete weapon
Validation rules (server-enforced):
* current values must be `0 <= current <= max`
* max values must be `>= 0`
* enums must be in allowed set
* name length limits
---
## 5) WebSocket events (Socket.IO)
### Client → Server
* `ship:join` `{shipId}`
* `ship:leave` `{shipId}`
* `ship:update` `{shipId, patch}` // core stats patch
* `weapon:create` `{shipId, weapon}`
* `weapon:update` `{weaponId, patch}`
* `weapon:delete` `{weaponId}`
### Server → Client (broadcast to ship room)
* `ship:state` `{ship, weapons}` // on join, or after major changes
* `ship:patched` `{shipId, patch, updated_at}`
* `weapon:created` `{shipId, weapon}`
* `weapon:patched` `{shipId, weaponId, patch, updated_at}`
* `weapon:deleted` `{shipId, weaponId}`
Implementation approach:
* On any mutation, server writes to DB then emits event.
* On join, server emits current `ship:state`.
* Clients apply patches locally; on reconnect, re-join and refresh state.
Conflict model:
* **Last write wins** is fine (your requirement). Keep it simple.
---
## 6) Frontend UI details (phone-first)
### Screen 1: Ship List
* List cards: name + “last updated”
* Buttons:
* “Create ship” (modal with name + optional initial stats)
* Tap card to open
* Delete icon → confirm modal (“Delete ship X?”)
### Screen 2: Ship Dashboard
Sections:
1. **Vitals**
* Hull: current/max (stepper)
* Armor: current/max
* AC (stepper)
2. **Mobility**
* Speed (stepper)
* Maneuver class (dropdown)
* Size category (dropdown)
3. **Weapons**
* List weapons with quick fields (ammo, status)
* Tap weapon to open “Weapon details”
* “Add weapon” button
4. **Notes**
* Multi-line text
Include a top bar:
* Ship name
* “Rules” link/button
* “Back to ships”
### Screen 3: Weapon Details (or modal)
Constrained inputs for ammo/status/attack_mod.
Freeform for damage/range/notes.
### Screen 4: Rules/Reference
* Static markdown viewer with headings + quick links
* Optional “search within rules” (client-side filter)
---
## 7) Persistence + backups
* SQLite file at `/data/spelljammer.sqlite`
* Docker volume mount that path.
* Optional: periodic backup script/cron outside app (copy DB file nightly).
---
## 8) Docker Compose (single service)
* Build a single image that serves both:
* backend API + websockets
* frontend static files
* Expose one port (e.g., 3000) to Caddy reverse proxy.
Example structure (for the implementing AI):
* `/server` Fastify app
* `/web` React app build output served by server (or Caddy, but keep simple)
---
## 9) Implementation steps (what the AI should do in order)
1. Create repo scaffold with `/server` and `/web`
2. Implement SQLite schema + migrations
3. Implement REST endpoints + validation
4. Add Socket.IO with rooms:
* join/leave
* mutation events that persist + broadcast
5. Build React UI:
* routing for screens
* state store (zustand or simple context)
* socket connection + reconnection handling
6. Wire CRUD flows:
* list → select → join room → render state
* edit fields → emit update → optimistic UI
7. Add delete confirmation modal
8. Add rules markdown page (static)
9. Dockerize + compose + test behind Caddy
---
## 10) Acceptance criteria checklist
* ✅ Create ship, appears in list, persists after restart
* ✅ Select ship, see dashboard with core stats + weapons
* ✅ Delete ship requires confirm, removes weapons too
* ✅ All edits propagate to another browser within <1s
* ✅ App is usable on phone (single column layout, large touch targets)
* ✅ SQLite file persists via mounted volume
* ✅ WebSocket reconnect works (refresh state on reconnect)
* ✅ No auth, no user accounts
---
## 11) “Reference guide” integration (v1)
Since you want read-only rules “for during battle”:
Start with a **curated markdown** page that copies only the snippets you frequently need (e.g., maneuverability classes, hull/armor notes, weapon usage, combat steps). You can refine later.
(If you want, I can extract a concise “Battle Reference” page from your PDF and format it as markdown for the AI to drop into `/web/src/rules/battle.md`.)
---
## 12) v1 Implementation Status
**Status: v1 COMPLETE** (implemented 2026-02-19)
All 14 commits have been implemented:
1. ✅ Project scaffold (Fastify + Vite + TypeScript)
2. ✅ SQLite connection + migration system
3. ✅ Ship REST API with Zod validation
4. ✅ Weapon REST API with validation
5. ✅ Socket.IO with rooms + real-time events
6. ✅ React routing + layout (mobile-first dark theme)
7. ✅ Zustand stores + Socket.IO client
8. ✅ Ship List page with create modal
9. ✅ Ship Dashboard (vitals + mobility)
10. ✅ Weapons section (add/edit/detail modals + notes)
11. ✅ Delete confirmation polish
12. ✅ Rules/Reference page (collapsible battle reference)
13. ✅ Dockerfile + docker-compose
14. ✅ README with testing + deployment docs
See `README.md` for full setup, testing, and deployment instructions.