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 goal is to provide a smooth and engaging user experience when playing against an Artificial Intelligence (AI), with configurable board sizes and selectable difficulty levels.

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 and statistics), and a Rust-based Game Server (handling game logic). 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

The player accesses the web application in their browser and starts a new game of Y. 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 game.db. 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

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 game.db, 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 auth.db. 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 auth.db, and match data is persisted by the Game Service in game.db.

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.

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 that allows users and bots to play the Y board game. The system provides a platform where human players can compete against each other or against AI bots, with match history and statistics tracking for registered users.

3.1. Business Context

3.1.1. Communication Partners

business context
Partner Input Output

Human Player (Web User)

  • User registration/login credentials

  • Game moves (position=YEN, strategy, difficulty)

  • Match creation requests (size, strategy, difficulty)

  • Statistics/history queries

  • Authentication tokens/sessions

  • Current game state (YEN format)

  • Valid/invalid move responses

  • Match results and statistics

  • Game history data

Bot Client (External/Internal)

  • Bot authentication

  • Game moves via Bot API (position=YEN, strategy, difficulty)

  • Match participation requests

  • Authentication tokens

  • Current game state (YEN format)

  • Move validation responses

  • Match outcomes

Administrator

  • System monitoring requests

  • User management operations

  • Bot registration/configuration

  • System status

  • User data

  • Bot performance metrics

3.1.2. Domain Concepts

  • YEN (Y-encoded Notation): Domain-specific format for representing board positions and moves in the Y game

  • Match: A game session between two players (human or bot)

  • Strategy: Game difficulty level and bot behavior configuration

  • Anonymous Play: Unregistered users can play but their scores are not persisted

3.2. Technical Context

3.2.1. System Architecture

technical context deployment

3.2.2. Technical Interfaces

Component Connection Protocol/Technology Port/Channel Purpose

Web Browser → Nginx (API Gateway)

HTTP, REST API

80 (HTTP)

  • Single public entry point

  • Request routing to backend services

  • CORS handling

  • Rate limiting

  • Static file serving (React frontend)

Nginx → Auth Service

HTTP, REST API

3001 (HTTP)

  • User authentication and registration

  • JWT token generation and validation

  • Credential management

  • Password hashing

Nginx → Users Service

HTTP, REST API

3000 (HTTP)

  • User profile retrieval and updates

  • User search operations

Nginx → Game Service

HTTP, REST API

3002 (HTTP)

  • Match creation and persistence

  • Move history storage

  • Statistics retrieval

Nginx → Game Server

HTTP, REST API

4000 (HTTP)

  • Bot move computation

  • Move validation

  • Win condition checking

  • YEN format game logic

Auth Service → auth.db

SQLite native (embedded)

Local file access

  • Credential CRUD operations

  • JWT token metadata persistence

  • Transaction management

Users Service → users.db

SQLite native (embedded)

Local file access

  • User profile CRUD operations

  • Transaction management

Game Service → game.db

SQLite native (embedded)

Local file access

  • Match state persistence

  • Move history storage

  • Statistics aggregation

React Frontend (in Browser) → Nginx

HTTP, REST API, AJAX

80 (HTTP)

  • API calls to all backend services

  • Game state updates

  • User authentication

  • Statistics queries

3.2.3. Key API Endpoints

Authentication (via Nginx → Auth Service):

  • POST /api/auth/register - User registration

  • POST /api/auth/login - User authentication, returns JWT token

  • POST /api/auth/refresh - JWT token refresh

  • POST /api/auth/verify - JWT verification endpoint for internal service-to-service authorization checks (must not be exposed publicly)

User Profile Management (via Nginx → Users Service):

  • GET /api/users/{id} - Retrieve user profile

  • PUT /api/users/{id} - Update user profile

  • GET /api/users - Search users

Game Data Management (via Nginx → Game Service):

  • POST /api/game/matches - Create new match (size, strategy, difficulty)

  • GET /api/game/matches/{id} - Retrieve match state

  • POST /api/game/matches/{id}/moves - Persist a move and updated YEN state

  • GET /api/game/stats/{userId} - Retrieve player statistics and match history

Game Logic (via Nginx → Game Server):

  • POST /api/gamey/play - Submit player move (position=YEN, strategy, difficulty)

    • Returns: Updated YEN board state, move validation status

  • POST /api/gamey/ybot/choose/{botId} - Bot move computation

    • Returns: YenMoveDto + game status

  • GET /api/gamey/validate - Validate move without executing

Bot API (External bots via Nginx):

  • POST /api/gamey/bot/play - Bot move submission (position=YEN, strategy, difficulty)

3.2.4. Data Formats

YEN Notation Example:

{
  "size": 4,
  "turn": "R",
  "players": ["B", "R"],
  "layout": "B/.B/RB./B..R"
}

Move Request/Response:

{
  "position": "B/.B/RB./B..R",
  "strategy": "heuristic",
  "difficulty": 3,
  "nextMove": {
    "player": "R",
    "coordinate": {"x": 0, "y": 1, "z": 2}
  }
}

3.2.5. Deployment Considerations

  • Containerization: All services (React Frontend, Nginx, Auth Service, Users Service, Game Service, Game Server) are containerized using Docker for consistent deployment

  • Databases: Three independent SQLite files (auth.db, users.db, game.db), each stored as a separate volume mount in its respective service container

  • Fault Isolation: A failure or overload in one database does not affect the others; authentication, profile, and game data are independently available

  • Scalability: Game Server is stateless and can be horizontally scaled behind Nginx load balancer; each Node.js service can also be scaled independently

  • Security: Nginx handles CORS, rate limiting, and request validation; no backend service is directly accessible from outside

  • API Gateway: Nginx isolates all backend services from direct external access

  • Frontend Deployment: React app is built and served as static files through Nginx

4. Solution Strategy

4.1. Overview

This section outlines the fundamental architectural and technological decisions that shape the Yovi system. These decisions were made based on project requirements, quality goals, and technical constraints imposed by the academic context.

4.2. Technology Decisions

4.2.1. Distributed Architecture with Microservices

Decision Rationale

Nginx as API Gateway

  • Security: Single public entry point isolates backend services from direct access

  • Routing: Centralized request routing based on URL paths (/api/auth/, /api/users/, /api/gamey/, /api/game/)

  • Cross-cutting concerns: Handles CORS, rate limiting, and static file serving in one place

  • Performance: Efficient reverse proxy with minimal overhead

  • Simplicity: Easy configuration and widely adopted in production environments

Separate Game Server (Rust)

  • Performance: Rust provides memory safety without garbage collection, ensuring fast execution for game logic and move validation

  • Concurrency: Rust’s ownership model enables safe concurrent processing of multiple game sessions

  • Domain Separation: Isolates core game logic from presentation and user management concerns

  • Requirement: Mandated by project specification to implement game engine in Rust

