A multiplayer Tic-Tac-Toe backend built with Go, gRPC, Protocol Buffers, PostgreSQL, and server-side streaming.
- Create and join games
- Turn-based gameplay with validation
- Rematch rounds with room-level score and draw tracking
- Real-time game updates using gRPC server-side streaming
- PostgreSQL persistence
- Session-based player authentication
- Optimistic locking for concurrent updates
- Reconnect/resume support for game streams
- Health and readiness checks
- Prometheus metrics
- Structured logging
- Graceful shutdown
- Docker and Docker Compose support
- GitHub Actions CI
- Unit, integration, race, and end-to-end tests
Client
|
v
gRPC API
|
v
Service Layer
|
v
Repository Layer
|
v
PostgreSQL
api/proto/xo/v1
├── Protocol Buffer definitions
cmd/server
├── Application entrypoint
internal/config
├── Configuration loading
internal/database
├── PostgreSQL connection management
internal/domain
├── Core business entities
internal/repository
├── Repository interfaces
internal/service
├── Business logic
internal/store/postgres
├── PostgreSQL repository implementations
internal/realtime
├── Realtime event hub
internal/metrics
├── Prometheus metrics
internal/transport/grpc
├── gRPC handlers and interceptors
migrations
├── Database schema migrations
test/e2e
├── End-to-end tests
Detailed learning notes are available in docs/:
- Architecture
- gRPC API Contract
- Domain Model and Game Rules
- Service Layer Workflows
- Persistence and Migrations
- Realtime Streaming
- Operations and Deployment
- Testing and CI
- Go
- gRPC
- Protocol Buffers
- PostgreSQL
- pgx
- Prometheus
- Docker
- Docker Compose
- GitHub Actions
- Go 1.24+
- Docker
- Docker Compose
- protoc
- grpcurl
git clone https://github.com/MehrshadFb/xo-grpc.git
cd xo-grpcInstall protobuf generators:
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest| Variable | Description |
|---|---|
| DATABASE_URL | PostgreSQL connection string |
| PORT | gRPC server port |
Example:
DATABASE_URL=postgres://xo_user:xo_password@localhost:5432/xo_grpc?sslmode=disable
PORT=50051Start PostgreSQL:
docker compose up -d postgresRun migrations:
make migrate-upStart the server:
DATABASE_URL='postgres://xo_user:xo_password@localhost:5432/xo_grpc?sslmode=disable' \
go run ./cmd/serverBuild and run:
docker compose up --buildStop:
docker compose downmake protoApply migrations:
make migrate-upRollback migrations:
make migrate-downCreateGame
JoinGame
GetState
MakeMove
RequestRematch
WatchGame
Health
WatchGame uses server-side streaming.
Clients can reconnect using:
message WatchGameRequest {
string game_id = 1;
string player_token = 2;
int64 after_version = 3;
}If the client already has the latest version, the server skips sending a duplicate snapshot and waits for future updates.
grpcurl -plaintext localhost:50051 xo.v1.HealthService/HealthExample response:
{
"status": "HEALTH_STATUS_SERVING",
"message": "ok"
}Prometheus metrics are exposed on:
http://localhost:9090/metrics
Example:
curl localhost:9090/metricsAvailable metrics:
xo_grpc_requests_total
xo_grpc_request_duration_seconds
xo_active_watch_streams
Run all tests:
go test ./...Run race detector:
go test -race ./...Run PostgreSQL integration tests:
DATABASE_URL='postgres://xo_user:xo_password@localhost:5432/xo_grpc?sslmode=disable' \
go test ./internal/store/postgres -vRun end-to-end tests:
go test ./test/e2e -vGitHub Actions automatically performs:
- Dependency installation
- Protobuf generation
- Migration execution
- Unit tests
- Integration tests
- Race tests
- Docker image build
Game updates use optimistic locking.
Each game maintains a version number.
Updates succeed only when the expected version matches the current database version, preventing stale writes from overwriting newer state.
- Structured logging using
slog - Prometheus metrics
- Health checks
- Readiness checks
MIT