david raistrick
7467a8d30f
feat(M5): docker-compose full stack (caddy + node backend + sqlite)
...
docker-compose.yml: two profiles.
- backend: backend (node+ws+better-sqlite3, /data volume) + frontend
(Caddy static build, STORAGE=ws, same-origin proxy)
- firebase: existing Dockerfile + nginx (upstream path, untouched)
Run: docker compose --profile backend up --build. OrbStack local now,
remote docker context later.
server/Dockerfile: node:18-alpine, workspaces (shared dep), rebuild
better-sqlite3 for musl, DB at /data/tracker.sqlite.
Dockerfile.ws: CRA build STORAGE=ws → caddy:2-alpine serves /srv.
No backend URL baked (same-origin).
Caddyfile: handle /api/* + handle /ws → backend:4001 (path preserved,
mutually-exclusive handles so try_files SPA fallback never shadows proxy).
handle { static try_files } last. HTTP basic auth block optional.
src/storage/ws.js: same-origin defaults. Empty baseUrl = relative fetch
(Caddy proxy). wsUrl derives from window.location (http→ws/https→wss).
Fallback localhost for bare npm start dev.
.dockerignore: add data/ scratch/ tmp/ (never bake into image). Keep
Caddyfile in context (frontend build COPYs it).
Smoke verified via OrbStack:
- GET / → 200 (static SPA)
- PUT/GET /api/doc roundtrip → JSON persists
- WS /ws subscribe + change push → both work through proxy
Firebase profile: pre-existing Dockerfile requires .env.local (hardcoded
COPY on main, not changed here). User must create file. Not a regression.
2026-07-01 14:39:47 -04:00
david raistrick
e514a48d6e
tests: BUG-8 ws reconnect RED, BUG-7 reorder no-undo doc, ws _test accessor
...
server/tests/ws-reconnect.test.js: subscribe, write (fires), force-drop WS,
write again (must still fire). RED on current. wsReady=null after drop,
no reconnect, subscribers dead forever. Display frozen.
src/storage/ws.js: added _test accessor (getWs, forceDrop, getReady,
docSubs, collSubs) for reconnect test. Test-only, no behavior change.
TODO: BUG-7 (reorder no undo), BUG-8 (ws reconnect) added.
2026-06-30 13:59:58 -04:00
david raistrick
f81308a0df
tests: consolidate into tests/ dirs, fix import paths
...
Move all test files out of source dirs into per-workspace tests/:
- shared/tests/ (3 unit test files)
- server/tests/ (1 integration test)
- src/tests/ (8 characterization + scenario tests + testHelpers)
Fix all relative import paths (App, storage, __mocks__, testHelpers).
Fix jest.config testMatch globs in shared/ and server/ (rootDir +
<rootDir>/tests pattern).
Delete scripts/repro-pause-bug.js (debug scratch, superseded by
turn.pause-add.test.js).
Keep scripts/replay-combat.js + scripts/audit-rotation.js as manual
demo/exploratory tools (NOT unit tests, not deterministic).
No logic changes. All green: shared 49 + 1 validated RED, server 23,
FE 62. Scenario test unchanged (240s timeout, pre-existing slow).
2026-06-29 16:02:22 -04:00
david raistrick
52866784b2
M2: replace shape-specific backend with generic KV doc store (firebase mirror)
...
Backend was endpoint-mapper (POST /api/campaigns ignores path id, etc). Adapter
translation layer brittle, untested, lost doc identity. Generic contract (Layer 2)
test caught 15 bugs immediately.
Rewrite to firebase-mirror KV model:
- server/db.js: docs table (path PK, parent, data JSON). getDoc/setDoc/updateDoc/
deleteDoc/getCollection/batchWrite. parent = path prefix for collection queries.
- server/index.js: generic REST (GET/PUT/PATCH/DELETE /api/doc, GET /api/collection,
POST /api/collection addDoc, POST /api/batch). WS subscribe by path (doc|collection),
broadcast to doc subs at changed path + collection subs at parent path.
- src/storage/ws.js: thin passthrough adapter. norm() strips firebase prefix.
initial value via REST (independent of WS connect), subsequent changes via WS.
- shared/turn.js kept (M4 use). server/handlers.js + server.test.js removed (logic
now in App, backend is dumb KV).
- src/storage/contract.js: flush() bumped to 50ms (WS roundtrip > setTimeout(0)).
Layer 2 test (server/ws-contract.test.js): spins fresh backend per test, runs same
storage contract spec against createWsStorage. Catches adapter translation bugs
that firebase-mock Layer 1 tests cannot.
nanoid v5 ESM breaks jest CJS -> replaced with crypto.randomUUID (Node builtin).
Tests: 114 green (39 shared + 19 ws-contract + 56 frontend).
2026-06-29 13:00:24 -04:00
david raistrick
0e76fb2fc7
M1: backend (Express+ws+better-sqlite3) + integration tests
...
- server/db.js: SQLite schema mirroring Firestore doc tree
- server/handlers.js: action -> shared turn fn -> tx persist -> broadcast
- server/index.js: REST endpoints + WebSocket real-time push
- server/server.test.js: 7 integration tests (REST CRUD + combat flow)
- --forceExit for jest (open WS handles)
Backend boots, serves state, persists to SQLite.
2026-06-28 17:01:53 -04:00
david raistrick
e06adaa081
M1: shared turn logic + characterization tests (39 green)
...
- npm workspaces: shared/, server/
- shared/turn.js: port turn logic verbatim from App.js (bugs preserved)
- 39 characterization tests lock current behavior
- gitignore: sqlite data, logs
2026-06-28 16:57:43 -04:00