Auth Service (Node.js + Express + TypeScript)

  • Single Responsibility: Exclusively manages user credentials, authentication, and JWT token lifecycle

  • Fault Isolation: A failure in the credentials database does not affect user profiles or game data

  • Security: Isolates sensitive credential data (password hashes, tokens) in a dedicated database (auth.db)

  • Independent Scalability: Can be scaled independently if authentication load increases

Users Service (Node.js + Express + TypeScript)

  • Single Responsibility: Manages user profile data exclusively (users.db)

  • Fault Isolation: A failure in the profile database does not affect authentication or ongoing games

  • REST API: Express simplifies RESTful API implementation

  • Type Safety: TypeScript prevents runtime errors and improves maintainability

Game Service (Node.js + Express + TypeScript)

  • Single Responsibility: Manages all game-related persistence: matches, moves, and statistics (game.db)

  • Fault Isolation: A heavy load of concurrent matches collapses only the game database, leaving authentication and user profiles unaffected

  • Domain Cohesion: Groups all game data in one service aligned with the game domain

  • Independent Scalability: Can be scaled independently under high game load

Frontend (React + Vite + TypeScript)

  • Component-based UI: React’s declarative approach simplifies game board rendering and state management

  • Fast Development: Vite provides instant hot module replacement (HMR) for rapid iteration

  • Type Safety: TypeScript prevents runtime errors and improves code maintainability

  • SPA Architecture: Single-page application enables smooth user experience without page reloads

  • Client-side coordination: Frontend manages API call orchestration from the browser

Databases (SQLite x3)

  • Fault Isolation: Three independent databases (auth.db, users.db, game.db) ensure that a failure or overload in one does not affect the others

  • Simplicity: Zero-configuration embedded database, no separate server process required

  • Portability: Single file databases simplify deployment and backup per service

  • Performance: Excellent read performance for each domain’s specific workload

  • Write-Ahead Logging (WAL): Enables concurrent reads during writes, sufficient for academic project scale

4.3. Architectural Patterns

4.3.1. Microservices Architecture

solution architecture

The system follows a microservices architecture where:

  • Nginx acts as the API Gateway, providing a single entry point and routing requests to appropriate services

  • React Frontend runs in the user’s browser and coordinates API calls to backend services

  • Auth Service is exclusively responsible for authentication, registration, and JWT management, backed by auth.db

  • Users Service manages user profile data, backed by users.db

  • Game Service manages all game-related persistence (matches, moves, statistics), backed by game.db

  • Game Server remains stateless and focuses solely on game domain logic

  • YEN notation defines the boundaries between services for game state communication

  • Each service owns its own database, ensuring fault isolation: a failure or overload in one database does not propagate to the others

4.3.2. Layered Architecture within Services

layered architecture

React Frontend Layers:

  • Components: React UI components for board, moves, statistics

  • State Management: Local game state and user session (React hooks/context)

  • API Layer: Abstraction over backend API calls

  • HTTP Client: Fetch/Axios for making HTTP requests to Nginx

Auth Service Layers:

  • AuthController: Handles HTTP requests for registration and login

  • AuthService: Business logic for password hashing and JWT management

  • CredentialsRepository: Abstracts access to auth.db

Users Service Layers:

  • UsersController: Handles HTTP requests for user profile operations

  • UserService: Business logic for user profile management

  • UserRepository: Abstracts access to users.db

Game Service Layers:

  • GameController: Handles HTTP requests for match and stats operations

  • MatchService: Business logic for match creation, move persistence, and lifecycle

  • StatsService: Aggregates and retrieves player statistics

  • MatchRepository / StatsRepository: Abstract access to game.db

Game Server Design:

  • Domain-Driven Design: Game, Board, Player, Move as core entities

  • Strategy Pattern: Multiple bot strategies with configurable difficulty levels

  • Encapsulation: Pure domain logic with no external dependencies

4.4. Quality Goals Achievement

Quality Goal Strategy Implementation

Performance

  • Rust for compute-intensive game logic

  • SQLite for fast read operations per service

  • Stateless game server for horizontal scaling

  • Nginx for efficient request routing

  • Move validation in O(n) time

  • Indexed database queries per domain

  • Concurrent request handling in Rust

  • Nginx caching for static files

Scalability

  • Stateless services enable horizontal scaling

  • Each database optimized for its own workload

  • Nginx can load balance multiple instances per service

  • Multiple game server instances possible

  • Independent service and database scaling

  • Caching strategies for frequent queries

  • Each service scales according to its own load

Maintainability

  • Clear separation of concerns across services and databases

  • Type safety (TypeScript + Rust)

  • Each service owns its data domain

  • Layered architecture in each service

  • Repository pattern for DB abstraction per service

  • API documentation

  • Shared YEN notation contracts

Interoperability

  • REST API with JSON

  • Standardized YEN notation

  • External bot API support

  • HTTP-based communication

  • Versioned API endpoints

  • Cross-team bot competition support

  • Well-defined API contracts

Security

  • Nginx isolates backend services

  • Rate limiting and CORS at gateway level

  • Authentication isolated in Auth Service

  • Credential data separated from profile and game data

  • JWT token-based authentication (Auth Service)

  • Password hashing (bcrypt/Argon2)

  • No direct backend access

  • Input validation at API boundaries

  • auth.db isolated from users.db and game.db

4.5. Key Constraints

Constraint Impact on Architecture

Mandated Technologies

TypeScript for frontend/backend and Rust for game engine are project requirements, limiting technology choices

YEN Notation

All game state communication must use YEN format, requiring parsing/serialization layers

Bot API Requirement

System must expose external API for bot clients, influencing authentication and API design

Academic Timeline

Limited development time favors familiar technologies (React, Express) and simple deployment (SQLite)

Web Deployment

Application must be publicly accessible, requiring containerization and reverse proxy strategy

Multiple Strategies

Game engine must support extensible bot strategies, leading to Strategy pattern adoption

Database Fault Isolation

Three independent databases (auth.db, users.db, game.db) ensure that overload or failure in one domain does not affect the others

4.6. Organizational Decisions

  • Monorepo structure: All services in one repository (webapp/, users/, auth/, gamey/, gameservice/, nginx/) for easier coordination

  • Docker Compose: Simplified local development with single command startup

  • Shared YEN notation: Common understanding of game state format across all services

  • API-first approach: Define API contracts before implementation

  • Version control: Git with feature branch workflow and code reviews

  • Documentation: arc42 for architecture, inline code documentation, README files per service

5. Building Block View

5.1. Whitebox Overall System

5.1.1. Overview Diagram

level1 overview

Motivation:

