A WebSocket-based game server implementation for the N3F interactive educational game.
This server provides:
- Real-time multiplayer game functionality via WebSockets
- Database integration (PostgreSQL and SQLite support)
- Support for different question types (flash cards, multiple choice)
- Player management and scoring
n3f-game-server/
├── cmd/ # Application entry points
│ └── server/ # Main server executable (just calls app.Run())
├── configs/ # Configuration
│ └── config/ # Environment-based configuration
├── internal/ # Private application code
│ ├── app/ # Application wiring and startup logic
│ ├── database/ # DB connection, driver abstraction, setup/teardown
│ ├── game/ # Game logic and in-memory types
│ ├── models/ # Data models (for DB/API, persistence)
│ ├── repository/ # Repository pattern, CRUD, persistence
│ └── websocket/ # WebSocket communication
├── pkg/ # Public libraries that can be used by external applications
cmd/server/: Thin entrypoint, not tested, just callsapp.Run().internal/app/: Application wiring and startup logic. All main setup is here.internal/database/: Handles low-level DB connection, driver abstraction, and setup/teardown logic. Used by the repository layer.internal/game/: Stateless game domain objects that implement theGameSessioninterface. These provide business logic validation and are not tied to persistence.internal/models/: Data models for persistence and transport (DB/API). These are flat, serializable, and DB-friendly.internal/repository/: Implements the repository pattern as the single source of truth for all game state. Exposes a comprehensiveRepositoryinterface with full CRUD operations.
- Go 1.24.2 or higher
- PostgreSQL (for production)
- SQLite (for development)
- Environment variables (see Configuration section)
-
Clone the repository:
git clone https://github.com/n3f/n3f-game-server.git cd n3f-game-server -
Install dependencies:
go mod download
The server uses a unified config loader:
- Loads built-in defaults
- Loads from a flat YAML file per environment (e.g., configs/development.yaml, configs/production.yaml)
- Environment variables override both YAML and defaults
The config file is selected based on the APP_ENV environment variable (defaults to development).
| Variable | Default | Description |
|---|---|---|
| DB_TYPE | sqlite | Database type (sqlite/postgres) |
| DB_PATH | ./data.db | SQLite database path (if using SQLite) |
| DB_HOST | localhost | PostgreSQL database host |
| DB_PORT | 5432 | PostgreSQL database port |
| DB_USER | postgres | PostgreSQL username |
| DB_PASSWORD | postgres | PostgreSQL password |
| DB_NAME | n3f_game | PostgreSQL database name |
| SERVER_PORT | 8080 | HTTP/WebSocket server port |
| APP_ENV | development | Which config YAML to load |
db_type: sqlite
db_path: data.db
server_port: 8080db_type: postgres
db_host: localhost
db_port: 5432
db_user: postgres
db_password: postgres
db_name: guess_grid
server_port: 80- If a YAML file is provided, its values override the defaults.
- If environment variables are set, they override both the YAML and the defaults.
go run cmd/server/main.go
- By default, the server loads config from
configs/development.yaml(ifAPP_ENVis unset). - To use production config, set
APP_ENV=production. - You can specify additional environment variables to override any config value.
Alternatively, build and run the executable:
go build -o n3f-server cmd/server/main.go
./n3f-server
The SQLite database will be automatically created at the path specified in DB_PATH. Note that database files (*.db) are gitignored and should not be committed to version control.
Create the database:
CREATE DATABASE n3f_game;Note: The schema is automatically created on startup if missing. Migration tooling is planned for the future.
The server implements a comprehensive Repository pattern where all game state is persisted through the database rather than kept in memory. This design provides:
- Scalability: No in-memory state means multiple server instances can share the same games
- Persistence: Game state survives server restarts
- Consistency: Single source of truth eliminates state synchronization issues
Game logic is implemented through stateless GameSession objects that provide:
- Business logic validation (e.g., grid symbol count validation)
- Game-specific configuration (e.g., grid dimensions)
- Type safety and extensibility for different game types
gamestable: Stores game metadata including ID, type, status, and timestampsgame_playerstable: Links players to games with names and join timestampsplayer_gridstable: Stores grid data for grid-based games
Connect to the WebSocket endpoint at:
ws://localhost:8080/ws
The server is currently in early development with the following components implemented:
- Basic WebSocket connection handling
- Database connection infrastructure (PostgreSQL and SQLite)
- Comprehensive game state management with Repository as single source of truth:
- Multiple game types (extensible via
GameSessioninterface) - Grid-based games (configurable grid size and symbol counts)
- Player management and state transitions
- Thread-safe operations with proper locking
- All game state persisted through Repository interface (no in-memory state)
- Multiple game types (extensible via
- Fully expanded Repository pattern with complete test coverage:
- Game lifecycle operations (create, read, update, delete, list)
- Player management (add, remove, existence checks, grid storage)
- Game state queries (player counts, start conditions, status checks)
- Grid operations for grid-based games
- Error handling with custom error types and codes
- Clean separation between stateless GameSession domain objects and persistent models
Planned features:
- Question database and retrieval
- Score tracking and persistence
- Player session handling
- WebSocket message protocol implementation
- Game state persistence
- Real-time multiplayer game functionality via WebSockets
- Configurable grid-based games (grid size and symbol counts can be set per game type)
- Database integration (PostgreSQL and SQLite support)
- Support for different question types (flash cards, multiple choice)
- Player management and scoring
Run tests:
go test ./...
- Use
go test -v ./...to see each test and subtest, including skips and failures. - Use
go test -run TestName -vto run and show only a specific test. - Add
t.Log()orfmt.Println()in your test for more debug output.
If a test isn't running, check:
- The test function name must start with
Testand be exported (capitalized) - The file must end with
_test.go - The test must be in a package included by your
go test ./...command
This project is licensed under the MIT License. See the LICENSE file for details.
[Insert contribution guidelines]