Skip to content

Architecture Decisions Record

Julián Fernández Herruzo edited this page Apr 6, 2026 · 2 revisions

Architecture Decision Records (ADR)

This section documents the most relevant architectural decisions made during the design of the system. Each decision includes context, alternatives, rationale, and consequences to ensure traceability and transparency.


ADR-01: Adoption of a Service-Oriented Architecture

Status: Accepted

Context

The system consists of three main functional areas:

  • User interface (Web application)
  • User management
  • Game engine logic

These areas could be implemented either as a monolithic application or as independent services.

Decision

The system is implemented as a set of loosely coupled services, each running independently and communicating via HTTP APIs.

Alternatives Considered

  • Monolithic architecture
  • Service-oriented (multi-container) architecture

Rationale

The service-oriented approach was selected because:

  • It enforces clear separation of concerns
  • It allows independent development and testing
  • It aligns with container-based deployment
  • It improves maintainability and scalability

Consequences

Positive:

  • Independent evolution of components
  • Clear API contracts
  • Better modularity

Negative:

  • Increased deployment complexity
  • Network communication overhead

ADR-02: Use of Container-Based Deployment

Status: Accepted

Context

The system needs to be executable in development environments and easily portable across machines.

Decision

All services are deployed using containerization and orchestrated together.

Alternatives Considered

  • Native execution on host machine
  • Containerized execution

Rationale

Containerization ensures:

  • Environment consistency
  • Dependency isolation
  • Simplified onboarding
  • Infrastructure reproducibility

Consequences

Positive:

  • Predictable deployments
  • Technology independence per service

Negative:

  • Slight overhead compared to native execution

ADR-03: Backend and Database Technology Selection (Node.js + MongoDB)

Status: Accepted

Context

The project requires a backend and persistence solution that enables rapid development, flexibility, and ease of deployment.

Technologies evaluated:

  • MongoDB (document database)
  • SQL (relational databases)
  • Neo4j (graph database)
  • Node.js vs Spring (backend frameworks)

Decision

Use:

  • Node.js for backend services
  • MongoDB as the primary database

Alternatives Considered

  • SQL databases
  • Neo4j
  • Spring (Java-based backend)

Rationale

Why MongoDB

  • Flexible, document-oriented schema
  • Well-suited for semi-structured and evolving data
  • Faster iteration during early development
  • Natural JSON serialization
  • Strong integration with JavaScript/TypeScript

Why Node.js

  • Unified language across frontend and backend (JavaScript/TypeScript)
  • Reduced stack complexity
  • Large ecosystem for web APIs
  • Asynchronous model suitable for I/O-heavy applications

Consequences

Positive:

  • Faster development cycles
  • Flexible data model
  • Reduced integration complexity
  • Consistent technology stack

Negative:

  • Less strict relational integrity than SQL
  • Complex queries may be harder than in relational systems
  • Requires discipline for data consistency at application level

ADR-04: Authentication Strategy Using JWT

Status: Accepted

Context

The system requires authentication that:

  • Supports user registration and login
  • Scales without server-side session storage
  • Integrates with a REST API architecture

Alternatives evaluated:

  • Traditional sessions (cookies + server storage)
  • OAuth 2.0
  • JWT (JSON Web Tokens)

Decision

Use JWT (JSON Web Tokens) for authentication and session management.

Alternatives Considered

  • OAuth 2.0
  • Server-side sessions

Rationale

Why JWT

  • Stateless authentication
  • Enables horizontal scalability
  • Simple integration with REST APIs
  • Low infrastructure overhead

Why Not OAuth 2.0

  • Designed for third-party authorization
  • Adds unnecessary complexity for internal authentication

Why Not Sessions

  • Requires server-side storage
  • Harder to scale horizontally
  • Introduces tighter coupling

Consequences

Positive:

  • Lightweight and scalable authentication
  • No session storage required
  • Well-suited for modern frontend applications

Negative:

  • Token revocation is more complex
  • Requires careful handling of expiration and refresh tokens
  • Security depends on proper client-side storage

ADR-05: Dedicated Persistence Layer for Users

Status: Accepted

Context

To support real user management, persistent storage is required.

Decision

Introduce a dedicated database accessed exclusively through the Users Service.

Alternatives Considered

  • In-memory storage
  • File-based storage

Rationale

  • Ensures durability and consistency
  • Enables long-term user management
  • Supports future features (authentication, statistics)
  • Maintains separation of concerns

Consequences

Positive:

  • Persistent user data
  • Clear data ownership
  • Improved scalability

Negative:

  • Additional infrastructure
  • Requires data modeling and connection management

ADR-06: Separation of Game Logic from User Management

Status: Accepted

Context

The system includes both user management and game execution logic.

Decision

The game engine is fully independent from user management and persistence.

Rationale

  • Enforces single responsibility principle
  • Improves reusability of the game engine
  • Prevents tight coupling between domains

Consequences

Positive:

  • Clear domain boundaries
  • Easier testing
  • Higher reusability

Negative:

  • Requires coordination via APIs

ADR-07: Technology Stack per Service

Status: Accepted

Context

Different components require different optimizations.

Decision

  • Frontend: React + TypeScript + Vite
  • User Service: Node.js (Express)
  • Game Engine: Rust

Alternatives Considered

  • Single unified stack
  • Fully compiled stack

Rationale

  • React enables fast UI development
  • Node.js allows rapid API development
  • Rust ensures performance and safety for game logic

Consequences