The Yovi system is decomposed into five main subsystems to achieve separation of concerns, independent scalability, technology-specific optimization, and fault isolation across data domains:

  • Nginx (API Gateway): Single public entry point for all requests, handling routing, rate limiting, and CORS

  • React Frontend (Webapp): User interface layer running in the browser, managing UI state and coordinating API calls to backend services

  • Auth Service: Authentication layer with exclusive access to auth.db, managing credentials, registration, login, and JWT tokens

  • Users Service: Profile layer with exclusive access to users.db, managing user profile data

  • Game Service: Game data layer with exclusive access to game.db, managing match persistence, move history, and statistics

  • Game Server: Pure game logic engine optimized for performance (Rust), completely stateless

Each service owns its own database. A failure or overload in one database does not propagate to the others, achieving fault isolation at the data layer.

Contained Building Blocks:

Building Block Responsibility

Nginx (API Gateway)

  • Single public entry point on port 80

  • Routes requests based on URL paths:

    • /api/auth/* → Auth Service (port 3001)

    • /api/users/* → Users Service (port 3000)

    • /api/game/* → Game Service (port 3002)

    • /api/gamey/* → Game Server (port 4000)

    • /* → React Frontend static files

  • Handles CORS and rate limiting

  • Serves React frontend static files

  • Isolates backend services from direct external access

React Frontend (Webapp)

  • Single-page application (SPA) running in user’s browser

  • Renders game board and UI components using React

  • Handles user interactions (login, game moves, statistics viewing)

  • Manages client-side state (game state, user session)

  • Makes HTTP API calls to all backend services through Nginx

  • Coordinates game flow from the client side

Auth Service

  • Single point of access to auth.db

  • Manages user registration and login

  • Password hashing (bcrypt/Argon2)

  • JWT token generation and validation

  • Token refresh logic

  • Exposes REST API on port 3001 (internal)

Users Service

  • Single point of access to users.db

  • Manages user profile data (username, avatar, preferences)

  • Handles user CRUD operations

  • Provides user search and retrieval

  • Exposes REST API on port 3000 (internal)

Game Service

  • Single point of access to game.db

  • Manages match lifecycle (creation, updates, completion)

  • Persists move history and serialized YEN board states

  • Aggregates and provides player statistics and rankings

  • Exposes REST API on port 3002 (internal)

Game Server (Rust)

  • Implements core Y game rules and logic

  • Validates moves and checks win conditions

  • Computes bot moves using various strategies (random, heuristic)

  • Completely stateless service using YEN notation

  • Exposes REST API on port 4000 (internal)

  • No database access, pure computation

auth.db (SQLite)

  • Stores user credentials (hashed passwords)

  • Persists JWT token metadata and refresh tokens

  • Accessible only through Auth Service

  • Isolated from profile and game data

users.db (SQLite)

  • Stores user profile information (username, avatar, preferences)

  • Accessible only through Users Service

  • Isolated from credentials and game data

game.db (SQLite)

  • Stores match records and metadata (size, strategy, difficulty, status)

  • Persists move history and serialized YEN board states

  • Maintains player statistics and rankings

  • Accessible only through Game Service

  • Isolated from credentials and profile data

Important Interfaces:

  • User → Nginx: HTTP REST API (port 80, public)

  • Nginx → React Frontend: Static file serving (HTML, JS, CSS)

  • Nginx → Auth Service: REST API (/api/auth/*, port 3001, internal)

  • Nginx → Users Service: REST API (/api/users/*, port 3000, internal)

  • Nginx → Game Service: REST API (/api/game/*, port 3002, internal)

  • Nginx → Game Server: REST API (/api/gamey/*, port 4000, internal)

  • React Frontend → Nginx: AJAX/Fetch API calls from browser

  • Auth Service → auth.db: SQLite native SQL queries

  • Users Service → users.db: SQLite native SQL queries

  • Game Service → game.db: SQLite native SQL queries

Communication Flow Example:

  1. User loads the app → Nginx serves React static files → React runs in browser

  2. User clicks "Login" → React calls POST /api/auth/login → Nginx routes to Auth Service

  3. Auth Service validates credentials against auth.db → Returns JWT token

  4. User creates a match → React calls POST /api/game/matches → Nginx routes to Game Service → persisted in game.db

  5. User makes a move → React calls POST /api/gamey/play → Nginx routes to Game Server → returns updated YEN

  6. Game Server returns move validation → React calls POST /api/game/matches/{id}/moves → Game Service persists in game.db

  7. React updates UI

5.2. Level 2

5.2.1. White Box: Auth Service

level2 auth

Contained Building Blocks:

Component Responsibility

AuthController

  • Exposes REST API endpoints: POST /api/auth/register, POST /api/auth/login, POST /api/auth/refresh

  • Input validation and error handling

  • Request/response mapping

AuthService

  • User registration logic

  • Password hashing and verification (bcrypt/Argon2)

  • JWT token generation and validation

  • Token refresh logic

CredentialsRepository

  • Database access layer for auth.db

  • SQL query execution and result mapping

  • Stores hashed passwords and token metadata

5.2.2. White Box: Users Service

level2 users

Contained Building Blocks:

Component Responsibility

UsersController

  • Exposes REST API endpoints: GET /api/users/{id}, PUT /api/users/{id}, GET /api/users

  • Input validation and authentication middleware (JWT verification via Auth Service)

  • Request/response mapping

UserService

  • CRUD operations for user profiles

  • User search and retrieval

  • Profile validation logic

UserRepository

  • Database access layer for users.db

  • SQL query execution and result mapping

  • Transaction management for profile operations

5.2.3. White Box: Game Service

level2 gameservice

Contained Building Blocks:

Component Responsibility

GameController

  • Exposes REST API endpoints for match and stats operations

  • Endpoints: POST /api/game/matches, GET /api/game/matches/{id}, POST /api/game/matches/{id}/moves, GET /api/game/stats/{userId}

  • Input validation and authentication middleware (JWT verification)

  • Request/response mapping

MatchService

  • Match creation and lifecycle management

  • Stores match metadata (size, strategy, difficulty, participants)

  • Updates match status (ongoing/finished)

  • Persists serialized YEN board states and move history

  • Match history queries

StatsService

  • Aggregates player statistics (wins/losses/draws)

  • Calculates rankings and metrics

  • Provides historical match data

  • Win rate calculations

MatchRepository

  • Database access layer for matches in game.db

  • Stores serialized YEN board states

  • Query optimization for match history

  • Match outcome persistence

StatsRepository

  • Database access layer for statistics in game.db

  • Optimized read queries for rankings

  • Computed statistics and performance metrics

5.2.4. White Box: Game Server

level2 gameserver

Motivation:

The Game Server encapsulates all game-specific logic using Domain-Driven Design principles. The Strategy pattern allows for extensible bot implementations without modifying core game logic. This service is completely stateless and has no database dependencies. All persistence is delegated to the Game Service.

Contained Building Blocks:

Component Responsibility

EngineService

  • REST API entry point (POST /api/gamey/play, POST /api/gamey/ybot/choose/{botId})

  • Parses YEN notation from requests

  • Delegates to NextMoveComputer or WinEvaluator

  • Returns YenMoveDto responses

  • Stateless request handling

NextMoveComputer

  • Computes next optimal move for a given bot strategy

  • Selects appropriate Strategy implementation based on botId/difficulty

  • Returns valid move in YEN notation

  • No side effects, pure computation

WinEvaluator

  • Checks if game has ended (win condition met)

  • Analyzes board for Y-connections (3-sided paths)

  • Returns game status (ongoing/won/draw)

  • Deterministic evaluation

Strategy Interface

  • Defines contract for bot implementations

  • compute_move(board: &Board, difficulty: u8) → Move

  • Enables extensibility for new strategies

RandomStrategy

  • Implements random valid move selection

  • Low difficulty, fast execution

  • Used for testing and beginner difficulty

  • No lookahead or evaluation

HeuristicStrategy

  • Implements heuristic-based move evaluation

  • Considers board control, connection potential, blocking opponent

  • Configurable difficulty levels affect search depth

  • Position evaluation function

GameDomain Package

  • Game: Aggregates board, players, move history, game state

  • Board: Hexagonal grid representation using barycentric coordinates

  • Move: Represents player action (position + player)

  • Player: Entity representing B or R player

  • Coordinate: Barycentric coordinate (x, y, z)

  • WinChecker: Algorithm to detect Y-shaped winning connections

6. Runtime View

This section describes how the main components of the YOVI system collaborate at runtime to support user authentication, match management, gameplay, bot interaction, and statistics retrieval. The scenarios below are derived directly from the system’s architecture and message flows, using JSON/YEN as the canonical representation of game states.

All communication between the React Frontend (running in the user’s browser) and backend services goes through the Nginx API Gateway, which routes requests to the appropriate service based on URL paths.

6.1. Runtime Scenario 1: User Registration and Login

This scenario shows how a human user registers or logs into the system through the React Frontend. The frontend makes API calls through Nginx, which routes authentication requests to the Auth Service, which persists credential data in auth.db.

runtime login

Notable Aspects:

  • Authentication is fully isolated in the Auth Service and its dedicated auth.db

  • Nginx routes all /api/auth/* requests to Auth Service (port 3001)

  • React Frontend stores the JWT token (localStorage or sessionStorage)

  • auth.db acts as the single source of truth for credentials

  • A failure in other databases (users.db, game.db) does not affect the login flow

6.2. Runtime Scenario 2: Authorization Check

When a user requests protected resources, the React Frontend includes the JWT token in the request headers. Nginx forwards the request to the appropriate service, which delegates JWT verification to Auth Service through an internal call to /api/auth/verify.

runtime auth check

Notable Aspects:

  • JWT validation is responsibility of the Auth Service

  • Other services (Game Service, Users Service) delegate token verification to Auth Service via internal call

  • React Frontend handles unauthorized responses by redirecting to login

  • Nginx simply routes requests without authentication logic

Verify endpoint contract used by internal services:

  • Method and path: POST /api/auth/verify

  • Internal URL (Docker network): AUTH_INTERNAL_VERIFY_URL=http://auth:3001/api/auth/verify

  • Token input: preferred Authorization: Bearer <accessToken> (compatible fallback: JSON body { "token": "<accessToken>" })

  • Success response (200): { "valid": true, "claims": { "sub": "<userId>", "username": "<username>", "tokenType": "access", "iat": <epoch>, "exp": <epoch> } }

  • Error response (401): { "valid": false } for missing, malformed, invalid, expired, or non-access tokens

  • Security boundary: /api/auth/verify must not be exposed publicly through Nginx and should be consumed only over internal service-to-service network calls

  • Client resilience policy for internal callers: use short timeouts (500ms to 1s) and 0-1 retries to avoid cascading failures

6.3. Runtime Scenario 3: Match Creation and Initial State Retrieval

A user creates a new match by specifying board size, strategy, and difficulty through the React UI. The Game Service persists the match in game.db and returns the initial YEN state.

runtime create match

Notable Aspects:

  • The Game Service owns match lifecycle and persistence in game.db

  • Initial game state is always stored and returned in YEN format

  • React Frontend renders the game board based on received YEN notation

  • Match creation requires authentication (JWT token verified against Auth Service)

  • auth.db and users.db are not involved in this flow

6.4. Runtime Scenario 4: Player Move (Human Turn)

The human player submits a move by clicking on the game board in React. The frontend sends the current game state to the Game Server for bot move computation, then persists the updated state in the Game Service.

runtime human move

Notable Aspects:

  • React Frontend coordinates the multi-step flow from the browser

  • Game Server (Rust) is stateless and only computes moves based on YEN input, with no DB access

  • Game Service is the authoritative source of match state persistence in game.db

  • All updates are persisted atomically in game.db

  • auth.db and users.db are not involved in this flow

6.5. Runtime Scenario 5: Bot API Interaction

External bots can play matches programmatically using the API. The flow mirrors the human move scenario but uses bot credentials for authentication against the Auth Service.

runtime bot api

Notable Aspects:

  • Bot authentication is handled exclusively by Auth Service against auth.db

  • Game data (match state, moves) is managed exclusively by Game Service against game.db

  • External bots must follow the same YEN notation format as human players

  • A failure in users.db does not affect bot gameplay

6.6. Runtime Scenario 6: Statistics and History Retrieval

Users can request aggregated statistics such as number of matches, wins/losses, and performance metrics through the React UI. Statistics are served by the Game Service from game.db.

runtime stats

Notable Aspects:

  • Statistics are computed from persisted match data in game.db

  • The Game Service exposes a unified Stats API

  • React Frontend handles visualization (charts, tables)

  • All stats queries require authentication (JWT verified against Auth Service)

  • auth.db and users.db are not involved in this flow

7. Deployment View

The deployment view describes the technical infrastructure we use to run the Yovi system. It also shows how the software parts (building blocks) connect to that infrastructure.

Because our system uses Docker containers, we describe the deployment in two main environments: the Production Environment and the Development Environment.

7.1. Infrastructure Level 1 - Production Environment

This section describes the main production environment where the final users can access the system.

Overview Diagram

deployment level1 architecture

Motivation

The main goal of this deployment strategy is to find a good balance between working fast and keeping the system secure. Software needs hardware to run. By using a Virtual Machine (VM) as the main host, the system creates a secure border at the hardware level. Inside this VM, we use Docker containers to run the apps. This makes sure that the deployment is isolated and prevents problems with installed programs on the host machine.

Quality and/or Performance Features

  • Security (Defense in Depth): The infrastructure has two layers of isolation. If a container is attacked, the VM acts as an external wall that protects the physical server. Also, the Nginx API Gateway is the only part connected to the public internet.

  • Portability: By using Docker containers, the environment is always the same. The application works exactly the same way, no matter what physical server is running the Virtual Machine.

  • Independent Scalability: The system is divided into specific microservices (React Frontend, Auth Service, Users Service, Game Service, Game Server). Because of this, developers can give more resources to a specific service without affecting the others.

  • Fault Isolation: Each service owns its own database volume. An overload or failure in game.db does not affect auth.db or users.db, meaning authentication and profile access remain available even if the game data layer is under stress.

Mapping of Building Blocks to Infrastructure

Software Artifact (Building Block) Infrastructure Element

React Frontend (Webapp)

Deployed as static files (HTML, CSS, JS bundle) served by Nginx on port 80. The React application runs entirely in the user’s browser. Built with Vite and bundled for production.

Nginx (API Gateway)

Deployed in a Docker container inside the VM. It works as a Reverse Proxy and API Gateway. It is the only public entry point (Port 80) to route all incoming traffic. Handles CORS, rate limiting, and serves the React frontend static files. Routes API requests to backend services.

Auth Service (Node.js + Express + TypeScript)

Deployed in a Docker container inside the VM (Port 3001, internal only). Exclusively manages user credentials, registration, authentication, and JWT token lifecycle. No other service has access to auth.db.

Users Service (Node.js + Express + TypeScript)

Deployed in a Docker container inside the VM (Port 3000, internal only). Exclusively manages user profile data. No other service has access to users.db.

Game Service (Node.js + Express + TypeScript)

Deployed in a Docker container inside the VM (Port 3002, internal only). Exclusively manages match persistence, move history, and player statistics. No other service has access to game.db.

Game Server (Rust)

Deployed in a Docker container inside the VM (Port 4000, internal only). Calculates game logic and bot movements in YEN format. Completely stateless service optimized for performance. No database access whatsoever.

auth.db (SQLite)

A database file saved on a dedicated Host Volume inside the VM, connected exclusively to the Auth Service container. Stores user credentials and JWT token metadata. Only Auth Service has read/write permissions.

users.db (SQLite)

A database file saved on a dedicated Host Volume inside the VM, connected exclusively to the Users Service container. Stores user profile data. Only Users Service has read/write permissions.

game.db (SQLite)

A database file saved on a dedicated Host Volume inside the VM, connected exclusively to the Game Service container. Stores matches, move history, and statistics. Only Game Service has read/write permissions.

7.2. Infrastructure Level 1 - Development Environment

Following the arc42 rules for multiple environments, the development environment uses the same Docker containers to be equal to production, but without the secure Virtual Machine.

Motivation

Developers need a fast and reliable environment to write and test code on their computers. We use Docker Compose to start the whole system on the developer’s local machine.

Quality and/or Performance Features

  • Consistency: It solves the classic "it works on my machine" problem.

  • Fast Setup: A new developer can start the complete system (React Frontend, Nginx, Auth Service, Users Service, Game Service, Game Server, and all three databases) with just one docker-compose up command.

Mapping of Building Blocks to Infrastructure

In this environment, the mapping is exactly the same as in Production. The only difference is the host hardware: * Infrastructure Element: The developer’s personal computer (Localhost) running Docker Desktop, instead of a Cloud Virtual Machine.

7.3. Infrastructure Level 2

Here we explain the internal structure of the Docker environment from Level 1. We zoom into the isolated network and how data is saved.

deployment level2 dataflow

Internal Structure Explanation:

This level shows the internal Docker network rules. The Nginx API Gateway completely isolates the microservices from the public internet. External users can never reach the backend services directly. All requests must go through Nginx on port 80.

The request flow is as follows:

  • User browser loads the app: Nginx serves React static files (HTML, CSS, JS)

  • React app runs in browser: Makes API calls to /api/auth/, /api/users/, /api/game/ and /api/gamey/

  • Nginx routes API requests based on URL path:

    • /api/auth/* → Auth Service (port 3001), except /api/auth/verify (blocked externally with 403)

    • /api/users/* → Users Service (port 3000)

    • /api/game/* → Game Service (port 3002)

    • /api/gamey/* → Game Server (port 4000)

    • /* (all other paths) → React frontend static files

Example User Flow:

  1. User opens http://yourapp.com in browser

  2. Nginx serves index.html and React bundle from static files

  3. React app loads in browser, displays login screen

  4. User clicks "Login" → React sends POST /api/auth/login to Nginx

  5. Nginx routes request to Auth Service (port 3001)

  6. Auth Service validates credentials against auth.db and returns JWT token

  7. React stores token and creates a new match → React sends POST /api/game/matches to Nginx

  8. Nginx routes request to Game Service (port 3002)

  9. Game Service persists the new match in game.db and returns the match ID

  10. User makes a move → React sends POST /api/gamey/play to Nginx

  11. Nginx routes game logic request to Game Server (port 4000)

  12. Game Server computes the bot move and returns the updated YEN state

  13. React persists the move → sends POST /api/game/matches/{id}/moves to Nginx

  14. Nginx routes to Game Service (port 3002), which stores the move in game.db

  15. React updates the UI with the new board state

Internal Auth verification call (service-to-service only):

  • Internal URL env var: AUTH_INTERNAL_VERIFY_URL=http://auth:3001/api/auth/verify

  • Recommended timeout in callers: 500ms to 1s

  • Recommended retries: 0-1 (avoid retry storms)

Data Storage and Fault Isolation:

Data storage is strictly controlled through three independent volumes, all inside the VM:

  • auth.db is mounted exclusively inside the Auth Service container. Only Auth Service has read/write permissions. Stores credentials and JWT metadata.

  • users.db is mounted exclusively inside the Users Service container. Only Users Service has read/write permissions. Stores user profile data.

  • game.db is mounted exclusively inside the Game Service container. Only Game Service has read/write permissions. Stores matches, moves, and statistics.

If game.db becomes overloaded due to a high volume of concurrent matches, authentication (auth.db) and user profiles (users.db) remain fully operational. Each database fails independently.

The Game Server has no database access and operates in a completely stateless manner. All game state persistence is delegated to the Game Service after each move.

Network Isolation:

All backend services (Auth Service, Users Service, Game Service, Game Server) run on an internal Docker network. They cannot be accessed directly from outside the VM. Only Nginx has a public-facing port (80) exposed to the internet. This architecture ensures that:

  • Backend services are protected from direct attacks

  • All requests go through Nginx security layers (rate limiting, CORS)

  • Each database is isolated behind its own service container

  • Services communicate only through defined internal APIs

8. Cross-cutting Concepts

Content

This section describes overall, principal regulations and solution ideas that are relevant in multiple parts (= cross-cutting) of your system. Such concepts are often related to multiple building blocks. They can include many different topics, such as

  • models, especially domain models

  • architecture or design patterns

  • rules for using specific technology

  • principal, often technical decisions of an overarching (= cross-cutting) nature

  • implementation rules

Motivation

Concepts form the basis for conceptual integrity (consistency, homogeneity) of the architecture. Thus, they are an important contribution to achieve inner qualities of your system.

Some of these concepts cannot be assigned to individual building blocks, e.g. security or safety.

Form

The form can be varied:

  • concept papers with any kind of structure

  • cross-cutting model excerpts or scenarios using notations of the architecture views

  • sample implementations, especially for technical concepts

  • reference to typical usage of standard frameworks (e.g. using Hibernate for object/relational mapping)

Structure

A potential (but not mandatory) structure for this section could be:

  • Domain concepts

  • User Experience concepts (UX)

  • Safety and security concepts

  • Architecture and design patterns

  • "Under-the-hood"

  • development concepts

  • operational concepts

Note: it might be difficult to assign individual concepts to one specific topic on this list.

Possible topics for crosscutting concepts
Further Information

See Concepts in the arc42 documentation.

8.1. Domain Model

A first version of the domain model of the application, representing all the entities that interact with the application and their relations, is shown in the following diagram:

domain model

8.2. User experience (UX)

Since the project includes a web interface, we wanted the user experience to be as smooth and intuitive as possible. The idea is that anyone can open the application and start playing without needing instructions.

Key UX ideas:

  • Visual Feedback: The interface reacts immediately to user actions (valid moves, turn changes, errors). This helps players understand what is happening in the game at all times.

  • Consistency: We try to keep the same style and interaction patterns across all pages so the user does not have to "relearn" how to use the app.

  • Accessibility: Clear colors, readable text, and simple layouts help make the game accessible to a wider audience.

8.3. Safety and Security Concepts

Security is a cross‑cutting concern because it affects both the backend services and the frontend. Even though this is an academic project, we still apply basic security principles.

  • API Gateway Isolation: Nginx acts as the single public entry point, isolating backend services from direct external access. Only Nginx is exposed on port 80, while Users Service and Game Server run on internal Docker network ports.

  • Authentication and Authorization: Only authenticated users can access certain features, such as creating matches or viewing their profile. The Auth Service handles JWT authentication and exposes token verification for internal service-to-service authorization checks.

  • Password Protection: Passwords are never stored in plain text. Instead, they are hashed and salted before being saved in the database using bcrypt or Argon2.

  • Data Protection: We only store the minimum amount of user information needed for the system to work. Data is split by domain with strict ownership: auth.db is accessible only through Auth Service, users.db only through Users Service, and game.db only through Game Service.

  • CORS and Rate Limiting: Nginx handles Cross-Origin Resource Sharing (CORS) headers and rate limiting to prevent abuse and ensure legitimate API usage.

8.4. Architecture and Design Patterns

The system follows a microservice-based architecture. Instead of having one big monolithic application, we split the project into several smaller, independent services:

  • React Frontend (webapp/): The user interface running in the browser. It is a single-page application (SPA) built with React, Vite, and TypeScript. The frontend manages UI state and coordinates API calls to backend services.

  • Nginx: The API Gateway and reverse proxy that routes requests to appropriate backend services. It handles CORS, rate limiting, and serves the React frontend static files.

  • Auth Service (auth/): Node.js + Express + TypeScript service that manages registration, authentication (JWT access/refresh lifecycle), and internal token verification. It is the single point of access to auth.db.

  • Users Service (users/): Node.js + Express + TypeScript service that manages user profiles, match persistence, and statistics. It is the single point of access to users.db.

  • Game Server (gamey/): Rust service that implements the Y‑game engine and bot logic. It is stateless and focuses purely on game rules, move validation, and bot strategies.

Some patterns we use:

API Gateway Pattern: Nginx centralizes all external requests and routes them to the appropriate service based on URL paths (/api/users/, /api/gamey/, /).

Repository Pattern: The Users Service uses the Repository pattern to abstract database access, making it easier to test and maintain.

Strategy Pattern: The Game Server uses the Strategy pattern to implement multiple bot difficulty levels (random, heuristic) in an extensible way.

Separation of Concerns: The frontend separates UI components, state management (React hooks/context), and API call logic into distinct layers.

8.5. Development Concepts

These concepts describe the practices that the whole team follows during development.

Version Control:

The project is developed collaboratively using GitHub. Branching, pull requests and code reviews ensure that all components evolve consistently.

Testing:

Each part of the system includes automated tests:

  • Rust Game Server: unit tests for game logic and strategies

  • Users Service (Node.js): API endpoint tests and integration tests

  • React Frontend: component tests and end-to-end tests

Testing is transversal because it guarantees correctness across all services.

Continuous Integration:

GitHub Actions automatically run builds and tests whenever code is pushed. This helps detect errors early and keeps all services aligned.

8.6. Persistence Layer

The application relies on SQL databases (SQLite - relational database) split by domain: auth.db, users.db, and game.db.

Each database is accessed exclusively by its owning service. This design decision ensures:

  • Data Consistency: each service manages transactions in its own domain

  • Security: other services cannot directly access or modify another service’s database

  • Separation of Concerns: Auth handles credentials/tokens, Users handles profiles/statistics, and Game handles match state

Game sessions are computed in memory by the Rust Game Server and persisted to game.db when needed (history/resume). Credentials and token metadata remain exclusive to Auth Service in auth.db.

If additional persistence requirements arise in the future (for example, caching or match replay functionality), the system can be extended without affecting the existing services thanks to the microservice-based design.

8.7. Error Handling

The application includes a consistent error handling strategy to deal with the different types of errors that may appear during execution. The goal is to detect problems early, avoid unexpected crashes and provide clear feedback both to developers and to users.

At the user level, the application only displays simple and understandable messages, without exposing technical details. This prevents confusion and avoids leaking internal information. On the other hand, the backend services and the Rust game engine generate structured error messages and log them internally so developers can identify the cause of the problem more easily.

Error Handling Across Services:

  • React Frontend: Displays user-friendly error messages for API failures, invalid moves, or authentication errors. Uses try-catch blocks and error boundaries for React component errors.

  • Nginx: Returns standard HTTP error codes (400, 401, 404, 500) and logs errors for monitoring.

  • Users Service: Validates input, handles database errors, and returns appropriate HTTP status codes with error messages. Uses middleware for centralized error handling.

  • Game Server: Returns structured error responses for invalid YEN notation, illegal moves, or computation failures. Rust’s Result type ensures explicit error handling.

9. Architecture Decisions

9.1. ADR 1: Microservices architecture

  • Context: The platform is expected to scale with increasing user demand, evolve over time with new features or game modes, and support parallel development by multiple team members. High availability and maintainability are important non-functional requirements.

  • Status: Accepted by the teacher and development team.

  • Possible alternatives:

    • Monolithic architecture: where all game logic, API web and data storage services would be integrated in a single backend app. Although it would have simplified the development at first, this solution presents big issues in terms of scalability and maintainability.

  • Decision: We decided to implement a microservice-based architecture with a clear separation between game logic, data persistence, and presentation layers. The system will consist of:

    • Game Server (Rust) handling core game rules, move validation, and bot strategies

    • Auth Service (Node.js + Express + TypeScript) managing user authentication, registration, and JWT token lifecycle, with exclusive access to auth.db

    • Users Service (Node.js + Express + TypeScript) managing user profile data, with exclusive access to users.db

    • Game Service (Node.js + Express + TypeScript) managing match persistence, move history, and statistics, with exclusive access to game.db

    • React Frontend (Vite + TypeScript) for user interaction, running entirely in the browser and coordinating API calls to backend services

    • Nginx API Gateway routing requests and handling cross-cutting concerns (CORS, rate limiting, security)

    • Each service owns its own database, ensuring fault isolation at the data layer
      This approach allows each component to evolve independently while using the most appropriate technology for its responsibilities.

  • Pros:

    • Clear separation of concerns between game logic, data persistence, and user interface

    • Enables independent development and deployment of all services

    • Each database is isolated per domain, ensuring fault isolation

    • Nginx provides security isolation for backend services

  • Cons:

    • Increased architectural complexity compared to a single monolithic backend

    • Introduces inter-service communication overhead and potential latency

    • Frontend must coordinate multiple API calls for complex workflows

9.2. ADR 2: Rust for Game Server

  • Context: The game server must be performant, safe, and reliable, as errors in the game logic could compromise fairness or stability. Additionally, the engine may need to handle multiple concurrent games and interact efficiently with other services in the system.

  • Status: Accepted by the teacher and development team.

  • Possible alternatives:

    • There were no possible alternatives because this was an imposed constraint, given by the course’s teachers.

  • Decision: We decided to implement the Game Server using Rust, which provides strong compile-time guarantees for memory safety and concurrency without relying on a garbage collector. This makes it well-suited for implementing complex game logic that must be both efficient and robust. The Game Server will be completely stateless, with no database access. All persistence is delegated to the Game Service.

  • Pros:

    • Strong memory safety guarantees, reducing runtime errors and crashes

    • High performance and excellent support for concurrency, which is important for managing game sessions in parallel

    • Stateless design enables horizontal scaling

  • Cons:

    • Steeper learning curve, as the development team is not familiar with this programming language

9.3. ADR 3: Docker Containerization

  • Context: The platform is composed of multiple independent components implemented with different technologies and runtimes. A way to ensure consistent development, testing, and deployment across different environments is essential to reduce configuration issues and simplify setup for new team members.

  • Status: Accepted by the teacher and development team.

  • Possible alternatives:

    • There were no possible alternatives because this was an imposed constraint, given by the course’s teachers.

  • Decision: We decided to containerize all major components of the system using Docker. Each service (React Frontend, Nginx, Auth Service, Users Service, Game Service, Game Server) will run inside its own Docker container, with Docker Compose used to orchestrate and manage the multi-container setup. This ensures environment consistency and simplifies deployment and execution of the full system.

  • Pros:

    • Provides consistent environments across development, testing, and deployment

    • Simplifies setup and onboarding by reducing manual configuration

    • Enables easier deployment and scaling of individual services

    • Isolated network for backend services through Docker networking

    • Each database file is mounted as an independent volume per service container

  • Cons:

    • Adds an extra layer of complexity to the development workflow

    • Requires basic knowledge of Docker and container orchestration from the development team

9.4. ADR 4: SQLite as Database System

  • Context: The application requires persistent storage for game data, user information, and match states. The database solution should be simple to operate, easy to integrate with the existing backend services, and appropriate for an academic project deployed in a cloud environment.

  • Status: Proposed by the development team.

  • Possible alternatives:

    • MongoDB: A document-oriented NoSQL database was considered. It would allow the development team to store game states in a more flexible way, using JSON structures. This alternative was not adopted as the development team was not familiar with this kind of DBs when the decision was taken.

  • Decision: We decided to use SQLite as the database system for all three data domains. Each service owns its own SQLite database file (auth.db, users.db, game.db), mounted as an independent Docker volume. No service has access to another service’s database. This choice is also highly based on the development team’s experience using relational databases.

  • Pros:

    • Easy integration with backend services and containerized environments

    • Suitable for small-to-medium workloads

    • Low learning curve, as the development team is used to working with relational databases

    • Each service owns its own database file, enforcing data isolation

    • Embedded database requires no separate server process

  • Cons:

    • Limited scalability and concurrency support compared to cloud-native database solutions

    • Not ideal for high-availability or horizontally scaled write-heavy workloads

9.5. ADR 5: Nginx as API Gateway

  • Context: The system requires a secure entry point for all external requests. Backend services (Auth Service, Users Service, Game Service, and Game Server) should not be directly accessible from the internet. Additionally, cross-cutting concerns such as CORS, rate limiting, and request routing need to be handled consistently.

  • Status: Proposed by the development team.

  • Possible alternatives:

    • Direct access to backend services: Each service could expose its own public port, but this would increase security risks and make it harder to manage cross-cutting concerns.

    • Cloud API Gateway services (AWS API Gateway, Azure API Management): These would provide more features but add complexity and cost for an academic project.

  • Decision: We decided to use Nginx as a reverse proxy and API Gateway. Nginx will be the only component with a publicly exposed port (80). It will route requests based on URL paths:

    • /api/auth/* → Auth Service (port 3001, internal)

    • /api/users/* → Users Service (port 3000, internal)

    • /api/game/* → Game Service (port 3002, internal)

    • /api/gamey/* → Game Server (port 4000, internal)

    • /* → React Frontend static files Nginx will also handle CORS headers, rate limiting, and request logging.

  • Pros:

    • Single public entry point enhances security (defense in depth)

    • Backend services are isolated on internal Docker network

    • Centralized handling of CORS, rate limiting, and logging

    • High performance and battle-tested in production environments

    • Simple configuration and widely known by the development community

  • Cons:

    • Adds an additional component to the system architecture

    • Requires learning Nginx configuration syntax

    • Single point of failure (mitigated by its reliability)

9.6. ADR 6: Three Independent Databases for Fault Isolation

  • Context: The initial architecture used a single SQLite database accessed exclusively by the Users Service. As the system evolved and the number of concurrent users and game sessions grew, a concern arose: a single overloaded or failed database would bring down all data-dependent functionality simultaneously — authentication, user profiles, and game data would all fail together.

  • Status: Accepted by the teacher and development team.

  • Possible alternatives:

    • Single database: One SQLite file accessed by one service. Simple but creates a single point of failure at the data layer. If the database is locked or overloaded (e.g., by a high volume of match writes), authentication also fails.

    • Single service with multiple internal connections: A single backend service managing three internal database connections. This keeps one entry point but does not achieve true fault isolation at the service level — if the service crashes, all three databases become inaccessible anyway.

  • Decision: We decided to split the data layer into three independent services, each owning its own SQLite database:

    • Auth Serviceauth.db: stores credentials and JWT token metadata

    • Users Serviceusers.db: stores user profile data

    • Game Servicegame.db: stores matches, move history, and statistics Each database is mounted as an independent Docker volume, and no service has access to another service’s database.

  • Pros:

    • Fault isolation: a failure or overload in game.db (e.g., caused by a high volume of concurrent matches) does not affect authentication or user profile access

    • Independent scalability: each service and its database can be scaled according to its own load profile

    • Single responsibility: each service has a clearly defined data domain, improving maintainability

  • Cons:

    • Queries that previously joined data across domains (e.g., linking statistics to a user profile) now require inter-service HTTP calls, adding latency and complexity

    • Three services to maintain instead of one, increasing development and operational overhead

    • Cross-service consistency (e.g., deleting a user requires coordinating Auth Service, Users Service, and Game Service) must be handled at the application level

10. Quality Requirements

This project is mainly focused on 4 basic quality attributes for an online game as GameY is. Those are good performance, high usability, easy maintainability and strong security.

10.1. Quality Tree

quality tree

10.2. Quality Scenarios

Attribute Description Metric

Response time

Time the system takes to react after a user’s abstraction

The system should respond to user actions within 1 second

Currency

System’s capacity to support different games and users at the same time

The system should support at least 25 simultaneous games or users without noticeable lag

Intuitiveness

Ease with which players can understand and play the game in a short period of time

New players should be able to understand and play the game within 10 minutes.

Continuity

System’s capacity to keep games and sessions active, keeping their progress updated

At least 90% of games and sessions should maintain their progress after interruptions.

Modularization

Organizational quality, where different functionalities of the program are located in different modules, so that changes in one part do not affect others

The program should be organized in at least 3 independent modules to isolate changes

API access

Secure control to the game funcitionalities, avoiding non authorized uses of the game

All unauthorized API requests should be blocked to prevent misuse

User’s information

Users' data protection, granting privacy and integrity.

User critical data should be properly protected and encrypted

11. Risks and Technical Debts

Contents

A list of identified technical risks or technical debts, ordered by priority.

We identified some technical risks that can affect the development of the Y game project. These risks must be identified and registered, and we can mitigate or accept them.

11.1. Risks

Risks can appear like part of Quality Attributes scenarios. We categorized the next ones based on the risk criteria of the project.

Table 1. Risk table
Area (Risk Criterion) Brief Description Mitigation measures Probability (1-3) Impact (1-3) Total Risk

Security

The project needs to pass strict security tests. There is a risk to not complete these requirements when we implement the backend and expose vulnerabilities in the game or the connection.

Do early validations, use security tools integrated in the Rust compiler (cargo audit) and make exhaustive code reviews.

2

2

4

Data Integrity

The system now uses three independent databases (auth.db, users.db, game.db). Operations that span multiple services (e.g., deleting a user requires coordinating Auth Service, Users Service, and Game Service) must be handled at the application level without native transaction support across services. This increases the risk of partial failures leaving data in an inconsistent state.

Implement compensating operations for cross-service data changes. Define clear ownership rules per data domain. Add integration tests that verify consistency across services after multi-step operations.

2

3

6

Performance

The game engine in Rust must allow to play against a bot with different strategies. If the decision algorithms of the robot are not optimized, the response time can degrade the experience of the user.

Design efficient AI strategies, measure times of execution (benchmarking) in the Rust engine from the first sprints and profile the code if there is bottlenecks.

2

2

4

Inter-service Communication Complexity

The separation into three independent backend services (Auth Service, Users Service, Game Service) introduces inter-service HTTP calls for operations that previously were internal (e.g., JWT verification, linking statistics to user profiles). This adds latency, increases the number of potential failure points, and complicates local development and debugging.

Define clear and versioned internal API contracts between services. Use Docker Compose to simplify local multi-service orchestration. Implement timeouts and fallback strategies for inter-service calls. Add end-to-end tests that cover cross-service flows.

2

2

4

Unknowns

Lack of deep knowledge in the ownership model of Rust and the typing of TypeScript. Sometimes we don’t have enough information about how an architecture can satisfy the requirements.

Dedicate initial time to Proof of Concepts (PoC), read official documentation and establish pair programming to level the knowledge of the team.

3

3

9

11.2. Technical debts

Technical debt Brief description

External API Dependency

Our app depends a lot of external services (like map services or data APIs). If those services change their API or go down, parts of our app will stop working. Right now, we don’t have a good abstraction layer to swap those services easily.

Network Inconsistency

The performance of the app depends directly on how good the user’s internet connection is. We still haven’t implemented a solid offline mode or cache system (like Service Workers), so with a bad connection the user experience will be very bad.

Monolithic Configuration

Because we don’t have much experience with server deployment, our first configuration will probably be a bit hardcoded or less modular than it should be. Later we need to refactor this to move to a more scalable setup using environment variables.

Cross-service Data Consistency

Operations that affect multiple data domains (e.g., user deletion, which must remove records from auth.db, users.db, and game.db) currently have no distributed transaction mechanism. This is accepted as a technical debt for the academic scope of the project and should be addressed with compensating transactions or a saga pattern in a production-grade system.

12. 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

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 without persisting their statistics or match history

Arc42

Architecture documentation template followed in this project for structural consistency

BFF (Backend for Frontend)

Architectural pattern where the Web App Server orchestrates calls to multiple backend services (Users Service and Game Server)

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

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

Match

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

Microservices

Distributed architecture pattern where the system is decomposed into independent services (Frontend, Web App Server, Users Service, Game Server)

Move/Movement

Player action placing a piece at specific coordinates on the board

PlantUML

Tool used for generating architectural diagrams throughout the documentation

Registered Player

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

Reverse Proxy

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

SQLite

Embedded relational database used for persisting users, matches, and statistics

Stateless Service

Service that does not maintain persistent state between requests (e.g., Game Server)

Strategy

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

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 that acts as the single point of access to the database, managing authentication, user accounts, match persistence, and statistics

WAL (Write-Ahead Logging)

SQLite mode that enables concurrent reads during writes, improving database performance

Web App Server

Node.js/Express/TypeScript service implementing the BFF pattern, orchestrating requests between Frontend, Users Service, and Game Server

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