About arc42

arc42, the template for documentation of software and system architecture.

Template Version 8.2 EN. (based upon AsciiDoc version), January 2023

Created, maintained and © by Dr. Peter Hruschka, Dr. Gernot Starke and contributors. See https://arc42.org.


Note

This version of the template contains some help and explanations. It is used for familiarization with arc42 and the understanding of the concepts. For documentation of your own system you use better the plain version.

1. Introduction and Goals

YOVI is a web platform for playing the game Y, developed by Micrati.

The system is designed for both human users and automated agents (bots). Its primary goals are to provide a smooth and engaging user experience when playing against an Artificial Intelligence (AI) with configurable board sizes and selectable difficulty levels, and to support real-time online multiplayer matches between human players through a matchmaking system.

YOVI consists of a React-based web frontend (running in the browser), an Auth Service (managing authentication and credentials), a Users Service (managing user profile data), a Game Service (handling match persistence, statistics, online matchmaking, and real-time sessions via Socket.IO), and a Rust-based Game Server (handling game logic and bot strategies). All backend services communicate via REST APIs using JSON messages, with YEN notation for game states, and are accessible through a single Nginx API Gateway.

This section summarizes the most relevant functional requirements from an architectural perspective.

1.1. Requirements Overview

The following table summarizes the main use cases of the system:

Primary Actors Use Case / Functionality Description

Player

Play Game vs AI

The player accesses the web application in their browser and starts a new game of Y against an AI bot. The React frontend displays a board with configurable size. The player takes turns placing pieces on the board. After each player move, the frontend sends the current game state in YEN notation to the Game Server via Nginx. The AI responds with its move, which is applied to the board and shown to the player. The Game Service persists each move in gamedb (PostgreSQL). The system manages turns and checks after each move if the game has ended. The process repeats until a victory or defeat condition occurs.

Player

Online Multiplayer Match

A registered player joins the online matchmaking queue through the React frontend. The Game Service searches for another available player. When two players are matched, a real-time session is created and both players are connected via Socket.IO. Each player takes turns placing pieces; the board state is broadcast in real time to both clients after every move. If no opponent is found within the configured timeout (MM_TIMEOUT_SEC), the system assigns a bot as the opponent (bot fallback).

Player

Turn Timeout and Bot Fallback

During an online match, each player has a limited time to make their move (TURN_TIMEOUT_SEC). If a player does not move within the allowed time, the TurnTimerService triggers the BotFallbackService, which computes and applies a move automatically on the player’s behalf, keeping the game progressing without interruption.

Player

Strategy Configuration

Before or during a game, the player selects a game strategy for the AI and an associated difficulty level through the React UI. The system stores this configuration in the Game Service and uses it whenever it requests the next move from the Game Server. The game state and selected strategy are sent to the Rust Game Server, which calculates the move accordingly.

Registered Player

History and Statistics Management

A registered player accesses their profile within the web application. The React frontend requests statistics from the Game Service via Nginx. The system retrieves information associated with the user from gamedb (PostgreSQL), including total games played, wins, losses, and other performance metrics. This information is presented in a structured manner in the UI, allowing the player to track progress and results over time.

Player

User Registration and Authentication

A new player registers through the React frontend. The Auth Service receives the registration request, hashes the password, and stores the credentials in authdb (PostgreSQL). On subsequent visits, the player logs in through the Auth Service, which validates credentials and returns a JWT token used to authenticate requests to other services.

External Bot

API for External Bots

An external bot makes requests to the system API through Nginx to create games, check board state, or make moves. The bot sends the game state using YEN notation to the Game Server and receives responses in the same format. Authentication is handled by the Auth Service against authdb (PostgreSQL), and match data is persisted by the Game Service in gamedb (PostgreSQL).

System (Game Server)

Move Validation and Suggestion

The Game Server receives the current game state in YEN notation from the React frontend (via Nginx). The Rust module determines if the game has ended and, if not, calculates the optimal next move according to the selected strategy. The result is returned to the frontend to update the game board. The Game Server is completely stateless and has no database access.

1.2. Quality Goals

The following table outlines the key quality attributes that are most important for the architecture of the YOVI system

Quality Attribute Description

Performance

The system must calculate moves and check victory conditions in suitable timeframes to ensure a smooth gameplay experience, even on variable-size boards.

Scalability

The system must support multiple concurrent games and users, allowing growth without major architectural redesigns.

Maintainability

The architecture should facilitate adding new strategies, Y game variants, or logic changes without impacting the rest of the system.

Interoperability

The system must allow integration with external clients through a well-defined, documented, and interface-independent API.

Usability

The web application should offer a clear and intuitive interface, enabling users to play games and consult information effortlessly.

Security

The system should protect backend services from direct external access, handle authentication properly, and ensure data integrity through controlled and isolated database access per service.

Real-time Responsiveness

Online multiplayer matches must propagate board state updates to all connected players with minimal latency, ensuring a seamless turn-based experience over WebSocket connections.

1.3. Stakeholders

The table below identifies the main stakeholders of the YOVI system, along with their roles, contacts, and expectations regarding the architecture and the delivered solution.

Role/Name Contact Expectations

Micrati (Client)

Micrati Company

Delivery of a functional system that meets all requirements.

Development Team

UO302313@uniovi.es – David Fernando Bolaños Lopez UO294946@uniovi.es – Raúl Velasco Vizán UO301919@uniovi.es – Ángela Nistal Guerrero UO300731@uniovi.es – Olai Navarro Baizán UO301831@uniovi.es – Alejandro Requena Roncero

Develop a robust solution, well-documented and easy to integrate.

Players

Application Users

An attractive web interface, ability to check personal statistics, and AI/bots that provide a real challenge with fast response times and selectable difficulty levels.

Professors

Jose Emilio Labra Gayo

Technical quality in code, a functional project, and coherent architectural documentation.

2. Architecture Constraints

Before starting the design and implementation of YOVI, it is important to be aware of the constraints that will guide architectural decisions. These constraints reflect organizational limitations, technical choices, and mandatory practices that the development team must follow. Understanding them helps ensure that the architecture is feasible, maintainable, and aligned with project requirements.

2.1. Organizational Constraints

The following organizational constraints define the environment in which the YOVI system is developed.

Constraint Explanation

Small team of 5 people

The entire solution must be developed and maintained by a small team, so simplicity, modularity, and ease of integration are prioritized.

Delivery deadlines