Positive:

  • Best tool for each component
  • High performance where needed
  • Improved developer productivity

Negative:

  • Polyglot complexity
  • Multiple build and deployment processes

ADR-08: RESTful API Design

Status: Accepted

Context

Services need a communication mechanism.

Decision

Use RESTful HTTP APIs with JSON payloads.

Alternatives Considered

  • GraphQL
  • Message queues
  • Direct calls

Rationale

  • Simplicity and widespread adoption
  • Easy debugging and testing
  • Stateless communication

Consequences

Positive:

  • Standardized communication
  • Easy integration

Negative:

  • Potential inefficiencies vs GraphQL
  • HTTP overhead

ADR-09: Monitoring with Prometheus and Grafana

Status: Accepted

Context

The system requires observability.

Decision

Use Prometheus for metrics and Grafana for visualization.

Alternatives Considered

  • No monitoring
  • Commercial tools

Rationale

  • Open-source and cost-effective
  • Strong ecosystem compatibility

Consequences

Positive:

  • Real-time system insights
  • Improved reliability
  • Educational value

Negative:

  • Additional setup complexity
  • Extra infrastructure components

ADR-10: TLS Termination at the Edge with Caddy

Status: Accepted

Context

The platform was originally exposed over plain HTTP. The deployment target is a single Ubuntu VM with Docker Compose, and the system needed HTTPS with minimal operational overhead and no changes to internal service code.

Decision

Use Caddy as the public-facing reverse proxy to terminate TLS and forward traffic to the internal gateway over the Docker network.

Alternatives Considered

  • TLS directly in the Node.js gateway: Couples TLS concerns to application code, complicates certificate renewal, and requires manual handling of ACME protocols. Discarded to preserve separation between edge security and business logic.
  • Nginx + Certbot: Widely used and well-documented, but requires separate Certbot configuration, cron-based renewal, and more manual setup. Discarded in favour of a solution with automatic certificate lifecycle management out of the box.
  • Traefik: Capable and Docker-native, but more complex to configure for a single-VM setup with no orchestrator. The operational overhead was not justified at this scale.
  • Caddy: Automatic certificate provisioning and renewal via ACME, secure defaults, simple declarative configuration. Selected option.

Rationale

Caddy was selected because it provides automatic certificate provisioning and renewal with minimal configuration, keeps TLS concerns separated from application logic, and is well-suited to a single-VM Docker Compose deployment. It reduces both the time to ship HTTPS and the ongoing operational burden.

Consequences

Positive:

  • Automated certificate lifecycle with no manual renewal
  • Clean separation between edge security and application routing
  • Faster HTTPS rollout with less custom code

Negative:

  • One additional infrastructure component to operate
  • Certificate issuance depends on ACME reachability and correct DNS resolution

ADR-11: Public Domain Resolution with DuckDNS

Status: Accepted

Context

The system is deployed on a VM where managing a custom domain adds cost and friction for an academic or prototyping environment. A stable public hostname is required for TLS certificate issuance via ACME.

Decision

Use a DuckDNS hostname as the public domain for the application.

Alternatives Considered

  • Custom paid domain with static IP: Provides full control and branding, but introduces registration cost and DNS management overhead. Not justified for the current deployment context.
  • Raw IP access: No DNS dependency, but incompatible with ACME-based certificate issuance, which requires a resolvable domain name. Discarded.
  • DuckDNS: Free, fast to set up, and fully compatible with ACME certificate workflows. Selected option.

Rationale

DuckDNS was selected primarily because it is free, which is the decisive factor in an academic or prototyping context. It also integrates cleanly with ACME-based certificate issuance (used by Caddy in ADR-10) and eliminates the need for manual DNS edits when the VM's IP changes.

Consequences

Positive:

  • Zero cost
  • Stable public hostname compatible with automated HTTPS provisioning
  • No manual DNS edits required on IP changes

Negative:

  • External dependency on DuckDNS availability
  • No custom branding; not suitable for a production product

ADR-12: Mandatory HTTP to HTTPS Redirection

Status: Accepted

Context

After enabling HTTPS via Caddy (ADR-10), plain HTTP access remained possible. Allowing both protocols in parallel increases the risk of insecure usage and inconsistent canonical URLs.

Decision

Enforce permanent 301 redirection from HTTP to HTTPS at the edge.

Alternatives Considered

  • Keep HTTP and HTTPS in parallel: Avoids redirect overhead but leaves an insecure entry point open. Discarded.
  • Temporary redirect (302): Functionally equivalent in the short term but does not signal permanence to browsers or CDNs, undermining long-term caching and canonical URL behaviour. Discarded.

Rationale

A permanent redirect is the standard approach to enforce encrypted transport, establish a single canonical URL scheme, and let browsers cache the redirect to reduce future latency. The configuration cost is trivial within Caddy.

Consequences

Positive:

  • All traffic encrypted in transit
  • Consistent URL scheme across frontend and API
  • Browsers cache the redirect, reducing future plaintext requests

Negative:

  • Legacy clients expecting plain HTTP will fail without warning
  • Reverting to mixed-protocol access requires an explicit configuration change

Conclusion

The architecture prioritizes:

  • Modularity and separation of concerns
  • Scalability through stateless services
  • Developer productivity and rapid iteration
  • Flexibility in both data modeling and technology choices

The combination of Node.js, MongoDB, JWT, and a service-oriented architecture provides an effective balance between simplicity, performance, and scalability for the system.

Clone this wiki locally