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.
1. Introduction and Goals
1.1. Requirements Overview
The project aims to develop a full-stack web application for a game named YOVI, communicating human players and automated agents. The following high level specifications must be in the final version of the application:
1.1.1. User Management
| ID | Description |
|---|---|
FR-01 |
The system shall allow users to register and authenticate (login/logout) to manage their personal profiles. |
FR-02 |
The system shall maintain a persistent history of matches played by each registered user. |
FR-03 |
The system shall provide a dashboard for users to view their statistics, including win/loss ratios and total games played. |
1.1.2. Gameplay (Web Frontend)
| ID | Description |
|---|---|
FR-04 |
The frontend shall implement the "Classic Version" of Game Y in a Player-vs-Machine (AI) mode. |
FR-05 |
The system shall support variable board sizes, allowing the player to define the dimensions before starting a match. |
FR-06 |
The UI shall allow the player to select from multiple game strategies or difficulty levels provided by the AI. |
FR-07 |
The frontend shall visualize the board using the coordinate systems (Barycentric or Index-based) defined in the YEN notation. |
1.1.3. Game Engine (Rust Module)
| ID | Description |
|---|---|
FR-08 |
The module shall provide a web service interface to receive game states and return move calculations. |
FR-09 |
The engine shall validate the current board state to determine if a match has been won, lost, or is still in progress. |
FR-10 |
The engine shall implement at least two distinct move-generation strategies for the AI. |
1.1.4. External Bot API
| ID | Description |
|---|---|
FR-11 |
The API shall expose a |
FR-12 |
The API shall provide endpoints for bots to retrieve user information and historical game data. |
FR-13 |
The API shall support parameters for bots to specify which game strategy the engine should utilize during a match. |
1.1.5. Data & Communication
| ID | Description |
|---|---|
FR-14 |
All communication between the TypeScript frontend and the Rust backend shall be conducted via JSON messages. |
FR-15 |
The system shall strictly adhere to the YEN notation for representing board layouts, player turns, and piece positions. |
1.2. Quality Goals
| Goal | Description |
|---|---|
Availability |
The application and its API must be publicly accessible and maintain high uptime for both web users and bot integrations. |
Usability |
The frontend should be intuitive, allowing users to easily toggle between game strategies and view their statistics without a steep learning curve. |
Performance |
The backend architecture should handle concurrent matches from both web users and API-based bots without significant latency. |
Security |
User data and match histories must be protected via secure authentication, ensuring users can only manage their own profiles. |
1.3. Stakeholders
| Role/Name | Contact | Expectations |
|---|---|---|
Development team |
yovi_en1a |
To receive clear requirements and timely feedback on builds. |
Players |
N/A |
To get an engaging application of the game that is stable and intuitive. |
Evaluators |
Archisoft |
To ensure the architectural integrity between the frontend (TypeScript) and backend (Rust) via the YEN notation. |
Micrati |
N/A |
To receive a functional prototype that meets all predefined success criteria. |
2. Constraints
2.1. Technical Constraints
Technical constraints define the specific technologies and tools that must be used.
| Constraint | Description |
|---|---|
Programming Languages |
Frontend must be TypeScript. The core Game Y logic (win verification/suggestions) must be Rust. |
Data Exchange |
All subsystem communication must use JSON formatted according to the YEN notation (size, turn, players, layout). |
Deployment & Runtime |
The system must be containerized with Docker and run on an Ubuntu Linux environment. |
External Connectivity |
The system must expose a documented Web API accessible by third-party bots for automated gameplay. |
2.2. Architectural Constraints
Architectural constraints are the high-level design requirements that dictate the system’s structure.
| Constraint | Description |
|---|---|
Subsystem Decoupling |
The system must be split into at least two distinct subsystems (Web App and Rust Module). They must remain independent and communicate only via web services. |
Strategy Extensibility |
The architecture must support multiple AI strategies and difficulty levels, selectable by the user or the bot via the API. |
Multi-Coordinate Support |
The system must handle both Barycentric (x,y,z) and Index-based (0…n) coordinate systems, ensuring correct mapping between the UI and the Engine. |
2.3. Organizational Constraints
Organizational constraints relate to the project management and academic requirements.
| Constraint | Description |
|---|---|
Academic Framework |
Must satisfy all criteria for the ASW assignment, including traceability and quality attributes. |
Team Workflow |
Mandatory use of Git for version control, featuring documented Code Reviews and Issue Tracking. |
Documentation Standard |
Architecture must be documented using the arc42 template and include Architectural Decision Records (ADRs). |
Evaluation Metrics |
The system must be evaluated on Availability and Observability (Monitoring) and Testing Coverage. |
2.4. Conventions
Conventions are the rules agreed upon by the team to ensure consistency.
| Convention | Description |
|---|---|
Language |
English is the mandatory language for code, documentation, and the API. |
API Documentation |
All endpoints must be fully documented. |
Modeling |
Diagrams must follow UML standards and be rendered using software such as PlantUML. |
Naming Conventions |
Follow standard TypeScript (camelCase) and Rust (snake_case) style guides respectively. |
3. Context and Scope
The YOVI_0 system (Game Y at UniOvi) is a distributed gaming platform designed to provide a competitive environment for both human players and automated agents. The system’s primary boundary lies between the user-facing web interface and the high-performance game logic engine implemented in Rust.
3.1. Business Context
The business context defines how YOVI_0 interacts with external entities. The system acts as a standardized provider for both human players and third-party bots, ensuring interoperability through the YEN notation.
| Communication Partner | Inputs | Outputs |
|---|---|---|
Human Player |
Account registration data, game moves via hexagonal UI, and selection of AI strategy. |
Real-time board updates, personal performance statistics, and historical match records. |
External Bots |
RESTful API requests containing current board states in YEN notation. |
Calculated next moves in YEN notation and game-state validation. |
Micrati Developers / Admins |
Infrastructure configuration, CI/CD scripts, and Docker management. |
Application health metrics, observability logs, and test coverage reports. |
External Domain Interfaces:
-
YEN Notation: The primary domain language. It is a JSON-based representation ensuring interoperability between any external subsystem.
-
Coordinate Systems: Supports both Barycentric (x,y,z) and Index-based coordinates to accommodate different mathematical approaches by bot developers.
3.2. Technical Context
The YOVI_0 architecture follows a microservices-inspired model. All communication between the React-based frontend and the specialized services is handled over network calls.
| Interface | Protocol | Description |
|---|---|---|
Client Browser |
HTTPS / TCP |
The entry point for the user. Delivers the React SPA, which subsequently handles business logic via fetch/axios. |
Internal Services |
HTTP / JSON |
Communication between the Webapp and the Node.js User Service (Port 3000) and the Rust GameY Engine (Port 4000). |
Public Bot API |
REST / JSON |
A public endpoint allowing third-party applications to interact with the game engine using the YEN standard. |
Mapping Input/Output to Channels:
-
Game Logic Flow: Move submissions are sent via JSON POST to the Rust service. The service parses the YEN layout, validates the move, and returns the updated state.
-
Authentication Flow: Credentials are sent via HTTP POST to the User Service, which processes the persistence simulation and returns a status code.
-
Observability: Logs from Node.js and Rust are mapped to standard Docker output (
stdout), accessible via the technical management console.
4. Solution Strategy
4.1. Technology Decisions
As outlined in the Technical Context (Section 3), the core technology stack and infrastructure—Rust for the Logic Engine, React.js for the Frontend, Node.js for the User Service, YEN Notation for communication, and Docker for containerization were predefined constraints for this project.
Our primary architectural decisions focus on how to integrate these given constraints effectively and what supplementary technologies to employ to complete the system:
Decision |
Technology |
Motivation |
Database |
MongoDB |
Document-based storage naturally fits the predefined YEN Notation (JSON) format seamlessly and allows for flexible player statistics without rigid schemas. |
4.2. Top-level Decomposition
To effectively integrate the mandated technologies, the system follows a Microservices-oriented decomposition. This ensures a clean separation of concerns and independent scalability:
-
Webapp (React): Serves as the presentation layer and the primary entry point for human users.
-
Logic Engine (Rust): A stateless, isolated service dedicated purely to high-performance game rule validation and AI calculations (Port 4000).
-
User Service (Node.js): Acts as the orchestrator for user accounts and statistics, handling concurrent API requests and communicating directly with our chosen MongoDB cluster (Port 3000).
4.3. Achievement of Quality Goals
-
Interoperability: By rigorously applying the mandated YEN Notation across our REST/JSON APIs, the system allows external bots (using different coordinate systems like Barycentric or Index) to integrate effortlessly with the Rust engine.
-
Persistence & Flexibility: Our strategic decision to use MongoDB ensures that as the game evolves (e.g., adding new bot metrics or match data), the system can dynamically adapt its data structures.
-
Performance: The architectural decoupling guarantees that the heavy computational hexagonal grid logic is strictly handled by the Rust Engine, while the Node.js service leverages its non-blocking I/O to handle user requests without bottlenecks.
5. Building Block View
The Building Block View provides a hierarchical decomposition of the YOVI_0 system. It describes the static structure, showing how the system is organized into subsystems and components, and how they interact with each other. This view is essential for understanding the overall architecture and the responsibilities of each part of the system.
5.1. Level 1: Overall System
Level 1 represents the highest level of abstraction, showing the main subsystems of the YOVI_0 system and their interactions. Each subsystem is responsible for a specific aspect of the system’s functionality, and they communicate with each other to fulfill the requirements of the project.
The following diagram shows the top-level decomposition of the YOVI_0 system into its three primary subsystems: the Frontend (Webapp), the User Management (User Service), and the Logic Engine (GameY).
5.1.1. Component Descriptions
| Name | Responsibility |
|---|---|
Webapp |
The central UI and gateway. Manages hexagonal grid rendering and provides the documented API for external bots. |
User Service |
Handles administrative logic: user registration, session management, and persists match statistics to the DBMS. |
GameY Engine |
The high-performance "brain." Written in Rust for memory safety and speed; it validates game rules and provides AI moves via YEN notation. |
MongoDB |
The Document-based DBMS. It persists all non-transient data, chosen for its native support of JSON-like structures (perfect for YEN payloads). |
5.2. Level 2: Webapp (Frontend Subsystem)
The Webapp is a Single Page Application (SPA) built with React and Vite. It acts as the primary user interface and the orchestrator of requests between the User Service and the GameY Engine.
5.2.1. Component Descriptions
| Component | Detailed Responsibility |
|---|---|
main.tsx |
The Bootstrap of the application. It utilizes the react-dom/client library to find the root element in the HTML and injects the React application. It implements StrictMode to identify potential problems during development. |
App.tsx |
The Layout Orchestrator. It imports the global CSS and provides the high-level UI structure. It acts as a container for the different views (currently the RegisterForm). |
RegisterForm.tsx |
The Interaction Hub. This is the most complex component in this module. It manages local state for input data, loading animations, and error handling. It is responsible for the sequence: Submit → User Creation → Game Status Check. |
env.d.ts |
The Configuration Schema. It defines the ImportMetaEnv interface. This ensures that the TypeScript compiler recognizes custom environment variables used for service discovery, preventing runtime crashes. |
5.2.2. Internal dynamics and logic
The internal behavior of this module is driven by the state within RegisterForm.tsx:
-
Service Discovery: The module does not hardcode URLs. It uses an Environment-Aware approach:
-
It defaults to http://localhost:3000 (Users) and http://localhost:4000 (GameY) for local development.
-
It allows overrides via VITE_API_URL and VITE_GAMEY_URL for production/containerized environments.
-
-
Asynchronous Lifecycle:
-
User Registration: Initiates a fetch POST request with a JSON payload containing the username.
-
Chained Validation: Upon a successful (200 OK) response from the User Service, it triggers the checkGamey() function. This ensures that the player is only notified that "Game is ready" if the Rust engine is reachable.
-
-
Resilience: The UI is designed to be fail-safe. If the GameY engine is down, the user is still successfully registered, but the system displays a "Game is not ready" warning to manage user expectations.
5.3. Level 2: GameY Engine (Logic Subsystem)
The GameY Engine is a high-performance Rust subsystem responsible for the rules of the "Game of Y". It is structured as both a Library (lib.rs) for core logic and a Binary (main.rs) that provides a Command-Line Interface (CLI) and an HTTP Bot Server.
5.3.1. Component Descriptions
| Module | Detailed Responsibility |
|---|---|
main.rs |
Application Entry Point. Uses clap to parse CLI arguments. It determines the execution mode: Human (local CLI), Computer (local vs Bot), or Server (HTTP API for the Webapp). |
lib.rs |
Library Root. The central exported interface. It organizes the crate into public modules and provides the high-level GameY struct used to manipulate the triangular board. |
core |
The Rules Engine. Implements the triangular board mathematics, coordinate systems (Barycentric/Index), and the connection-based win conditions. |
bot_server |
The Gateway. Uses tokio to run an asynchronous HTTP server. It allows the Webapp to request moves via REST, serving as the bridge between the React frontend and the Rust logic. |
bot |
The Intelligence. Contains the GamerBot and the YBotRegistry. It implements the strategies used to calculate the next optimal move for a computer player. |
notation |
The Interoperability Layer. Implements YEN (Y Exchange Notation). It defines a JSON-serializable format for board layouts (e.g., "B/BR/.R."), inspired by chess’s FEN. |
cli |
Interactive Shell. Provides a rich terminal experience using rustyline. It supports board rendering, move history, and saving/loading game states to files. |
gamey_error |
Domain Safety. Defines the GameYError enum using thiserror. It strictly enforces game rules (e.g., Occupied, InvalidPlayerTurn) and ensures system resilience. |
5.3.2. Internal dynamics and logic
The GameY module operates through distinct execution patterns:
-
Stateful CLI Loop: In cli.rs, the run_cli_game function maintains an interactive loop. It captures user indices (e.g., "5"), converts them to coordinates, and applies moves to the GameY state. It supports "meta-commands" like save, load, and show_coords.
-
Stateless Server Pattern: When running in Mode::Server, the engine becomes a stateless API. It receives a YEN payload from the Webapp, reconstructs the game state momentarily in memory, calculates the AI’s response via the bot module, and returns the new state.
-
Strict Error Enforcement: Every action passes through the gamey_error module. If a player (or the Webapp) attempts an illegal move (such as placing a piece on an Occupied cell), the engine returns a specific error variant rather than allowing an inconsistent game state.
-
Serialization (YEN): The notation/yen.rs module ensures that complex triangular board states can be compressed into a single string. This is critical for the "Building Block" connection between the Webapp and GameY, as it minimizes the data payload sent over HTTP.
5.4. Level 2: User Service
5.4.1. Component Responsibilities
| Component | Technology | Responsibility |
|---|---|---|
Express Entry Point |
Node.js / Express 5.x |
Orchestrates the business logic for |
Security Manager |
bcrypt |
Ensures "Security by Design" by hashing passwords. |
Database Driver |
MongoDB Driver 7.x |
Handles asynchronous communication with the |
Metrics Provider |
express-prom-bundle |
Bridges the application to the Prometheus monitoring instance. |
6. Runtime View
6.1. Scenario 1: Human Player vs. AI (Move Execution)
Description: This scenario illustrates the core game loop when a human player interacts with the frontend to play against the system’s AI. It highlights the transformation of UI interactions into the standardized YEN notation and the delegation of logic to the high-performance Rust engine.
Notable Aspects: The Webapp acts as a pure presentation layer. It does not calculate game rules. All coordinate conversions (Barycentric/Index) and move validations are strictly handled by the GameY Engine.
6.2. Scenario 2: Human Player vs. Human Player (Multiplayer Turn Execution)
Description: This diagram illustrates the turn flow between two human players. It demonstrates how a move made by one player is validated, saved, and seamlessly pushed to the opponent’s screen.
Notable Aspects: Unlike the "Human vs. AI" scenario where the Rust engine immediately calculates a counter-move, here the GameY Engine (Rust) is strictly used for rule validation. The User Service (Node) acts as the central state manager. It handles saving the updated board to the database internally and directly pushes the new state to the second player’s client (via WebSockets/Push), initiating their turn without the need for manual retrieval or polling.
6.3. Scenario 3: Match Conclusion and Statistics Persistance
Description: This scenario demonstrates the data flow when a game concludes (either by a win, loss, or draw). It shows the interaction between the Frontend, the Logic Engine, and the User Service to ensure persistent data storage.
Notable Aspects: The GameY Engine is stateless; it only validates the win. The responsibility of saving the match and updating user statistics is delegated to the User Service, which asynchronously communicates with MongoDB.
6.4. Scenario 4: User Authentication and Login Flow
Description: This scenario illustrates the security and session management architecture of the system. It details how the system handles a user login request, verifies credentials, and establishes a secure session for the player.
Notable Aspects: The GameY Engine is bypassed entirely for this process, as it is strictly dedicated to game logic. This interaction occurs purely between the Webapp (Frontend), the User Service (Node.js), and the Database (MongoDB). It demonstrates a clean separation of concerns where the User Service handles all identity and access management.
6.5. Scenario 5: Error Handling - Invalid Move Validation
Description: This exception scenario demonstrates system resilience. It shows what happens when an invalid move (for example, attempting to play on an already occupied coordinate) is submitted by the user.
Notable Aspects: The GameY Engine acts as the single source of truth for game rules. If a YEN payload violates these rules, the engine strictly rejects the state change. It returns an appropriate error code, which the Webapp must gracefully handle to warn the user without breaking or crashing the UI state.
7. Deployment View
7.1. Infrastructure Level 1: Azure Cloud Environment
7.1.1. Motivation
The system runs on a single Azure Virtual Machine (Ubuntu 24.04 LTS). Azure was chosen for its reliability and easy VM setup. A single VM keeps costs low while still resembling a real production environment. All components are containerized with Docker so that the setup works the same way in development and in production, and deployments via GitHub Actions stay simple.
7.2. Infrastructure Level 2: Container Orchestration (Docker Compose)
7.2.1. Motivation
Docker Compose manages all containers in a single configuration file. All services run on a shared internal network (monitor-net) so they can talk to each other without exposing unnecessary ports to the outside. The Webapp is compiled with the backend URLs baked in at build time (VITE_API_URL, VITE_GAMEY_URL), so no extra runtime configuration is needed.
The diagram below shows how containers are connected inside monitor-net. Grafana maps its internal port 3000 to host port 9091 to avoid clashing with the Users service.
7.3. Mapping of Building Blocks to Infrastructure
| Building Block | Infrastructure Element | Description |
|---|---|---|
webapp |
Docker Container (Nginx) |
Serves the React/Vite frontend. Accessible via Port 80. |
users |
Docker Container (Node.js) |
Handles identity, history, and stats. Accessible via Port 3000. |
gamey |
Docker Container (Rust) |
Logic for Game Y moves and win validation. Accessible via Port 4000. |
mongodb |
Docker Container (MongoDB) |
Persistent document store for user profiles and match history. Accessible internally on Port 27017. |
prometheus |
Docker Container |
Scrapes metrics from the services via the internal network. |
grafana |
Docker Container |
Visualizes metrics. Mapped to Port 9091 to avoid conflict with the Users service. |
7.4. Infrastructure Level 3: Data Persistence
7.4.1. Motivation
The application requires its data to survive when containers restart. Prometheus and Grafana use bind mounts so their configuration files live directly in the repository and are version-controlled like any other code. MongoDB uses a named Docker volume so that user and game data persists across docker-compose down and up cycles without any manual intervention.
| Element | Storage Strategy | Path |
|---|---|---|
Metrics Config |
Docker Bind Mount |
|
Grafana Dashboards |
Docker Bind Mount |
|
User & Game Data |
Docker Named Volume ( |
Managed by Docker. Data survives restarts and redeployments independently of the container image. |
7.5. Network and Connectivity
All containers communicate over the monitor-net bridge network. Only the following ports are exposed to the host:
-
Port 80: Web application entry point.
-
Port 3000: Users REST API (used by Webapp and Bots).
-
Port 4000: Game Engine API (YEN notation).
-
Port 27017: MongoDB — internal only, not exposed to the host.
-
Port 9090 / 9091: Prometheus and Grafana for system observability.
8. Cross-cutting Concepts
8.1. Domain Concepts
8.1.1. Game Y and Hexagonal Grids
The core domain of the application revolves around the "Classic Version" of Game Y. The game environment is based on variable-sized hexagonal boards. The system supports multiple coordinate representations for these grids: * Barycentric Coordinates (x,y,z): Used to represent three-dimensional positioning in a 2D hexagonal space. * Index-based Coordinates (0…n): Linear representation for simpler indexing in arrays or matrices.
8.1.2. YEN Notation
All game states are uniformly formatted using the YEN Notation, which dictates how board sizes, player turns, and piece positions are serialized. This ensures consistent state representation across the Frontend, the Logic Engine, and external bots.
A YEN string encodes the complete game state in a compact, human-readable format. For example, on a 3×3 board where Blue has played two cells and Red has played one:
B/BR/.R.
-
B— It is Blue’s turn. -
BR/— Row 1 contains a Blue piece, a Red piece, then the row separator. -
.R.— Row 2 contains an empty cell, a Red piece, and another empty cell.
8.2. Architecture and Design Patterns
8.2.1. Microservices Architecture
The concrete service breakdown (Webapp, User Service, Logic Engine) is described in Sections 4 and 5. The cross-cutting design rules that govern the microservice decomposition are:
-
Independent Deployability: Each service is packaged as its own Docker image with an isolated build pipeline. A new release of one service never requires redeploying another.
-
Strict Network Boundaries: Services communicate exclusively over defined HTTP endpoints. There are no shared databases, in-process calls, or file-system dependencies between services.
-
Single Responsibility: Each service owns exactly one concern — the Logic Engine owns game rules, the User Service owns identity and persistence, and the Webapp owns presentation. Business logic must not leak across service boundaries.
8.2.2. Stateless Processing
The Logic Engine is intentionally stateless. Current game states (in JSON format) are passed within each request, allowing the engine to calculate AI behavior or determine win/loss states without storing active match sessions in memory.
8.3. Communication and Integration Concepts
8.3.1. RESTful JSON APIs
Communication both internally (between subsystems) and externally (third-party bots) relies fully on HTTP REST APIs utilizing JSON.
* Internal APIs: The User Service and Logic Engine communicate with the Webapp using predefined JSON schemas strictly validating YEN notation.
* External Bot Interface: The system provides dedicated endpoints (e.g., a play method) for third-party bots to interact with the engine.
8.3.2. Asynchronous Push Communication (WebSockets)
For real-time interactions, particularly in the "Human vs. Human" multiplayer scenario, the architecture envisions asynchronous push communication. Instead of relying on inefficient client-side polling, the Node.js User Service will actively push game state updates (e.g., opponent moves) directly to the connected React clients via WebSockets. * Current State: Asynchronous push communication is planned but not yet implemented. The current system relies exclusively on RESTapi calls. * Future Updates: Once WebSockets (e.g., via Socket.IO) are integrated, this section will be expanded with the specific event structures and network flow diagrams.
8.4. Data Persistence Concepts
8.4.1. Data Mapping Strategy
The technology choice (MongoDB) is documented in Sections 4 and 7. The cross-cutting design rule for persistence is how domain relationships are mapped to documents:
-
User Documents are stored as flat, self-contained documents in the
userscollection (fields:username,email,passwordhash,createdAt). No embedding of child objects is used at this stage. -
Match History (planned): Match results will be stored as separate documents in a
matchescollection, referencing the participating users by their_idrather than embedding the full user object. This avoids data duplication and keeps user updates (e.g., profile changes) consistent without cascading writes. -
Design Rule — Referencing over Embedding: Whenever two entities have independent lifecycles (e.g., a user exists regardless of any single match), the system favours document references (
ObjectIdforeign keys) over nested embedding. Embedding is reserved for data that is never queried or updated independently (e.g., a list of coordinates within a single match snapshot).
8.5. Security Concepts
8.5.1. User Authentication and Password Storage
-
Registration: Players register with a username, email, and password. The User Service hashes all passwords using bcrypt (cost factor 10) before persisting them to MongoDB. Plaintext passwords are never stored.
-
Login: Upon login the User Service retrieves the stored hash and verifies it against the submitted password via
bcrypt.compare.
8.5.2. Session Management
-
Current State: Token-based session management (e.g., JWTs) is not yet implemented. The runtime scenario in Section 6.4 already envisions a JWT-based flow (generate token on login → store in Session Storage → attach to subsequent requests). This will be implemented in a future iteration and this section will be updated accordingly.
-
Planned Approach: The User Service will issue a signed JSON Web Token (JWT) upon successful login. The React Webapp will store the token in the browser’s Session Storage and attach it as an
Authorization: Bearer <token>header on every API request. The User Service will validate the token on protected endpoints.
8.5.3. Configuration and Secrets Management
Service configuration (ports, upstream URLs, database connection strings) is managed through environment variables that are injected via docker-compose.yml.
| Variable | Service | Example Value |
|---|---|---|
|
User Service |
|
|
Game API |
|
|
Webapp (build-time) |
|
|
User Service |
|
Warning
|
The current setup uses plain environment variables in |
8.5.4. Data Scoping and Privacy
-
Data Privacy: Requests are secured to ensure players can only access and modify their own personal profiles and match histories.
8.5.5. CORS (Cross-Origin Resource Sharing)
Because the Webapp (Port 80) communicates with backend APIs on different ports (3000, 3001, 4000), CORS must be configured explicitly.
-
User Service (Node.js): Implements a strict origin whitelist using the
corsmiddleware. Allowed origins are configured via theALLOWED_ORIGINSenvironment variable (comma-separated). By default, onlylocalhostorigins are permitted. Requests from unlisted origins are rejected with an error. -
Game API (
gameyapi): Currently uses a permissive CORS policy (cors()with no origin restriction) to facilitate external bot integration. This will be tightened before production deployment.
8.5.6. Rate Limiting
|
Note
|
Rate limiting is not yet implemented. Since the system exposes a public API for external bots (see Section 3), it is susceptible to abuse or accidental overload. Rate limiting middleware (e.g., |
8.6. User Experience (UX) Concepts
8.6.1. State Management and Rendering
In the Frontend Webapp, complex match states and user actions are managed reactively. * State Trees: React manages the active game properties (board layout, opponent type, current turn) locally to provide instant visual feedback without blocking for server responses during non-validating actions. * Hexagonal UI Representation: The UI seamlessly maps the engine-provided mathematical coordinate arrays (Barycentric or Index-based) onto visual hexagonal grids for intuitive gameplay.
8.7. Quality and Reliability Concepts
8.7.1. Logging Strategy
All services emit logs exclusively to stdout/stderr, which allows the Docker container runtime to collect and forward them transparently. No dedicated log-aggregation sidecar is required for the current setup.
-
Rust Logic Engine (
gamey): Uses thetracingcrate withtracing_subscriber. This produces structured, level-based log output (INFO,DEBUG,WARN) that is machine-readable and can be forwarded to an aggregator (e.g., Loki/Grafana) in a future step. Fatal startup errors are written tostderrviaeprintln!. -
Node.js Services (
users,gameyapi): Use the built-inconsole.log/console.warn/console.errorAPI. Output is written directly to the process stdout/stderr, which Docker captures. Log lines are prefixed with context tags (e.g.,[CREATE],[MOVE],[BOT]) to aid filtering. -
React Frontend (
webapp): Browserconsole.*calls are available during development. No log forwarding to the backend occurs from the client.
|
Note
|
Centralized log aggregation (e.g., shipping Docker logs to a Loki stack alongside the existing Prometheus/Grafana setup) is planned for a later iteration. |
8.7.2. Error Handling and Cross-Service Error Propagation
The system uses a layered error propagation model based on standard HTTP semantics. The example described in Scenario 5 (Section 6.5) illustrates a concrete instance of this pattern.
The concrete error handling layers are:
-
Rust Logic Engine: Returns precise HTTP error codes (
400 Bad Requestfor invalid YEN/rule violations,500 Internal Server Errorfor unexpected failures). The JSON body contains a machine-readableerrorfield. -
Node.js Middleware (Game API / User Service): Catches errors from upstream Rust calls, logs them via
console.error, and maps them to sanitized, client-facing JSON responses. Internal error details (stack traces, Rust error messages) are not forwarded to the browser. -
React Frontend: Reads HTTP status codes from API responses. Non-2xx responses trigger UI-level feedback (e.g., warning toasts, reverting optimistic state updates). The Webapp never crashes on expected error payloads.
8.7.3. Observability and Monitoring
To satisfy availability evaluation metrics, the system incorporates rigorous operational monitoring: * Metrics Ingestion: Both the Node.js API and the Rust Gamey Engine emit structured operational metrics. * Visualization: Prometheus scrapes system health, latency, and throughput metrics, which are then aggregated and visualized using Grafana dashboards.
8.7.4. Testing and Quality Assurance
System reliability is continuously verified through multiple layers of testing: * Multi-Layer Testing: The system utilizes unit tests for individual algorithmic checks (especially Rust logic), integration tests for API endpoints, and End-to-End (E2E) UI tests for critical user journeys. * Static Analysis: Code quality and security are strictly evaluated via SonarCloud against defined Quality Gates prior to any merge.
8.7.5. Continuous Integration and Deployment (CI/CD)
The development pipeline is automated natively with GitHub Actions:
* CI Pipelines: Push events and pull requests trigger automated test suites and SonarCloud evaluations.
* CD Pipelines: Upon a successful release merge, Docker images are automatically built from each service’s Dockerfile and orchestrated on the production server via docker-compose (see Sections 2 and 7 for the containerization details).
8.8. Development and Operational Concepts
8.8.1. Documentation Strategy
The architecture documentation follows a strict Docs-as-Code approach: * AsciiDoc & Arc42: All architectural documentation is written in AsciiDoc, structured entirely according to the arc42 template. This approach ensures technical documentation lives alongside the source code in version control. * PlantUML: As dictated by our conventions, all architectural diagrams and models must comply with UML standards and are rendered programmatically using PlantUML.
8.8.2. Collaboration and Source Control
-
Git Workflows: Employs pull requests, mandatory code reviews, and issue tracking.
-
Traceability: Documentation must constantly be maintained following the arc42 structure (including ADRs) to comply with academic quality evaluation criteria.
9. Architecture Decisions
10. Quality Requirements
10.1. Quality Tree
10.2. Quality Scenarios
11. Risks and Technical Debts
12. Glossary
| Term | Definition |
|---|---|
<Term-1> |
<definition-1> |
<Term-2> |
<definition-2> |