The system must meet the deadlines set by the ASW project, including partial and final submissions.

Mandatory testing

Unit, integration, and end-to-end tests must be performed during development to ensure system quality.

2.2. Technical Constraints

Technical constraints specify mandatory technologies, languages, and communication protocols that the system must adopt.

Constraint Explanation

Frontend language: TypeScript

The web application must be implemented in TypeScript, so client-side logic must adhere to this ecosystem.

Frontend framework: React

The web interface must be built using React, which influences component structure and state management.

Game logic module language: Rust

Victory checking and move suggestion are implemented in Rust, constraining the communication interface and available libraries.

Communication via JSON / YEN notation

All exchanges between the web application and the game logic module, as well as with the bot API, must use JSON messages in YEN format.

Mandatory web deployment

The application must be deployed and publicly accessible, influencing architecture design for web hosting and basic scalability.

Data persistence

Storage of users, games, and statistics is required, affecting database selection and backend organization.

3. Context and Scope

Yovi is a distributed web application for playing the Y board game against bots or against other human players. The system combines a React frontend, a Node.js service layer, and a Rust game engine. Registered users can authenticate, maintain a profile, create matches, review their statistics, enter the online matchmaking queue, and play real-time matches through Socket.IO.

3.1. Business Context

3.1.1. Communication Partners

business context
Partner Input Output

Human Player

  • Registration and login credentials

  • Profile reads and updates

  • Match creation requests (BOT, LOCAL_2P, ONLINE)

  • Gameplay actions and online session events

  • Ranking and statistics queries

  • Access and refresh tokens

  • Profile data

  • Match IDs, board state and results

  • Ranking, statistics and history

  • Matchmaking and session events

Bot Client

  • YEN board positions

  • Bot identifier and difficulty alias

  • Move computation requests

  • Computed move

  • Updated game status

Administrator

  • Dashboard access

  • Prometheus queries

  • Operational checks and incident diagnosis

  • Metrics time series

  • Service health indicators

  • Bot latency and matchmaking latency graphs

3.1.2. Domain Concepts

  • YEN (Y-encoded Notation) is the canonical serialization for board state exchanged with the Rust engine.

  • Match is a persistent game record stored in gamedb, with mode (BOT, LOCAL_2P, ONLINE), rules and outcome.

  • Online Session is the live Redis-backed state used during human-vs-human play.

  • Matchmaking Queue is the Redis-backed waiting area that pairs compatible online players.

  • Ranking is the ELO-based leaderboard derived from finished ranked matches.

  • Bot Difficulty Alias maps user-facing levels (easy, medium, hard, expert, expert_fast) to concrete engine bots.

3.2. Technical Context

3.2.1. System Landscape

technical context

3.2.2. Technical Interfaces

Connection Technology Channel Purpose

Browser → Nginx

HTTPS, REST, Socket.IO

443 (80 redirects)

  • Public entry point

  • Static SPA delivery

  • API access

  • WebSocket upgrade for online play

Nginx → Auth Service

HTTP

3001

  • Registration, login, refresh, logout

  • Internal token verification endpoint routing

Nginx → Users Service

HTTP

