Deployment: https://yovi-es1c.duckdns.org/
YOVI is a web platform for playing the Game of Y. The repository contains a React frontend, Node/Express services, a Rust game engine and bot server, monitoring, architecture documentation, model training tools and load tests.
- UO302313 - David Fernando Bolaños López
- UO294946 - Raúl Velasco Vizán
- UO301919 - Ángela Nistal Guerrero
- UO300731 - Olai Navarro Baizán
- UO301831 - Alejandro Requena Roncero
| Path | What it contains |
|---|---|
webapp/ |
React + Vite + TypeScript SPA. Includes auth screens, game screens, online matchmaking/session UI, chat, stats and ranking. |
auth/ |
Node.js + Express + TypeScript authentication service backed by PostgreSQL. Issues access/refresh JWTs and verifies tokens for other services. |
users/ |
Node.js + Express + TypeScript profile service backed by SQLite. Stores username/avatar profiles and exposes Prometheus metrics. |
gameservice/ |
Node.js + Express + TypeScript game service backed by PostgreSQL and Redis. Stores matches, moves, stats, rankings and online sessions. |
gamey/ |
Rust Game Y engine and Axum bot server. Provides CLI play, YEN notation, bots and Prometheus metrics. |
training/ |
Offline Python pipeline for self-play, training and ONNX export of the neural policy-value model consumed by gamey. |
nginx/ |
Public gateway, TLS termination, reverse proxy, WebSocket proxy, rate limiting, SPA fallback and monitoring subpaths. |
monitoring/ |
Prometheus and Grafana configuration provisioned by Docker Compose. |
loadtests/ |
k6 REST load tests and Artillery Socket.IO load tests for local and remote environments. |
docs/ |
Arc42 architecture documentation built with Asciidoctor. |
- Registration, login, token refresh, logout, logout-all and internal token verification in
auth. - User profiles with authenticated create/read/update operations in
users. - Bot and local two-player matches through
gameservice, including board size, difficulty, modes, Pie rule and Honey blocked cells. - Online human-vs-human matchmaking through Redis and Socket.IO.
- Active online sessions with synchronized state, move submission, Pie swap, turn timeout handling, reconnect grace period, abandon/forfeit and chat filtering.
- Match persistence in PostgreSQL with YEN move history.
- User statistics and ELO-style rankings.
- Rust bot API with
easy,medium,hard,expert_fastandexpertaliases, backed by heuristic bots and neural MCTS. - Prometheus metrics for services and Grafana dashboards through Compose.
- k6 and Artillery load-test suites for auth, game creation, matchmaking, online sessions and turn timeout flows.
Docker Compose exposes Nginx on ports 80 and 443. HTTP redirects to HTTPS. Backend containers are intended to be reached through Nginx, except gameservice also maps 3002:3002 for direct local diagnostics.
| Public path | Target |
|---|---|
/api/auth/* |
Auth service on auth:3001 |
/api/users/* |
Users service on users:3000 |
/api/game/* |
Game service on gameservice:3002 |
/api/game/socket.io/ |
Game service Socket.IO endpoint |
/api/gamey/* |
Gamey bot server on gamey:4000 |
/play |
Gamey competition endpoint |
/prometheus/ |
Prometheus UI/API |
/grafana/ |
Grafana UI |
/openapis* |
Swagger UI |
/* |
Webapp SPA |
/api/auth/verify is blocked by Nginx and is only for internal service-to-service calls.
Create .env from .env.example, then run:
docker compose up --buildMain local URLs:
| Service | URL |
|---|---|
| Web application | https://localhost |
| Nginx health check | http://localhost/health |
| Prometheus | https://localhost/prometheus/ or http://localhost:9090 |
| Grafana | https://localhost/grafana/ or http://localhost:9091 |
| Direct Game Service diagnostics | http://localhost:3002 |
The Compose stack includes auth-db, game-db, redis, users, auth, gameservice, gamey, webapp, nginx, prometheus and grafana. The optional certbot service is behind the certbot profile.
Install dependencies per component and run services in separate terminals.
cd auth
npm install
npm run devcd users
npm install
npm run build
npm startcd gameservice
npm install
npm run devcd gamey
cargo run -- --mode server --port 4000cd webapp
npm install
npm run devLocal backend development needs PostgreSQL for auth, PostgreSQL for gameservice, Redis for matchmaking/sessions and gamey/models/yovi_model.onnx for the neural bots. The Users service also needs AUTH_SERVICE_URL for protected profile routes. Using Docker Compose for infrastructure is the simplest setup.
Root .env.example documents the variables used by Compose:
| Variable | Used by | Purpose |
|---|---|---|
IMAGE_TAG |
Compose images | Tag used for GHCR image names. |
PUBLIC_HOST |
Prometheus/Grafana | Public hostname for generated monitoring URLs. |
JWT_SECRET |
Auth, Game Service | JWT signing/verification secret. Required by auth. |
AUTH_DB_PASSWORD |
auth-db, auth |
PostgreSQL password for Auth. |
GAME_DB_PASSWORD |
game-db, gameservice |
PostgreSQL password for Game Service. |
PERSPECTIVE_API_KEY |
Game Service | Optional Google Perspective API key for chat moderation. |
PERSPECTIVE_TIMEOUT_MS |
Game Service | Perspective API timeout. |
PERSPECTIVE_FAIL_MODE |
Game Service | allow or reject when Perspective is unavailable. |
VITE_GAME_ENGINE_API_URL |
Webapp | Gamey API base path. |
VITE_GAME_SERVICE_API_URL |
Webapp | Game Service API base path. |
VITE_AUTH_API_URL |
Webapp | Auth API base path. |
VITE_USERS_API_URL |
Webapp | Users API base path. |
DUCKDNS_TOKEN, DUCKDNS_DOMAIN, CERTBOT_EMAIL |
Certbot | TLS certificate automation for DuckDNS deployments. |
npm run dev: start Vite.npm run build: TypeScript build plus Vite production build.npm run lint: run ESLint.npm test: run Vitest in watch mode.npm run test:coverage: run unit tests with coverage.npm run test:e2e: start local webapp/users and run Cucumber + Playwright.npm run test:e2e:docker: run Cucumber + Playwright against an already running Docker stack.
npm run dev: start withtsx watch.npm run start: startsrc/index.tswithtsx.npm run build: compile TypeScript.npm test: run Vitest.npm run test:coverage: run tests with coverage.npm run db:init: initialize the PostgreSQL schema.
npm run dev: runsrc/app.tswithts-node-dev; this initializes middleware only and does not start the HTTP listener.npm run build: compile TypeScript.npm start: run compileddist/src/index.js.npm test: run Vitest.npm run test:coverage: run tests with coverage.npm run db:init: initialize the SQLite schema.
npm run dev: start withts-node-dev.npm run build: compile TypeScript.npm start: run compileddist/src/app.js.npm test: run Vitest.npm run test:coverage: run tests with coverage.
cargo build: compile the Rust engine.cargo run: run CLI human mode.cargo run -- --mode computer --bot medium: play against a bot.cargo run -- --mode server --port 4000: run the HTTP bot server.cargo test: run Rust tests.cargo bench: run Criterion benchmarks.cargo doc --open: generate and open Rust docs.
python -m pip install -r training/requirements.txt: install training dependencies.python -m pytest training -q: run training tests.python training/train.py ...: train and export the model.python training/export_model.py ...: export a PyTorch checkpoint to ONNX.
cd docs && npm install: install doc tooling wrappers.cd docs && npm run build: generate HTML underdocs/build.cd docs && npm run deploy: publishdocs/buildto GitHub Pages.
See loadtests/README.md for k6 and Artillery commands. The suites can target the local Docker network or the deployed DuckDNS environment.
You can also take a look to our terraform project here.