feat: implement and deploy blind_chess MVP

- pnpm workspace: shared/server/client packages
- Server: Fastify+ws, chess.js, FSM (touch-move + hierarchy),
  per-player view filter, zod validation, rate limiting, grace-window
  disconnect handling
- Client: Svelte 5 + Vite, click-to-move board, moderator panel,
  promotion/draw dialogs
- Shared: protocol types, ModeratorText enum, geometricMoves helper
  (provably zero opponent-info leak)
- 43 tests pass (21 shared, 22 server incl. 4 real-WS integration)
- Deploy: CT 690 on node-241 (192.168.0.245), systemd-managed,
  Caddy block for chess.sethpc.xyz
- Live at https://chess.sethpc.xyz

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
claude (blind_chess)
2026-04-28 11:20:18 -04:00
parent 9a5ad55f30
commit a6de43edc1
53 changed files with 11970 additions and 5 deletions
+12
View File
@@ -38,6 +38,18 @@ Format: `YYYY-MM-DD: <decision> — <why>`
- 2026-04-28: Resign + draw-offer/accept-decline flow — standard chess UX. Resignation ends without grace; disconnect applies grace.
- 2026-04-28: Game-over screen reveals full board for both sides — post-game review is part of the experience.
## Implementation outcomes (2026-04-28 build session)
- 2026-04-28: **Repo:** `git.sethpc.xyz/Seth/blind_chess`. Created via `gitea create blind_chess`. Default branch `main`.
- 2026-04-28: **CT:** 690 on node-241, hostname `blind-chess`, IP 192.168.0.245, Debian 12, Node 22.22.2. 2 cores / 512 MB RAM / 8 GB rootfs. Resting memory ~29 MB, plenty of headroom.
- 2026-04-28: **Chosen `chess.js` v1.4.0** — uses `Move.isEnPassant()` / `isKingsideCastle()` / `isQueensideCastle()` instead of the deprecated `flags` string. The `Move` constructor's deprecated `flags` field is intentionally not relied upon.
- 2026-04-28: **Half-move clock for the 50-move rule** is read from FEN field 4 (chess.js doesn't expose it directly). See `translator.ts:halfMoveClock`.
- 2026-04-28: **Shared package import resolution**`packages/shared/package.json` `main` and `exports` point to `./dist/`. Source `.ts` is dev-only. Always run `pnpm --filter @blind-chess/shared build` before `pnpm --filter @blind-chess/server build` (the workspace project refs handle this when running `pnpm -r build`).
- 2026-04-28: **Client routing** is hash-based with a pathname fallback in `App.svelte` so `https://chess.sethpc.xyz/g/<id>` (the share URL) and `https://chess.sethpc.xyz/#/g/<id>` (the post-create URL) both render the game. The Fastify SPA fallback serves `index.html` on any non-matching `text/html` request.
- 2026-04-28: **Click-to-move only** — drag-and-drop deferred. Tap-arm + tap-destination is faithful to the touch-move FSM and works identically on phone and desktop.
- 2026-04-28: **WS path through Caddy**`wss://chess.sethpc.xyz/ws?game=<id>` works without explicit `transport ws` config. Caddy's reverse_proxy handles upgrade transparently.
- 2026-04-28: **Public DNS** — relies on existing `*.sethpc.xyz` wildcard pointing at the WAN IP; no Pi-hole entry was needed. Caddy host-routes `chess.sethpc.xyz` to 192.168.0.245:3000.
## Deferred / Rejected
<!-- Decisions NOT to do something are just as valuable -- prevents re-proposing rejected ideas -->