v0.11.0 harden persistence and prepare game replays
This commit is contained in:
+56
-32
@@ -2,7 +2,7 @@
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Go 1.24+
|
||||
- Go 1.26+
|
||||
- Stockfish in PATH
|
||||
- SQLite3
|
||||
- Git
|
||||
@@ -14,7 +14,7 @@
|
||||
git clone https://github.com/lixenwraith/chess
|
||||
cd chess
|
||||
go build ./cmd/chess-server
|
||||
go build ./cmd/chess-client
|
||||
go build ./cmd/chess-client-cli
|
||||
```
|
||||
|
||||
## Running
|
||||
@@ -29,20 +29,30 @@ go build ./cmd/chess-client
|
||||
- `-storage-path`: SQLite database file path (enables persistence and authentication)
|
||||
- `-pid`: PID file path for process tracking
|
||||
- `-pid-lock`: Enable exclusive locking (requires -pid)
|
||||
- `-log-level`: `debug`, `info`, `warn`, or `error` (default: `info`)
|
||||
- `-log-http`: Enable API and web request logs (default: `true`)
|
||||
- `-finished-game-ttl`: How long terminal games stay in memory (default: `1h`; `0` disables eviction)
|
||||
- `-web-api-url`: Browser-visible API origin for the embedded web client; useful when its public origin differs from the listen address
|
||||
|
||||
### Modes
|
||||
```bash
|
||||
# In-memory only (no persistence or auth)
|
||||
./chessd
|
||||
./chess-server
|
||||
|
||||
# With persistence and authentication
|
||||
./chessd -storage-path ./db/chess.db
|
||||
./chess-server -storage-path ./db/chess.db
|
||||
|
||||
# Development with all features
|
||||
./chessd -dev -storage-path chess.db -pid /tmp/chessd.pid -serve
|
||||
./chess-server -dev -storage-path chess.db -pid /tmp/chess-server.pid -serve
|
||||
|
||||
# Detailed persistence, engine-queue, cleanup, and request logs
|
||||
./chess-server -dev -storage-path chess.db -serve -log-level debug -log-http=true
|
||||
|
||||
# Web UI is public at one origin while the API is exposed at another
|
||||
./chess-server -serve -web-api-url https://api.example.test
|
||||
|
||||
# Initialize database with user tables
|
||||
./chessd db init -path chess.db
|
||||
./chess-server db init -path chess.db
|
||||
```
|
||||
|
||||
## Database Management
|
||||
@@ -50,60 +60,64 @@ go build ./cmd/chess-client
|
||||
### Schema Initialization
|
||||
```bash
|
||||
# Create all tables (users, games, moves)
|
||||
./chessd db init -path chess.db
|
||||
./chess-server db init -path chess.db
|
||||
```
|
||||
|
||||
### User Management CLI
|
||||
```bash
|
||||
# Add user with password
|
||||
./chessd db user add -path chess.db -username alice -password SecurePass123
|
||||
./chess-server db user add -path chess.db -username alice -password SecurePass123
|
||||
|
||||
# Add user with email
|
||||
./chessd db user add -path chess.db -username bob -email bob@example.com -password BobPass456
|
||||
./chess-server db user add -path chess.db -username bob -email bob@example.com -password BobPass456
|
||||
|
||||
# Interactive password input
|
||||
./chessd db user add -path chess.db -username charlie -interactive
|
||||
./chess-server db user add -path chess.db -username charlie -interactive
|
||||
|
||||
# List all users
|
||||
./chessd db user list -path chess.db
|
||||
./chess-server db user list -path chess.db
|
||||
|
||||
# Update password
|
||||
./chessd db user set-password -path chess.db -username alice -password NewPass789
|
||||
./chess-server db user set-password -path chess.db -username alice -password NewPass789
|
||||
|
||||
# Update email
|
||||
./chessd db user set-email -path chess.db -username alice -email newemail@example.com
|
||||
./chess-server db user set-email -path chess.db -username alice -email newemail@example.com
|
||||
|
||||
# Update username
|
||||
./chessd db user set-username -path chess.db -current alice -new alice2
|
||||
./chess-server db user set-username -path chess.db -current alice -new alice2
|
||||
|
||||
# Import with existing Argon2 hash
|
||||
./chessd db user set-hash -path chess.db -username alice -hash '$argon2id$v=19$m=65536,t=3,p=2$...'
|
||||
./chess-server db user set-hash -path chess.db -username alice -hash '$argon2id$v=19$m=65536,t=3,p=2$...'
|
||||
|
||||
# Delete user
|
||||
./chessd db user delete -path chess.db -username alice
|
||||
./chess-server db user delete -path chess.db -username alice
|
||||
```
|
||||
|
||||
### Game Query CLI
|
||||
```bash
|
||||
# Query all games
|
||||
./chessd db query -path chess.db -gameId "*"
|
||||
./chess-server db query -path chess.db -gameId "*"
|
||||
|
||||
# Query games for specific user
|
||||
./chessd db query -path chess.db -playerId "550e8400-e29b-41d4-a716-446655440000"
|
||||
./chess-server db query -path chess.db -playerId "550e8400-e29b-41d4-a716-446655440000"
|
||||
|
||||
# Query specific game
|
||||
./chessd db query -path chess.db -gameId "a1b2c3d4-e5f6-7890-1234-567890abcdef"
|
||||
./chess-server db query -path chess.db -gameId "a1b2c3d4-e5f6-7890-1234-567890abcdef"
|
||||
|
||||
# Delete database (destructive)
|
||||
./chessd db delete -path chess.db
|
||||
./chess-server db delete -path chess.db
|
||||
```
|
||||
|
||||
## Authentication Configuration
|
||||
|
||||
### JWT Secret Management
|
||||
- **Production**: Cryptographically secure 32-byte secret generated on startup
|
||||
- **Production**: A cryptographically secure 32-byte secret is generated on
|
||||
startup. This intentionally invalidates JWTs after a restart even though the
|
||||
SQLite session rows remain; configuring a stable deployment secret is tracked
|
||||
in `doc/todo.md`.
|
||||
- **Development** (`-dev`): Fixed secret for testing consistency
|
||||
- **Sessions**: Valid for 7 days, renewed on each login
|
||||
- **Sessions**: Stored for 7 days and renewed on each login; effective token
|
||||
lifetime is also bounded by signing-key rotation
|
||||
|
||||
### Password Requirements
|
||||
- Minimum 8 characters
|
||||
@@ -171,6 +185,12 @@ See [test documentation](../test/README.md) for comprehensive test suites coveri
|
||||
|
||||
# Test real-time game updates via long-polling
|
||||
./test/test-longpoll.sh
|
||||
|
||||
# Unit, migration, and persistence tests
|
||||
go test ./...
|
||||
|
||||
# Concurrency checks for the state/persistence boundary
|
||||
go test -race ./internal/server/storage ./internal/server/service
|
||||
```
|
||||
|
||||
## Configuration
|
||||
@@ -180,10 +200,10 @@ See [test documentation](../test/README.md) for comprehensive test suites coveri
|
||||
- Worker count: 2 (internal/processor/processor.go)
|
||||
- Queue capacity: 100 (internal/processor/queue.go)
|
||||
- Min search time: 100ms (internal/processor/processor.go)
|
||||
- Write queue: 1000 operations (internal/storage/storage.go)
|
||||
- DB connections: 25 max, 5 idle (internal/storage/storage.go)
|
||||
- Write queue: 1000 operations (internal/server/storage/storage.go)
|
||||
- DB connections: 8 max, 4 idle (internal/server/storage/storage.go)
|
||||
- JWT expiration: 7 days (internal/service/user.go)
|
||||
- Long-poll timeout: 25 seconds (internal/service/waiter.go)
|
||||
- Long-poll timeout: 30 seconds (internal/server/service/waiter.go)
|
||||
- Long-poll channel buffer: 1 (internal/service/waiter.go)
|
||||
|
||||
### Authentication Configuration
|
||||
@@ -193,11 +213,13 @@ See [test documentation](../test/README.md) for comprehensive test suites coveri
|
||||
- Hash algorithm: Argon2id (memory-hard, side-channel resistant)
|
||||
|
||||
### Storage Configuration
|
||||
- WAL mode enabled in development for concurrency
|
||||
- Foreign key constraints enforced
|
||||
- Async write pattern for games with 2-second drain on shutdown
|
||||
- WAL mode and NORMAL synchronous mode enabled on every connection
|
||||
- Foreign key constraints and a five-second busy timeout enabled on every connection
|
||||
- Async write pattern for games; shutdown drains every accepted write
|
||||
- Replay reads wait for prior queued writes and use one read transaction
|
||||
- Synchronous writes for user operations (data consistency)
|
||||
- Degradation to memory-only on write failures
|
||||
- Registration capacity/eviction, user creation, and initial session are atomic
|
||||
- A full queue or write failure degrades to memory-only and is visible in logs and `/health`
|
||||
- Case-insensitive collation for usernames and emails
|
||||
|
||||
### Rate Limiting Configuration
|
||||
@@ -249,6 +271,8 @@ See [test documentation](../test/README.md) for comprehensive test suites coveri
|
||||
- No password recovery mechanism
|
||||
- No email verification for registration
|
||||
- Fixed worker pool size for engine calculations
|
||||
- No real-time game updates (polling required)
|
||||
- Long-polling limited to 25 seconds per request
|
||||
- REST API only
|
||||
- No push-based game updates (30-second long-polling is used)
|
||||
- Live games are not rehydrated after restart; persisted games are currently replay-only
|
||||
- Database history has no automatic retention policy
|
||||
- Curated-game metadata and replay controls are deferred to [Replay Implementation Tasks](./todo.md)
|
||||
- REST API only
|
||||
|
||||
Reference in New Issue
Block a user