3.6 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Purpose
Segnapunti Anto is a real-time volleyball scoreboard PWA. An Express/WebSocket server hosts the game state; two separate web interfaces — a display (public scoreboard) and a controller (operator panel) — stay in sync via WebSocket. A terminal CLI (cli.js) provides an alternative controller interface.
Commands
npm run dev # Vite dev server — display: :5173, controller: :5173/controller.html (proxied on :3001)
npm run serve # Build + run production — display: :3000, controller: :3001
npm run cli # Terminal controller (connects to production :3000)
npm run cli:dev # Terminal controller (connects to dev :5173)
npm run test # Vitest watch mode
npm run test:all # All Vitest suites once (unit, integration, component, stress)
npm run test:unit # Unit + integration only
npm run test:component # Vue component tests
npm run test:stress # Load tests (50+ concurrent clients)
npm run test:e2e # Playwright E2E (requires servers to be running via npm run serve)
npm run test:e2e:ui # Playwright with interactive UI
Architecture
Controller (Vue) ──WebSocket──┐
Display (Vue) ──WebSocket──┤── websocket-handler.js ── gameState.js
CLI (Node) ──WebSocket──┘
All game logic lives in src/gameState.js as three pure functions:
createInitialState()— returns the initial stateapplyAction(state, action)— immutable reducer (deep-clones viaJSON.parse/stringify)checkVittoria(state)— volleyball win conditions (25-point sets with 2-point margin, 15-point final set)
src/websocket-handler.js receives actions, validates that the sender is a registered controller (not just a display), calls applyAction, then broadcasts the new state to all clients.
Two production HTTP servers are started by server.js (Express): port 3000 serves dist/index.html (display), port 3001 serves dist/controller.html (controller). Both share a single WebSocket endpoint at /ws.
In development, vite-plugin-websocket.js is a custom Vite plugin that embeds the WebSocket server inside the Vite dev server and proxies port 3001 traffic back to Vite.
Key Design Constraints
- All game rules on the server — clients are pure UI; the server is the source of truth.
- Role-based WebSocket — clients register as
displayorcontroller; only controllers may send actions. - Immutable state —
applyActionnever mutates; always returns a new state object. - Single-controller intent — the design targets one active controller and one display; no conflict resolution exists for simultaneous controllers.
Test Layout
| Suite | Path | Runner |
|---|---|---|
| Unit | tests/unit/ |
Vitest + Node |
| Integration | tests/integration/ |
Vitest + Node |
| Component | tests/component/ |
Vitest + Happy-DOM |
| Stress | tests/stress/ |
Vitest + Node |
| E2E | tests/e2e/ |
Playwright (Chromium, Firefox, Mobile Chrome) |
E2E tests run serially (workers: 1) to avoid WebSocket state races. Run npm run serve before npm run test:e2e.
Simplification Goals (Current Work)
The intended architecture is: one host acts as both WebSocket server and display; one connected device acts as controller. Complexity reduction should be evaluated against this constraint — anything that supports multi-controller scenarios, complex client topologies, or unneeded abstractions is a candidate for removal.