3000

  • Profile CRUD under /api/users/profiles/*

  • Service metrics under /metrics

Nginx → Game Service

HTTP + Socket.IO

3002

  • Match creation and persistence

  • Rankings and statistics

  • Online queue and session REST endpoints

  • Socket.IO path /api/game/socket.io/

Nginx → Gamey

HTTP

4000

  • Health and metrics

  • Bot move computation under /api/gamey/v1/ybot/*

Users Service → Auth Service

Internal HTTP

Docker network

  • Centralized JWT verification using AUTH_SERVICE_URL

  • Short timeout plus cached verification results

Game Service → Auth Service

Internal HTTP

Docker network

  • Centralized JWT verification for all /api/game/* endpoints

  • Keeps token semantics in one service

Game Service → Redis

Redis protocol

6379

  • Matchmaking queue

  • Live online sessions

  • Socket.IO Redis adapter

Auth Service → authdb

PostgreSQL

5432

  • Credentials, refresh tokens and token metadata

Users Service → users.db

SQLite

local file

  • User profiles and preferences

Game Service → gamedb

PostgreSQL

5432

  • Match records

  • Move history

  • Rankings and statistics

3.2.3. Key API Endpoints

Authentication:

  • POST /api/auth/register

  • POST /api/auth/login

  • POST /api/auth/refresh

  • POST /api/auth/logout

  • POST /api/auth/logout-all

  • POST /api/auth/verify (internal only, blocked externally by Nginx)

Users:

  • POST /api/users/profiles

  • GET /api/users/profiles/by-username/:username

  • GET /api/users/profiles/:id

  • PUT /api/users/profiles/:id

Game Service:

  • POST /api/game/matches

  • GET /api/game/matches/:id

  • POST /api/game/matches/:id/moves

  • PUT /api/game/matches/:id/finish

  • GET /api/game/stats/:userId

  • GET /api/game/rankings

  • GET /api/game/rankings/:userId

Online play:

  • POST /api/game/online/queue

  • GET /api/game/online/queue/match

  • DELETE /api/game/online/queue

  • GET /api/game/online/sessions/active

  • GET /api/game/online/sessions/:matchId

  • POST /api/game/online/sessions/:matchId/moves

  • POST /api/game/online/sessions/:matchId/reconnect

  • POST /api/game/online/sessions/:matchId/abandon

  • Socket.IO events: queue:join, queue:cancel, match:join, move:play, chat:message, queue:status, matchmaking:matched, session:state

Gamey:

  • GET /api/gamey/status

  • POST /api/gamey/v1/ybot/choose/:botId

  • POST /api/gamey/v1/ybot/play

  • GET /api/gamey/metrics

3.2.4. Data Formats

Example YEN payload:

{
  "size": 5,
  "turn": 0,
  "players": ["B", "R"],
  "layout": "...../...../...../...../....."
}

Example matchmaking request:

{
  "boardSize": 9,
  "rules": {
    "pieRule": true,
    "honey": false
  }
}

3.2.5. Deployment Considerations

  • The public surface is intentionally narrow: browser traffic enters through Nginx only.

  • Auth, users, game persistence and game computation are split into separate deployable services.

  • users and gameservice depend on auth for token validation, so auth availability is part of the runtime security boundary.

  • Redis contains only ephemeral online state; durable match history is always stored in gamedb.

  • Prometheus and Grafana are exposed through Nginx path prefixes (/prometheus/ and /grafana/) instead of direct public container ports.

4. Solution Strategy

4.1. Overview

The solution strategy is driven by four concerns:

  • keep game computation fast enough for interactive play,

  • isolate data and failures by domain,

  • centralize authentication semantics in one service,

  • make realtime online play observable and load-testable.

4.2. Main Strategic Decisions

Decision Why it is the chosen strategy

Nginx as the only public ingress

  • Terminates TLS and redirects port 80 to 443.

  • Centralizes CORS, rate limiting, static frontend delivery and Socket.IO upgrade handling.

  • Exposes monitoring under /prometheus/ and /grafana/.

  • Blocks external access to /api/auth/verify, keeping token verification internal.

Separate Rust game engine (gamey)

  • Keeps rules, board evaluation and bot logic isolated from persistence concerns.

  • Provides low-latency move computation and a clean performance boundary for Criterion benchmarks.

  • Supports both classic search bots and neural MCTS bots behind stable difficulty aliases.

Auth as the source of truth for token verification

  • users and gameservice no longer interpret JWTs independently.

  • Token semantics, claims validation and token type checks stay in one service.

  • Internal callers use AUTH_SERVICE_URL plus short timeouts and small caches to avoid cascading latency.

Polyglot persistence by domain

  • authdb stores credentials and refresh tokens.

  • users.db stores profile data.

  • gamedb stores matches, moves, rankings and statistics.

  • Redis stores only ephemeral online queue and session state.

Realtime online play in gameservice

  • Online queue, session state and Socket.IO live together in one service.

  • Redis removes pressure from gamedb for transient session data.

  • Matchmaking and timeout behavior can be tested separately from the Rust engine.

Testing and observability as first-class concerns

  • Vitest covers Node.js services and frontend units/integration flows.

  • Cucumber + Playwright cover browser-level system scenarios.

  • k6 and Artillery validate REST and Socket.IO under load.

  • Prometheus, Grafana and Criterion provide runtime and in-process performance evidence.

4.3. Architectural Shape

solution architecture

The architecture deliberately keeps responsibilities narrow:

  • the browser coordinates UX and initiates requests,

  • Nginx protects and routes,

  • Auth owns identity and tokens,

  • Users owns profiles,

  • Game Service owns persistence and realtime orchestration,

  • Gamey owns rules and bot computation,

  • Prometheus/Grafana expose operational evidence.

4.4. Internal Design Patterns

Pattern Usage in Yovi

API Gateway

Nginx routes /api/auth/, /api/users/, /api/game/, /api/gamey/, /prometheus/ and /grafana/, and blocks public /api/auth/verify.

Repository pattern

auth, users and gameservice keep database access behind repositories so service logic can be tested with mocks or isolated database fixtures.

Strategy pattern

gamey maps user-facing bot levels to concrete implementations such as random, minimax and neural MCTS.

Event-driven realtime flow

Socket.IO events (queue:join, matchmaking:matched, match:join, move:play, chat:message, session:state) decouple online session updates from REST endpoints.

Layered service structure

Controllers handle transport concerns, services own business behavior, repositories own persistence, middleware owns cross-cutting concerns such as auth and error mapping.

4.5. Quality Goal Mapping

Quality Goal Strategy Concrete implementation

Performance

  • Rust for move computation

  • Redis for transient online state

  • cached token verification

  • Criterion benchmarks for evaluate, evaluate_batch and choose-move paths

  • load-tested matchmaking and online flows

  • Prometheus latency histograms for bot moves and matchmaking

Security

  • single ingress

  • central token verification

  • strict domain data ownership

  • /api/auth/verify is internal-only

  • /api/game/ and /api/users/profiles/ require bearer tokens

  • credentials never leave auth

Maintainability

  • service boundaries

  • typed codebase

  • documented contracts

  • TypeScript + Rust

  • arc42 and service READMEs

  • automated regression tests per service

Reliability

  • online state isolated from durable state

  • timeout and reconnect handling

  • Redis stores live sessions, gamedb stores finished history

  • matchmaking cleanup, reconnect grace and bot fallback logic

Observability

  • unified metrics pipeline

  • repeatable load suites

  • /metrics in every backend service

  • Grafana overview dashboard

  • k6 and Artillery profiles committed in the repo

4.6. Constraints with Architectural Impact

Constraint Architectural consequence

Rust is mandatory for the engine

The game rules and bot logic live in a standalone service instead of being embedded into Node.js.

YEN remains the engine contract

Browser, Game Service and Gamey need conversion layers between stored match state and engine requests.

The system must be deployable on the web

TLS ingress, Dockerized services and static SPA delivery are required.

The project must support both AI and online modes

The solution combines durable match persistence with a separate realtime session model.

Load and acceptance evidence are part of the deliverable

Tests, coverage, load profiles, Grafana dashboards and Criterion benchmarks are documented as architecture evidence, not as afterthoughts.

5. Building Block View

5.1. Whitebox Overall System

5.1.1. Overview Diagram

level1 overview

Motivation

The system is decomposed into focused subsystems so that persistence, realtime orchestration, authentication and game computation can evolve independently:

  • Nginx is the only public ingress and owns cross-cutting HTTP concerns.

  • React Frontend owns the browser UX and client-side orchestration.

  • Auth Service owns identity, credentials, refresh tokens and token verification.

  • Users Service owns profile data and delegates JWT validation to Auth Service.

  • Game Service owns durable game state, rankings, matchmaking and Socket.IO sessions.

  • Gamey owns Y rules and bot move computation and remains stateless.

  • Redis stores only transient online state.

Contained Building Blocks

Building Block Responsibility

Nginx (API Gateway)

  • Single public ingress via 443 with 80 redirect

  • Routes /api/auth/, /api/users/, /api/game/, /api/game/socket.io/, /api/gamey/*, /prometheus/, /grafana/ and frontend assets

  • Handles CORS, rate limiting and WebSocket upgrade

  • Blocks public access to /api/auth/verify

React Frontend (Webapp)

  • Runs entirely in the user’s browser

  • Renders board, matchmaking, rankings and profile views

  • Stores session state and access token client-side

  • Calls backend APIs only through Nginx

  • Opens Socket.IO connections for online play

Auth Service

  • Owns authdb

  • Handles register, login, refresh, logout and logout-all

  • Verifies access tokens for other services through /api/auth/verify

  • Exposes Prometheus metrics at /metrics

Users Service

  • Owns users.db

  • Manages user profiles under /api/users/profiles/*

  • Uses verifyJwtMiddleware plus AuthVerifyClient to validate bearer tokens through Auth Service

  • Exposes Prometheus metrics at /metrics

Game Service

  • Owns gamedb and Redis

  • Protects all /api/game/* routes with centralized auth verification

  • Persists matches, moves, rankings and statistics

  • Owns matchmaking, online sessions, reconnect grace and turn timeouts

  • Emits Socket.IO events and exposes metrics at /metrics

Gamey

  • Implements core Y rules, board evaluation and bot selection

  • Exposes /status, /metrics, /v1/ybot/choose/:botId and /v1/ybot/play

  • Maps aliases such as medium to minimax_balanced_d2

  • Has no database access and remains fully stateless

Redis

  • Ephemeral store used only by Game Service

  • Keeps queue entries, active sessions and Socket.IO pub/sub state

  • Durable history always lives in gamedb

authdb

  • Stores credentials, refresh tokens and token metadata

  • Accessible only through Auth Service

users.db

  • Stores user profiles and preferences

  • Accessible only through Users Service

gamedb

  • Stores matches, move history, rankings and statistics

  • Accessible only through Game Service

5.2. Level 2

5.2.1. White Box: Auth Service

level2 auth
Component Responsibility

AuthController

  • Exposes register, login, refresh, logout, logout-all and verify

  • Starts per-route HTTP metrics timers

  • Maps service errors to HTTP responses

AuthService

  • Registers users

  • Hashes and verifies passwords

  • Issues and rotates tokens

  • Maintains refresh-token lifecycle

CredentialsRepository

  • Encapsulates authdb access

  • Persists credentials and token metadata

VerifyTokenMiddleware

  • Validates access tokens for /api/auth/verify

  • Returns normalized claims for internal callers

5.2.2. White Box: Users Service

level2 users
Component Responsibility

UsersController

  • Exposes POST /api/users/profiles

  • Exposes GET /api/users/profiles/by-username/:username

  • Exposes GET /api/users/profiles/:id

  • Exposes PUT /api/users/profiles/:id

UserService

  • Implements profile CRUD logic

  • Validates profile updates

UserRepository

  • Reads and writes users.db

  • Keeps SQL isolated from HTTP concerns

VerifyJwt

  • Protects /api/users/profiles/*

  • Reads bearer token from Authorization

  • Attaches userId and username to the request

AuthVerifyClient

  • Calls POST /api/auth/verify

  • Uses a small in-memory cache and a short timeout

  • Converts upstream failures into service-unavailable responses

5.2.3. White Box: Game Service

level2 gameservice
Component Responsibility

GameController

  • Exposes match, ranking, stats, matchmaking and online session REST endpoints

  • Validates payloads and maps domain errors to HTTP

MatchService

  • Creates matches and persists moves

  • Finishes matches and triggers ranking updates

  • Queues bot move work for AI matches

StatsService

  • Aggregates player statistics and history views

RankingService

  • Applies ELO updates

  • Exposes leaderboard and per-user ranking

MatchmakingService

  • Manages the Redis queue

  • Pairs compatible players

  • Emits matchmaking:matched

OnlineSessionService

  • Creates and updates live session state

  • Handles reconnect, abandon, chat and move application

  • Emits session:state

TurnTimerService

  • Tracks per-turn deadlines

  • Notifies session logic when a turn expires

BotFallbackService

  • Calls Gamey when a bot move is needed during online play

  • Applies automatic moves after timeout or fallback conditions

VerifyJwt / AuthVerifyClient

  • Validate tokens through Auth Service

  • Protect the entire /api/game router

SocketServer

  • Handles queue:join, queue:cancel, match:join, move:play and chat:message

  • Uses the Redis adapter to support multi-instance delivery

5.2.4. White Box: Gamey

level2 gamey
Component Responsibility

Axum Router

  • Exposes /status, /metrics, /v1/ybot/choose/:botId and /v1/ybot/play

  • Parses requests and serializes engine responses

Bot Registry

  • Resolves aliases such as easy, medium, hard, expert and expert_fast

  • Keeps the available bot implementations available to HTTP handlers

Minimax Bots

  • Implement classic search-based play

  • Include the balanced medium bot alias

Neural MCTS Bots

  • Load the ONNX model at startup

  • Power expert and expert_fast

Game Domain

  • Owns board representation, rules, win detection and move application

Metrics

  • Publishes bot move histograms and other Prometheus metrics

6. Runtime View

This section describes the main runtime collaborations across authentication, profile access, AI matches, realtime online play, rankings and timeout handling.

6.1. Runtime Scenario 1: Registration and Login

runtime login

Notable aspects:

  • only Auth Service touches credentials,

  • token issuance is fully isolated from profile and match persistence,

  • Prometheus can observe latency and success rates through auth metrics.

6.2. Runtime Scenario 2: Authorized Profile Request

runtime profile auth

Notable aspects:

  • The auth decision is centralized in Auth Service.

  • Short auth timeouts prevent profile requests from hanging indefinitely.

6.3. Runtime Scenario 3: AI Match Creation and Persistence

runtime ai match

Notable aspects:

  • Game Service owns durable match creation,

  • the browser never talks directly to gamedb,

  • authorization is checked before any match write happens.

6.4. Runtime Scenario 4: Human Move Against a Bot

runtime bot move

Notable aspects:

  • Gamey remains stateless and performs no persistence,

  • browser orchestrates the engine call and then persistence,

  • match state is durable only after Game Service accepts the move.

6.5. Runtime Scenario 5: Rankings and Statistics

runtime ranking

Notable aspects:

  • rankings and statistics are read from the same durable game store,

  • Game Service is the single API for leaderboard and history queries.

6.6. Runtime Scenario 6: Online Matchmaking and Session Join

runtime matchmaking

Notable aspects:

  • queue state is ephemeral and Redis-backed,

  • pairing and live-session creation happen inside Game Service,

  • REST polling remains available as a fallback through /api/game/online/queue/match.

6.7. Runtime Scenario 7: Online Move, Chat and Reconnect

runtime online session

Notable aspects:

  • Redis stores the authoritative live session snapshot,

  • gamedb keeps the durable move history,

  • reconnect uses explicit session APIs and grace windows.

6.8. Runtime Scenario 8: Turn Timeout and Bot Fallback

runtime timeout

Notable aspects:

  • the timeout path reuses the same engine used for normal bot play,

  • automatic moves remain auditable because they are persisted,

  • reconnect grace is handled before timeout escalation.

7. Deployment View

The deployment view documents how Yovi is packaged and exposed in Docker-based environments. The same logical topology is used in local development and in the deployed stack.

7.1. Infrastructure Level 1: Production-Like Docker Topology

deployment level1

Why this topology

  • Nginx is the only public ingress.

  • Every backend service stays on the internal Docker network.

  • Monitoring is reachable through Nginx path prefixes instead of publishing extra public ports.

  • Redis is isolated to online features; durable state is stored only in PostgreSQL or SQLite volumes.

Mapping of building blocks to infrastructure

Software Artifact Infrastructure Mapping

React Frontend

Built as static assets and served by Nginx. No standalone public frontend server is exposed.

Nginx

Public container exposing 443; redirects 80 to HTTPS, proxies API and Socket.IO traffic, exposes /prometheus/ and /grafana/.

Auth Service

Internal Node.js container on port 3001, backed by authdb volume.

Users Service

Internal Node.js container on port 3000, backed by users.db volume and depending on Auth Service for token verification.

Game Service

Internal Node.js container on port 3002, backed by gamedb volume and Redis.

Gamey

Internal Rust container on port 4000, stateless except for the ONNX model bundled in the image.

Redis

Internal in-memory container used only by Game Service for online queue, live sessions and Socket.IO adapter state.

Prometheus

Internal container scraping /metrics from backend services.

Grafana

Internal container visualizing Prometheus data through the provisioned dashboards.

7.2. Infrastructure Level 1: Development Environment

Development uses the same containerized topology, but normally on a developer workstation with Docker Desktop instead of a VM. This keeps service discovery, ports and internal URLs consistent with the deployed stack.

Key properties:

  • one-command startup through Docker Compose,

  • same reverse-proxy behavior as production,

  • same internal service names (auth, users, gameservice, gamey, redis, prometheus, grafana),

  • same load-test target topology for local k6 and Artillery.

7.3. Infrastructure Level 2: Internal Network and Observability

deployment level2

Internal structure explanation

  • AUTH_SERVICE_URL points from users and gameservice to the internal auth container, not to Nginx.

  • /api/auth/verify is blocked at the gateway, so only internal service-to-service callers can use it.

  • Socket.IO is proxied through /api/game/socket.io/, which means websocket upgrade support is part of the gateway contract.

  • All backend services export /metrics; Prometheus scrapes them and Grafana consumes only Prometheus.

Operational consequences

  • If Redis restarts, online sessions and queue state are lost, but authentication, profiles and historical matches continue to work.

  • If Auth Service becomes unavailable, protected profile and game endpoints fail closed with 503 rather than accepting unverifiable tokens.

  • Gamey can be scaled independently because it is stateless and uses only HTTP plus a bundled model file.

8. Cross-cutting Concepts

8.1. Domain Model

domain model

The central domain concepts are:

  • Player: authenticated user participating in matches and rankings,

  • Match: durable record of a game,

  • OnlineSession: live Redis-backed state for realtime play,

  • Ranking: ELO-based standing in competitive play,

  • YEN: contract used to send board state to the Rust engine.

8.2. User Experience Concepts

The browser experience follows a few stable rules:

  • authentication, profile, history, rankings and gameplay are reachable without changing applications,

  • bot matches are responsive and deterministic when forced lines exist,

  • online play uses realtime updates instead of polling as the primary experience,

  • reconnect and timeout behavior are explicit in the UI so players understand whether they are waiting for a human move or an automatic fallback.

8.3. Security Concepts

Concept How it is applied

Single ingress

Nginx is the only public entry point. Backend services stay on the internal Docker network.

Centralized token verification

Auth Service owns /api/auth/verify; users and gameservice call it internally instead of validating tokens independently.

Fail closed

If token verification fails or Auth Service is unavailable, protected requests return 401 or 503; they are never accepted optimistically.

Data ownership

Credentials stay in authdb, profiles stay in users.db, and game history stays in gamedb.

Gateway protection

Nginx rate-limits public API traffic and blocks external /api/auth/verify.

8.4. Architecture and Design Patterns

  • Microservices: auth, users, gameservice and gamey are deployable services with explicit responsibilities.

  • Layered design: controllers, services, repositories and middleware are separated in the Node.js services.

  • Strategy pattern: Gamey resolves difficulty aliases to concrete bot strategies.

  • Event-driven realtime flow: Socket.IO is used for queue status, matchmaking, session state, chat and move propagation.

  • Gateway pattern: Nginx centralizes cross-cutting HTTP concerns.

8.5. Persistence Concepts

Durable and ephemeral data are intentionally separated:

  • authdb stores credentials and token metadata,

  • users.db stores profile data,

  • gamedb stores matches, move history, rankings and statistics,

  • Redis stores queue entries, live online sessions and Socket.IO adapter state.

This split allows online-state failures to be isolated from historical data and credentials.

8.6. Ranking Concept

Ranked results use an ELO model maintained by Game Service:

  • BOT matches use fixed bot ratings as the opponent reference,

  • ONLINE matches use the actual opponent rating at finish time,

  • LOCAL_2P matches do not update rankings,

  • ranking updates are best-effort relative to match completion: the match result is more important than the leaderboard write.

8.7. Testing and Verification Concept

Testing is treated as architecture evidence, not only as implementation support.

Test family Tools and scope

Unit and integration

Vitest in auth, users, gameservice and webapp; cargo test in gamey, including property-based tests through proptest.

System / acceptance

Cucumber + Playwright in webapp/test/e2e, executed through npm run test:e2e:docker.

Load testing

k6 for REST flows and Artillery for Socket.IO flows, both documented in loadtests/README.md.

Benchmarks

Criterion benchmarks in gamey/benches/gamey_benchmarks.rs, including evaluate, evaluate_batch and choose-move paths.

Regression diagnostics

Service-specific auth middleware tests, matchmaking regression tests and Artillery smoke profiles for TLS and websocket validation.

8.8. Observability Concept

The observability stack is based on Prometheus and Grafana:

  • every backend service exports /metrics,

  • Nginx exposes /prometheus/ and /grafana/,

  • the provisioned Grafana overview dashboard includes service health, active games, socket connection peak, bot-move latency, matchmaking latency and HTTP request rate panels,

  • load tests and benchmarks are used to validate suspicious metrics before changing alert or dashboard semantics.

8.9. Error Handling Concept

Errors are normalized per layer:

  • the frontend turns backend failures into user-readable states,

  • Node.js services map domain errors to structured HTTP responses,

  • Socket.IO errors are emitted only to the affected session/client when appropriate,

  • Gamey returns structured HTTP failures for invalid requests and engine problems,

  • internal auth verification failures are surfaced as 503 instead of leaking transport details.

9. Architecture Decisions

This section records the main accepted architectural decisions. Rejected options are kept inside each ADR as alternatives, so the trade-off is visible without duplicating mirror-image decisions.

9.1. ADR 1: Microservices by Domain Boundary

  • Context: The platform combines authentication, profiles, durable game history, realtime online play and compute-heavy bot logic. These concerns evolve at different speeds and fail in different ways.

  • Status: Accepted.

  • Alternatives: A monolithic backend, or a partially split backend with shared persistence.

  • Decision: Split the platform into Auth Service, Users Service, Game Service, Gamey, Webapp and Nginx. Each service owns a narrow responsibility and explicit interfaces.

  • Pros: Clearer ownership, better fault isolation, independent scaling paths, and cleaner separation between gameplay orchestration and engine logic.

  • Cons: More HTTP hops, more operational components, and more integration-testing effort across services.

  • Consequences: The backend is structured around explicit domain boundaries instead of a single application boundary.

9.2. ADR 2: Rust for the Game Engine

  • Context: Move computation and rules enforcement are the most performance-sensitive and correctness-sensitive part of the system.

  • Status: Accepted.

  • Alternatives: Implement the engine inside Node.js, or use another managed-language backend for bot logic.

  • Decision: Implement Gamey in Rust and expose it through a small HTTP API.

  • Pros: Strong memory safety, predictable performance, a clean benchmark boundary, and a good fit for search-heavy bot logic.

  • Cons: Steeper learning curve, separate build pipeline, and additional complexity around runtime model compatibility.

  • Consequences: Game rules and bot strategies are isolated inside Gamey and can be tuned independently from persistence and session orchestration.

9.3. ADR 3: Polyglot Persistence with Explicit Data Ownership

  • Context: Credentials, profiles, durable match history and live online sessions have different persistence needs.

  • Status: Accepted.

  • Alternatives: A single shared relational database, or a document database for all domains.

  • Decision: Use authdb (PostgreSQL) for auth, users.db (SQLite) for profiles, gamedb (PostgreSQL) for matches and rankings, and Redis for ephemeral online state.

  • Pros: Strong ownership boundaries, better fault isolation, persistence technology matched to domain needs, and clearer operational responsibilities.

  • Cons: More data stores to operate, no distributed transaction boundary, and more explicit cross-service coordination.

  • Consequences: Durable and ephemeral data are now separated by domain and lifetime instead of being administered as one shared persistence layer.

9.4. ADR 4: Nginx as the Only Public Ingress

  • Context: The system needs TLS termination, CORS, rate limiting, static frontend delivery, websocket proxying and path-based routing.

  • Status: Accepted.

  • Alternatives: Expose each service directly, or rely on a managed cloud API gateway.

  • Decision: Put Nginx in front of all services and expose only 443 publicly, with 80 redirecting to HTTPS.

  • Pros: Centralized ingress policy, smaller public attack surface, uniform TLS and websocket handling, and a single routing layer for the SPA and APIs.

  • Cons: One more critical component, and Nginx configuration becomes part of application correctness.

  • Consequences: Nginx now owns public ingress, blocks external /api/auth/verify, and exposes monitoring through path prefixes.

9.5. ADR 5: Redis plus Socket.IO for Online Play

  • Context: Human-vs-human online matches need low-latency queueing and realtime bidirectional updates.

  • Status: Accepted.

  • Alternatives: REST polling only, SSE, or in-memory matchmaking without Redis.

  • Decision: Keep live queue and session state in Redis and use Socket.IO for queue, session and chat events. Nginx proxies the websocket path /api/game/socket.io/.

  • Pros: Low-latency updates, better user experience, scalable pub/sub through the Redis adapter, and lower pressure on gamedb for transient session state.

  • Cons: Additional operational complexity, ephemeral state loss on Redis restart, and more difficult debugging of realtime flows.

  • Consequences: Online play is modeled as a Redis-backed live system plus durable persistence in Game Service.

9.6. ADR 6: Centralized JWT Verification in Auth Service

  • Context: Duplicating JWT parsing and validation rules across services creates drift, inconsistent failure behavior and duplicated security logic.

  • Status: Accepted.

  • Alternatives: Local JWT verification inside users and gameservice, or gateway-level authorization only.

  • Decision: Auth Service exposes /api/auth/verify for internal callers only. users and gameservice call it through AUTH_SERVICE_URL and treat failures as 401 or 503.

  • Pros: One source of truth for token semantics, consistent claims validation, simpler security maintenance, and easier token-policy evolution.

  • Cons: Protected requests depend on Auth availability, add internal HTTP latency, and require careful timeout handling.

  • Consequences: Token semantics are centralized, and both profile and game APIs fail closed when verification cannot be completed.

9.7. ADR 7: Benchmark and Load Evidence as Architecture Assets

  • Context: Bot strength and latency regressions are easy to introduce and difficult to reason about from code inspection alone.

  • Status: Accepted.

  • Alternatives: Rely only on ad-hoc manual profiling and sporadic load runs.

  • Decision: Keep Criterion benchmarks, k6 profiles, Artillery profiles, Prometheus metrics and Grafana dashboards in the repository and reference them from the architecture documentation.

  • Pros: Measurable performance baselines, repeatable regression detection, better architectural traceability, and better incident diagnosis.

  • Cons: More maintenance effort, evidence must be kept fresh, and benchmark or metric interpretation requires discipline.

  • Consequences: Performance and load behavior are now documented as part of the architecture instead of being treated as informal operational knowledge.

10. Quality Requirements

The architecture is optimized around five quality attributes: performance, reliability, security, maintainability and observability.

10.1. Quality Tree

quality tree

10.2. Quality Scenarios

Attribute Scenario Metric / acceptance target

Performance

A user creates, reads, plays and finishes a local or bot-backed match through the REST API.

Local k6 thresholds: create/finish p95 < 800 ms, get p95 < 500 ms, move p95 < 2000 ms.

Performance

A user authenticates through the public API.

Local k6 thresholds: register p95 < 1500 ms, login/refresh p95 < 1200 ms, success rate > 95%.

Performance

A player joins and cancels matchmaking through REST fallback endpoints.

Local k6 thresholds: queue join, poll, cancel and abandon p95 < 800 ms.

Performance

The Rust engine evaluates a board or batch for neural inference.

Criterion benchmarks exist for neural_evaluate and neural_evaluate_batch; regressions are detected from benchmark reports rather than by anecdote.

Reliability

Two players enter the online queue and complete the realtime flow under load.

Artillery online profile should complete without websocket or response-timeout failures. Latest validated local run: 640 created, 640 completed, 0 failed.

Reliability

A player disconnects or lets a turn expire.

The session remains coherent through reconnect APIs and bot fallback. Timeout smoke profile completes without scenario failures.

Security

A protected game or profile endpoint receives a missing, invalid or unverifiable token.

Request must fail closed with 401 or 503; protected routes never accept unverifiable tokens.

Security

An external client attempts to call the internal verification endpoint.

GET/POST /api/auth/verify through Nginx must be blocked (403).

Maintainability

A developer changes one domain without touching unrelated persistence code.

Each service owns its own database and automated tests cover its public behavior.

Observability

The team needs to diagnose latency or load anomalies quickly.

Prometheus metrics exist for auth, users, game service and gamey; Grafana overview exposes health, active games, socket peaks, bot latency and matchmaking latency.

10.3. Supporting Measures

  • Load thresholds are versioned in loadtests/k6/config.js.

  • Realtime regression scenarios are versioned in loadtests/artillery/*.yml.

  • In-process performance evidence is versioned in gamey/benches/gamey_benchmarks.rs.

  • Coverage targets are tracked through vitest --coverage and cargo test.

11. Risks and Technical Debts

11.1. Risks

Area Brief description Mitigation Prob. Impact Total

Security and availability

users and gameservice depend on Auth Service for every protected request. If Auth becomes unavailable or slow, profile and game endpoints degrade even if their own databases are healthy.

Keep short internal timeouts, small positive caches, clear 503 behavior, and monitor auth verification latency.

2

3

6

Model compatibility

Neural bots depend on an ONNX artifact that must stay compatible with the runtime loader. Training/export changes can produce models that fail at startup.

Freeze export contracts, add model-load smoke checks, and keep benchmark fixtures tied to the same export format.

2

3

6

Online ephemeral state

Redis stores queue and live session state only. A Redis restart drops active online sessions even if durable match history remains intact.

Keep reconnect and cleanup logic simple, document the limitation, and consider snapshot recovery only if the product scope requires it.

2

2

4

Cross-service consistency

Multi-step operations across auth, users and game data have no distributed transaction boundary.

Prefer compensating actions, explicit ownership rules and end-to-end regression tests around the affected workflows.

2

3

6

Performance on larger boards

Stronger bots and neural paths can increase latency quickly as board size grows or search depth is increased.

Keep Criterion benchmarks and Prometheus histograms under version control; gate strategy changes behind measured budgets.

2

2

4

Operational drift

Dashboards, load profiles and service behavior can drift apart, leading to misleading observability.

Treat load tests and Grafana queries as code, rerun smoke suites after protocol changes, and document known metric semantics.

2

2

4

11.2. Technical Debts

Technical debt Brief description

Distributed user lifecycle

User creation and eventual deletion span auth, users and game data without a saga or distributed transaction mechanism.

Redis durability for online matches

Online sessions are optimized for speed, not recovery. A full recovery story after Redis restart is not implemented.

Model validation in CI

Neural model export and runtime load compatibility are not yet enforced by a dedicated CI smoke stage.

Load-test evidence freshness

k6 thresholds are committed, but not every suite is rerun on every architecture change. Fresh execution evidence must be maintained deliberately.

12. Test Report

This chapter consolidates the automated test evidence currently available in the repository and the latest validated execution results collected on 23 April 2026.

12.1. Scope

The project uses several complementary test families:

  • unit and integration tests in every service,

  • browser-level acceptance/system tests,

  • REST and Socket.IO load tests,

  • in-process performance benchmarks for the Rust engine,

  • targeted regression tests for auth verification, matchmaking and online timeout behavior.

12.2. Unit and Integration Tests

Component Command Latest verified result Notes

Auth Service

npm.cmd --prefix auth run test:coverage

110 tests passed

Covers auth flows, token verification and error handling.

Users Service

npm.cmd --prefix users run test:coverage

35 tests passed

Includes the new centralized auth verification middleware regression tests.

Game Service

npm.cmd --prefix gameservice run test:coverage

292 tests passed

Covers match lifecycle, rankings, matchmaking, sessions and timeout logic.

Webapp

npm.cmd --prefix webapp run test:coverage

239 tests passed

Covers hooks, components and browser-side orchestration.

Gamey

cargo test --manifest-path gamey/Cargo.toml

all test suites passed (330 tests total)

Includes core engine tests, API tests and property-based checks.

12.3. Acceptance and System Tests

Suite Command Latest verified result Scope

Webapp E2E

npm.cmd --prefix webapp run test:e2e:docker

7 scenarios passed, 29 steps passed

Validates end-to-end browser flows through the Dockerized stack.

12.4. Code Coverage

Component Statements Branches Functions Lines

Auth Service

96.55%

86.75%

98.94%

96.95%

Users Service

79.42%

67.53%

74.28%

80.11%

Game Service

79.90%

73.33%

86.05%

84.19%

Webapp

91.16%

83.60%

90.53%

93.53%

Interpretation:

  • auth and webapp already have very strong coverage,

  • users and gameservice have good practical coverage, but still benefit from continued branch-focused testing on failure paths and uncommon flows.

12.5. Load Tests

12.5.1. Load Suites in the Repository

Tool Covered scope

k6

Auth flows, game REST flows, matchmaking REST fallback, response-time thresholds and failure-rate thresholds.

Artillery

Socket.IO matchmaking, online session join, chat and timeout scenarios, including local self-signed TLS variants.

12.5.2. Latest Validated Load Evidence

Suite Latest validated result Interpretation

Artillery online profile

640 created, 640 completed, 0 failed, 0 response timeout

Confirms that the fixed matchmaking flow now sustains the full online scenario without websocket/session failure.

Artillery online profile timing

session length mean 5986.1 ms, p95 7117 ms

Gives an end-to-end wall-clock baseline for the realtime online scenario.

Artillery timeout smoke

2 completed, 0 failed

Confirms the timeout path and fallback wiring are functional after the websocket/TLS fixes.

12.5.3. Threshold Baseline for k6

The REST load suites define acceptance thresholds in loadtests/k6/config.js. The most relevant local thresholds are:

  • auth: register p95 < 1500 ms, login/refresh p95 < 1200 ms,

  • game: create/finish p95 < 800 ms, get p95 < 500 ms, move p95 < 2000 ms,

  • matchmaking: queue join/poll/cancel/abandon p95 < 800 ms,

  • common thresholds: HTTP failure rate < 5%, checks success rate > 95%.

12.6. Criterion Benchmarks

Benchmark Latest verified result Meaning

neural_evaluate/cache_hit

about 503.69 ns

Cached single-board evaluation is effectively negligible compared with network or search overhead.

neural_evaluate/cache_miss

about 53.920 ms

Cold single-board neural inference is the meaningful lower bound for uncached evaluation cost.

neural_evaluate_batch/cache_hit

about 2.8113 us

Cached batch path stays very cheap and is suitable for repeated search reuse.

neural_evaluate_batch/cache_miss

about 167.95 ms

Cold batch inference is substantially more expensive and must stay out of latency-sensitive paths unless amortized.

These benchmarks are now explicit in gamey_benchmarks.rs, which makes performance regressions in evaluate and evaluate_batch directly visible in Criterion reports.

12.7. Other Tests and Diagnostics

  • users now includes dedicated regression tests for the Auth-service-backed JWT verification middleware and protected profile routes.

  • gameservice includes a regression test for creating multiple human matches in a single matchmaking tick.

  • gamey includes property-based tests (proptest) as part of cargo test.

  • Grafana dashboards and Prometheus metrics provide runtime validation for active games, socket peaks, bot latency and matchmaking latency.

12.8. Assessment

The current test evidence supports the main architectural claims:

  • the service boundaries are exercised by unit/integration tests,

  • the browser flow is exercised by E2E tests,

  • the realtime online flow has fresh post-fix load evidence,

  • the Rust engine has repeatable micro-benchmarks for the critical neural evaluation paths.

The main remaining gap is keeping full REST load evidence as fresh as the realtime evidence after substantial backend changes.

13. Glossary

Term Definition

API Gateway

Architectural component that serves as the single public entry point, routing client requests to backend services and managing cross-cutting concerns such as CORS, rate limiting, and WebSocket proxying

Nginx

Web server and reverse proxy used to implement the API Gateway pattern in this system

Anonymous Play

Game mode where unregistered users can play against the AI without persisting their statistics or match history

Arc42

Architecture documentation template followed in this project for structural consistency

Barycentric Coordinates

Coordinate system (x, y, z) used to represent positions on the hexagonal game board

Board

Hexagonal grid representing the Y game playing surface

Bot Client

External automated agent that plays through the system’s Bot API

Bot Fallback

Mechanism triggered by BotFallbackService when a player does not respond within the allowed turn time (TURN_TIMEOUT_SEC) or when no human opponent is found during matchmaking (MM_TIMEOUT_SEC). The Game Service calls the Rust Game Server to compute and apply a move automatically on the inactive player’s behalf.

CORS (Cross-Origin Resource Sharing)

HTTP-header based mechanism that allows a server to indicate which origins are permitted to access its resources from a browser

Docker

Containerization platform used for packaging and deploying all system services

Game Server

Rust-based microservice responsible for core game logic, move validation, and bot AI strategies. Completely stateless and has no database access.

Game Service

Node.js microservice responsible for match persistence, move history, player statistics, online matchmaking, and real-time session management via Socket.IO. Single point of access to gamedb (PostgreSQL) and Redis.

Match

Game session between two players (human or bot) with a specific board size and strategy configuration

Matchmaking

Process by which the Game Service pairs two human players waiting in the Redis-backed queue to start an online session. If no opponent is found within MM_TIMEOUT_SEC, a bot is assigned as the opponent.

Microservices

Distributed architecture pattern where the system is decomposed into independent services (React Frontend, Nginx, Auth Service, Users Service, Game Service, Game Server), each owning its own data store

Move/Movement

Player action placing a piece at specific coordinates on the board

Online Session

A real-time multiplayer match between two human players (or a human and a bot fallback), managed by the Game Service via Socket.IO. Session state is stored in Redis for low-latency access during play.

PlantUML

Tool used for generating architectural diagrams throughout the documentation

Redis

In-memory data store used exclusively by the Game Service to persist the matchmaking queue and active online session snapshots, and to act as the pub/sub adapter for Socket.IO

Registered Player

User with an account who can access match history, statistics, and online multiplayer features

Reverse Proxy

Server (Nginx) that forwards client requests to appropriate backend services and returns responses

Socket.IO

Library providing WebSocket-based bidirectional communication between the React Frontend and the Game Service. Used to broadcast real-time board state updates, turn notifications, timeout events, and game-over signals to all players in an online session.

PostgreSQL

Relational database used by Auth Service (authdb) and Game Service (gamedb) for durable transactional persistence

SQLite

Embedded relational database used by Users Service for profile persistence (users.db)

Stateless Service

Service that does not maintain persistent state between requests (e.g., Game Server). All state is passed in each request or stored externally.

Strategy

AI difficulty level and bot behavior configuration (e.g., random, heuristic, neural network)

Turn Timeout

Maximum time (TURN_TIMEOUT_SEC) a player has to submit a move during an online session. If the timer expires, TurnTimerService fires and BotFallbackService plays automatically on the player’s behalf.

Upstream

Nginx configuration directive defining a group of backend servers that can handle requests (e.g., users_backend, gamey_backend)

Users Service

Node.js microservice responsible for managing user profile data. Single point of access to users.db.

WAL (Write-Ahead Logging)

SQLite journaling mode that improves concurrent reads/writes in Users Service storage

Win Checker

Algorithm that detects Y-shaped winning connections on the board to determine game outcome

YBot

Rust trait/interface defining the contract for bot strategy implementations

YEN (Y-Encoded Notation)

Domain-specific format for representing board positions and moves in the Y game, used for inter-service communication between the React Frontend, Game Service, and Game Server

YGN (Y Game Notation)

Alternative notation format supported by the Game Server for recording complete game sequences, used for match replay and history export