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. Introducción y Objetivos
1.1. Descripción de los requisitos
El sistema desarrollado permite jugar al juego Y a través de una interfaz web, apoyándose en una arquitectura modular compuesta por varios servicios.
Actualmente, la aplicación ofrece las siguientes funcionalidades principales:
-
La app dispone de una interfaz web para jugar al juego Y.
-
Se ofrecen dos modos de juego:
-
Partida jugador contra jugador.
-
Partida jugador contra bot.
-
El bot tiene diferentes estrategias implementadas, y el usuario puede elegir cuál de ellas usar (nivel de dificultad).
-
-
-
El tablero tiene tamaño variable, configurable por el usuario dentro de unos límites establecidos.
-
El usuario puede elegir quién empieza la partida, según el modo de juego.
-
El usuario podrá registrarse en la aplicación, o inciar sesión si ya tiene cuenta asociada.
-
Cada usuario podrá ver un historial de partidas y sus estadísticas (ganadas/perdidas, número de partidas, etc.).
-
-
Se proporcionará un API externo (documentado) para que los bots puedan usar el sistema.
-
El API permitirá consultar/gestionar info de usuarios y partidas.
-
El API tendrá un método
playque recibe al menosposition(en notación YEN) y devuelve el siguiente movimiento (también en YEN).
-
-
El “motor” del juego estará en un módulo/servicio aparte (implementado en Rust), y la web lo llamará por HTTP mediante JSON (usando YEN).
Casos de uso:
| ID | Caso de uso | Actor | ¿Qué pasa? |
|---|---|---|---|
UC-01 |
Registrarse / iniciar sesión |
Usuario |
El usuario se crea cuenta o entra con su cuenta para poder guardar partidas y ver estadísticas. |
UC-02 |
Configurar una partida |
Usuario |
El usuario selecciona el modo de juego, el tamaño del tablero, el bot en caso necesario y quién comienza la partida. |
UC-03 |
Crear partida jugador vs jugador |
Usuario |
El sistema crea una nueva sesión de juego HvH y devuelve el estado inicial de la partida. |
UC-04 |
Crear partida jugador vs bot |
Usuario |
El sistema crea una nueva sesión de juego HvB, aplicando la configuración elegida y, si corresponde, realizando el primer movimiento del bot. |
UC-05 |
Jugar un turno desde la web |
Usuario |
El usuario selecciona una celda válida y el sistema actualiza el estado de la partida. |
UC-06 |
Obtener la respuesta del bot |
Sistema |
Tras la jugada del usuario en una partida HvB, el servicio de juego calcula y aplica automáticamente el movimiento del bot. |
UC-07 |
Comprobar si la partida ha finalizado |
Sistema |
Después de cada movimiento, el servicio determina si existe un ganador o si la partida continúa. |
UC-08 |
Ver historial y estadísticas |
Usuario registrado |
El usuario ve el historial partidas anteriores y sus estadisticas guardadas en su cuenta. |
UC-09 |
Consultar el estado de una partida |
Usuario |
La interfaz puede recuperar el estado actual de una sesión de juego mediante su identificador. |
1.2. Objetivos de calidad
Los objetivos de calidad del sistema se concretan y evaluarán en la sección "10. Atributos de Calidad" siguiendo el modelo ISO/IEC 25010, mediante un árbol de calidad y escenarios. De forma resumida, la arquitectura prioriza:
-
Adecuación funcional: El motor debe garantizar el cumplimiento de reglas y la validación del estado de la partida, evitando acciones inválidas y guiando al usuario durante el juego.
-
Eficiencia de desempeño: Se busca respuesta ágil y sin “lag” en las operaciones principales, con un uso eficiente de recursos y soporte de concurrencia, apoyado en el motor en Rust y el despliegue en contenedores.
-
Compatibilidad / interoperabilidad: La comunicación entre subsistemas y con bots externos debe ser estable, clara y validada, basada en JSON con notación YEN y un API bien documentado.
-
Usabilidad: La web debe ser intuitiva y fácil de aprender, con una interfaz que indique turnos, opciones y restricciones, reduciendo errores del usuario.
-
Fiabilidad / disponibilidad: El sistema debe mantener estabilidad ante fallos habituales y ser observable/monitorizable para detectar caídas o degradaciones.
-
Seguridad: Se controlarán accesos (registro/login y API pública), validación de entradas y medidas de protección de credenciales (por ejemplo, cifrado/hasheado de contraseñas).
-
Mantenibilidad: El diseño modular por microservicios y la separación de responsabilidades deben permitir incorporar nuevas estrategias/reglas o cambios en el API minimizando el impacto en el resto del sistema.
-
Portabilidad: Al basarse en Docker, el sistema debe ser desplegable en distintos entornos con una instalación reproducible.
1.3. Stakeholders
| Stakeholder | Descripción | Expectativas / motivaciones |
|---|---|---|
Jugador (usuario final) |
Persona que entra a la web para jugar al juego Y (contra otra persona o contra el bot). |
Que sea fácil de usar, que cargue rápido, que el juego no dé errores raros, poder elegir tamaño/estrategia y ver su historial y estadísticas. |
Equipo de desarrollo |
Mario Amandi, Marcelo Díez, Andrea Ivanov y Eloy Rubio |
Poder avanzar sin bloqueos, tener una arquitectura modular, poder implementar buenos tests y desplegar el sistema, además de mejorar las habilidades de programación (nuevos lenguajes), desarrollo y trabajo en equipo. |
Profesorado |
Jose E. Labra Gayo, Pablo González, Diego Martín Fernández y Celia Melendi Lavandera |
Que se cumplan los requisitos, que se justifiquen las decisiones arquitectónicas, que haya pruebas de código y que el despliegue sea accesible por web. |
Micrati |
Empresa que decide apostar por el desarrollo del juego y encarga el proyecto. |
Que el producto final sea usable y presentable, que cumpla los requisitos establecidos, que sea fácil de mantener/mejorar y que no tenga fallos. |
2. Restricciones Arquitectónicas
2.1. Restricciones técnicas y estructurales
| Restricción | Descripción |
|---|---|
Frontend desarrollado con Vite y React |
La interfaz gráfica del sistema debe implementarse como una aplicación web usando React y Vite. |
Servicio de usuarios desarrollado con Node.js y Express |
El servicio dedicado a la gestión de usaurios debe implementarse con una API REST con Node.js y Express, utilizando persistencia en MongoDB. |
Juego desarrollado con Rust |
La lógica clave del juego (crear tablero, manejar movimientos, implementación de bot, etc) tiene que estar desarrollado en Rust y exponerse mediante un servicio HTTP. |
Comunicación entre servicios mediante HTTP y JSON |
La integración entre los distintos módulos del sistema debe realizarse mediante peticiones HTTP e intercambio de datos en formato JSON. |
Uso de notación YEN para representar el estado de la partida |
El estado del tablero se representa mediante la notación YEN. Además, el sistema puede intercambiar jugadas mediante identificadores de celda dentro de las sesiones de juego. |
Soporte de tablero de tamaño variable |
El sistema debe soportar un tablero cuyo tamaño sea configurable (un tamaño establecido predefinido, y que el usuario pueda escoger otro tamaño diferente, dentro de los límites definidos). |
Diferentes estrategias de bot (dificultad) |
El bot debe tener más de una estrategia y el usuario debe poder elegirla (relacionado con niveles de dificultad). |
Host en Docker |
El sistema deberá estar "levantado" con Docker en una máquina virtual para la entrega final. |
Documentación con arc42 |
La documentación debe seguir la estructura base de la plantilla arc42. |
Control de versiones |
El proyecto se desarrollará mediante Git, alojándolo en GitHub. |
2.2. Restricciones organizativas y de proceso
| Restricción | Descripción |
|---|---|
Énfasis en calidad y evaluación |
Se valora explícitamente documentación, pruebas, despliegue, repositorio y calidad general. |
Trabajo en equipo y control de cambios |
Al ser un proyecto en grupo, se necesita un flujo de trabajo con control de versiones, revisiones y acuerdos, además de comunicación entre compañeros. |
Gestión de tareas |
Se utilizará la funcionalidad de Github "Github Issues" para asignar y gestionar las tareas de cada miembro del equipo. |
Tiempo y alcance limitados |
El proyecto tiene diferentes entregas a lo largo de su desarrollo (versiones). |
Reuniones de equipo |
Se realizará al lo menos una reunión semanal (sesión de laboratorio). Además, se harán reuniones extras cuando se vea necesario (presenciales o telemáticas) para poner de acuerso diferentes implementaciones. Estas quedarán reflejadas en sus respectivas actas en el apartado "Wiki" del repositorio de GitHub. |
3. Contexto y Alcance
3.1. Contexto de negocio
-
Jugador: Usa el sistema para registrarse o iniciar sesión, configurar partidas, jugar al juego Y desde la interfaz web y consultar resultados/estadísticas.
-
Bot: Sistema externo que interactúa con YOVI mediante una API, permitiendo automatizar partidas o realizar jugadas.
-
Administrador: Responsable de desplegar, supervisar y mantener el sistema.
-
YOVI: Sistema principal que ofrece la funcionalidad de juego y expone las capacidades necesarias tanto para usuarios finales como para integraciones externas.
3.2. Contexto técnico
-
Web Browser (Jugador): Cliente desde el que el usuario accede a la aplicación web.
-
Bot Externo: Cliente software que consume la API del sistema para interactuar con las partidas.
-
Servidor (Docker): Aloja los servicios backend y el motor del juego. Contiene:
-
gateway (Nginx): Punto de entrada único al sistema. Redirige las peticiones al frontend o a los servicios backend según la ruta solicitada.
-
webapp (React/Vite): Aplicación frontend tipo SPA que implementa la interfaz de usuario.
-
users (Node/Express): Servicio backend encargado de la gestión de usuarios.
-
gamey (Rust): Servicio backend que encapsula la lógica del juego y expone la API de partidas y movimientos.
-
MongoDB: Servicio de persistencia utilizado por el módulo de usuarios.
-
La comunicación técnica principal del sistema se realiza a través del gateway. El navegador carga la aplicación frontend a través de este componente, y tanto la interfaz web como los clientes externos acceden a los servicios backend mediante rutas HTTP diferenciadas.
4. Estrategia de Solución
4.1. Decisiones Tecnológicas
El sistema adopta una arquitectura de microservicios con tres componentes principales:
-
webapp (React + Vite + TypeScript): Interfaz web donde los usuarios juegan
-
users (Node.js + Express): Gestiona usuarios, autenticación y partidas
-
gamey (Rust): Motor del juego con las reglas y lógica del Juego Y
4.1.1. Stack Tecnológico
Frontend (webapp):
-
React + TypeScript para crear una interfaz de usuario moderna y robusta
-
Vite para desarrollo rápido
Backend (users):
-
Node.js + Express por su simplicidad para crear APIs REST
-
Swagger para documentar el API
-
Prometheus para recoger métricas del sistema
Motor de juego (gamey):
-
Rust por su alto rendimiento y seguridad
-
Axum como framework HTTP asíncrono para exponer el servidor de juego
-
Tokio como runtime asíncrono subyacente
-
Tower-http para gestión de middleware CORS
-
Puede ejecutarse como servidor web o desde línea de comandos
Base de datos:
-
MongoDB por su flexibilidad y fácil integración con JSON
Comunicación:
-
HTTP/REST con JSON
-
Notación YEN para las posiciones del tablero
Despliegue:
-
Azure para alojar la maquina virtual en la que se ejecuta la aplicación
-
Docker para que funcione igual en todos los entornos
4.2. Patrones Arquitectónicos
4.2.1. Frontend: Single Page Application (SPA)
Webapp es una aplicación de página única con React que actualiza dinámicamente el contenido sin recargar la página.
4.2.2. Motor de Juego: Separación entre Dominio e Infraestructura
gamey separa la lógica del juego de los detalles técnicos:
Lógica del juego:
-
core/: Núcleo del juego -
bot/: Diferentes estrategias de bots
Infraestructura:
-
game_server/: Servidor del juego con el servidor -
bot_server/: Conexión del bot con el servidor -
notation/: Conversión entre formatos (YEN, YGN)
4.2.3. Estrategias de Bot (módulo bot/)
El módulo de bots se estructura en torno al trait YBot y un registro centralizado (YBotRegistry) que permite seleccionar el bot deseado en tiempo de ejecución por nombre. Actualmente se dispone de tres implementaciones:
-
random_bot(random.rs): Elige una celda disponible al azar, sin ninguna heurística. Sirve como línea base de comparación para el resto de estrategias. -
greedy_bot(greedy.rs): Aplica una heurística de Potencial de Conectividad basada en coordenadas triangulares. Puntúa cada celda disponible según su proximidad a los bordes del tablero y su centralidad estratégica, eligiendo siempre el movimiento de menor coste. Es más predecible que MCTS pero sensiblemente mejor que el bot aleatorio. -
mcts_bot(mcts.rs): Implementa una versión simplificada de Monte Carlo Tree Search. Para cada movimiento posible ejecuta un número configurable de simulaciones aleatorias hasta el final de la partida, acumulando estadísticas de victoria. Se registra con dos niveles de dificultad:-
5.000 iteraciones — respuesta rápida, calidad media-alta.
-
20.000 iteraciones — mayor precisión, tiempo de respuesta más elevado.
-
4.2.4. API REST del Motor de Juego (game_server/)
El servidor expone una API versionada bajo el prefijo /v1 con los siguientes endpoints:
| Endpoint | Método | Descripción |
|---|---|---|
|
GET |
Comprueba que el servicio está en marcha. |
|
GET |
Devuelve la configuración del tablero: tamaño mínimo y máximo permitidos. |
|
POST |
Crea una nueva partida genérica a partir de un tamaño de tablero. |
|
POST |
Inicia una partida Humano vs Bot seleccionando el bot por su identificador y el jugador que empieza. |
|
POST |
Recibe el movimiento del humano (en notación YEN), lo aplica, calcula la respuesta del bot y devuelve el nuevo estado del tablero. |
4.3. Decisiones Organizativas
Gestión:
-
GitHub Issues para tareas y bugs
-
Kanban para seguimiento visual
-
Pull Requests con revisión obligatoria
-
Rama
masterprotegida
Documentación:
-
Arc42 para la documentación del proyecto
-
Draw.io para realizar los diagramas
-
Wiki para las actas de las reuniones
5. Vista de bloques
5.1. Visión general
Vista general del sistema con tres microservicios independientes: webapp (interfaz), users (gestión de usuarios) y gamey (motor del juego).
5.1.1. Descripción de los bloques
| Componente | Responsabilidad | Interfaces |
|---|---|---|
webapp |
Presenta la interfaz gráfica al usuario. Permite jugar partidas, registrarse e iniciar sesión. |
Consume la API REST de |
users |
Gestiona el registro, login y estadísticas de los usuarios. Expone una API REST documentada con Swagger. |
Se comunica con |
gamey |
Motor del juego. Valida movimientos, mantiene el estado de la partida en notación YEN y gestiona las estrategias de bot. |
Expone una API REST consumida por |
MongoDB |
Almacena los datos de usuarios y partidas. |
Solo accedida por |
6. Vista de ejecución
6.1. Registrar un usuario
Proceso de registrar un usuario.
6.2. Jugar una casilla
Proceso de jugar una casilla.
6.3. Jugar una casilla vs bot
Proceso de jugar una casilla en una partida contra un bot.
7. Vista de Despliegue
7.1. Infrastructura Nivel 1
La arquitectura de despliegue se basa en la contenedorización de los servicios mediante Docker Compose, permitiendo un entorno aislado y reproducible tanto en desarrollo como en producción. El sistema se despliega en una máquina virtual de Microsoft Azure accesible públicamente a través del dominio yovies4a.duckdns.org.
- Motivación
-
Se ha elegido Azure por su capacidad de integración con flujos de CI/CD a través de GitHub Actions y por la robustez de su infraestructura cloud. El uso de Docker garantiza que el software se comporte de la misma manera en el servidor que en los entornos de desarrollo local, evitando el clásico "en mi máquina funciona". El dominio público
yovies4a.duckdns.orgse gestiona mediante DuckDNS, un servicio de DNS dinámico que apunta a la IP pública de la máquina virtual de Azure. - Características de calidad y/o rendimiento
-
-
Disponibilidad: Azure garantiza un SLA elevado para sus servicios de computación, reduciendo el tiempo de inactividad no planificado.
-
Observabilidad: La inclusión de Prometheus y Grafana directamente en la infraestructura permite monitorizar el rendimiento y la salud de los servicios en tiempo real, con alertas configurables ante degradaciones.
-
Escalabilidad: Azure ofrece escalado automático (vertical y horizontal), lo que permite ajustar los recursos según la demanda del juego.
-
Reproducibilidad: El fichero
docker-compose.ymlen la raíz del repositorio define la topología completa del sistema, permitiendo levantar todos los servicios con un único comando (docker-compose up --build).
-
- Mapeo de los bloques de construcción a la infraestructura
| Bloque de Construcción | Puerto Externo | Descripción |
|---|---|---|
webapp |
80 |
Interfaz web servida por Nginx. Punto de entrada para jugadores humanos. |
users |
3000 |
API REST de gestión de usuarios y partidas. Punto de entrada para bots externos. |
gamey |
4000 |
Motor del juego en Rust. Accesible internamente y desde bots vía API. |
prometheus |
9090 |
Recolector de métricas del sistema. |
grafana |
9091 |
Visualizador de dashboards de monitorización. |
mongodb |
27017 |
Base de datos documental. Solo accesible desde la red interna de Docker. |
7.2. Infrastructura Nivel 2
7.2.1. Pipeline de CI/CD (GitHub Actions)
El despliegue en producción es completamente automatizado mediante GitHub Actions. Al publicar una nueva release en el repositorio, el workflow release-deploy.yml ejecuta las siguientes etapas en orden:
-
Test: Ejecuta los tests unitarios e integración de todos los servicios (
webapp,users,gamey). -
Build: Construye las imágenes Docker de cada servicio y las publica en GitHub Container Registry (GHCR) con la etiqueta de la versión y
latest. -
Publish: Publica la imagen versionada en el registro.
-
Deploy: Se conecta por SSH a la máquina virtual de Azure, descarga las nuevas imágenes y reinicia los contenedores con
docker-compose pull && docker-compose up -d.
El análisis de calidad de código se realiza de forma continua mediante SonarCloud, que se integra en cada pull request para reportar cobertura de tests, code smells y vulnerabilidades de seguridad.
7.2.2. Servicios de Aplicación
Estos contenedores representan la lógica de negocio y la interfaz de usuario:
-
webapp (Puerto 80): Servidor web Nginx que sirve la aplicación frontend React compilada como contenido estático. La variable de entorno
VITE_API_URLse configura en tiempo de build para apuntar al serviciousers. Se comunica con el backend mediante peticiones HTTP al API REST. -
users (Puerto 3000): Microservicio Node.js/Express encargado de la gestión de usuarios (registro, login), historial de partidas y estadísticas. Actúa como orquestador, recibiendo peticiones de la
webappy delgateway, y delegando la lógica del juego al serviciogamey. Expone métricas para Prometheus en el endpoint/metrics. -
gamey (Puerto 4000): Microservicio Rust que encapsula la lógica del juego Y. Gestiona el estado del tablero, valida movimientos, calcula si hay un ganador y proporciona movimientos de bot mediante distintas estrategias (incluyendo MCTS). Se comunica mediante JSON usando la notación YEN. Puede ejecutarse también en modo CLI para pruebas locales.
-
gateway (Puerto 443/80): Punto de entrada único al sistema que actúa como proxy inverso. Enruta el tráfico hacia
webappy hacia el API deuserssegún la ruta solicitada, gestionando también el acceso desde bots externos.
7.2.3. Servicios de Persistencia
-
MongoDB (Puerto 27017): Base de datos documental que almacena la información de usuarios, partidas y estadísticas. Solo es accesible desde la red interna de Docker (
docker network), sin exposición pública de puertos. Los datos se persisten mediante un volumen Docker montado en el host.
7.2.4. Servicios de Monitorización
Infraestructura dedicada a asegurar el correcto funcionamiento del sistema bajo carga:
-
Prometheus (Puerto 9090): Recolecta métricas de los servicios
users(y otros componentes instrumentados) mediante scraping periódico de endpoints/metrics. La configuración de targets se define en el ficheroprometheus.ymly se monta como volumen. -
Grafana (Puerto 9091): Visualiza las métricas recolectadas mediante paneles de control (dashboards) preconfigurados y aprovisionados automáticamente mediante volúmenes. Permite detectar de forma visual tendencias de carga, latencias y posibles caídas de servicio.
7.2.5. Entornos de Despliegue
| Entorno | URL / Acceso | Descripción |
|---|---|---|
Producción |
Máquina virtual Azure con Docker Compose. Se actualiza automáticamente con cada release mediante GitHub Actions. |
|
Desarrollo local |
Los desarrolladores levantan el entorno completo con |
|
Revisión (PR) |
GitHub Actions |
En cada pull request se ejecutan los tests automáticamente pero no se despliega en infraestructura pública. |
8. Conceptos Transversales (Cross-cutting Concepts)
8.1. Modelo de Dominio
El sistema gira en torno a la lógica del Juego Y, un juego de estrategia en tablero triangular cuyo objetivo es conectar dos lados del tablero con una cadena continua de piezas propias.
Los conceptos clave del dominio son:
-
Tablero (Board): Estructura triangular de tamaño variable (N×N casillas). Las posiciones se representan mediante coordenadas baricéntricas (x, y, z) donde
x + y + z = N - 1, lo que facilita el cálculo de distancias a los lados. -
Partida (Game): Sesión de juego entre dos participantes (usuarios o bots). Contiene el estado del tablero, el turno actual, los jugadores y el historial de movimientos.
-
Movimiento (Move): Acción de colocar una pieza en una casilla libre. Se serializa en notación YEN para el intercambio entre servicios.
-
Notación YEN (Y Exchange Notation): Formato de serialización JSON inspirado en FEN (del ajedrez). Representa el estado completo de una partida (tablero, turno, jugadores) para su almacenamiento o transmisión entre
webapp,usersygamey. -
Notación YGN (Y Game Notation): Formato de registro de la secuencia de movimientos de una partida completa, análogo al PGN del ajedrez.
-
Usuario: Persona registrada en el sistema con credenciales, historial de partidas y estadísticas.
-
Bot: Agente automático que juega partidas consumiendo el API público. Puede usar distintas estrategias de decisión.
8.2. Seguridad y Autenticación
La seguridad es un concepto transversal que afecta principalmente al servicio users y a las comunicaciones cliente-servidor.
-
Registro y autenticación: Los usuarios se registran y autentican mediante correo electrónico y contraseña. El sistema implementa una verificación en dos pasos (2FA por email) para confirmar la identidad del usuario antes de dar acceso a su cuenta.
-
Almacenamiento seguro de contraseñas: Las contraseñas nunca se almacenan en texto plano. Se guardan en MongoDB como hashes criptográficos (usando algoritmos como bcrypt), de forma que incluso un acceso no autorizado a la base de datos no exponga las credenciales reales.
-
Validación de entradas: El servicio
usersvalida todas las entradas recibidas (tanto de la webapp como de bots externos) para prevenir inyecciones y datos malformados. -
Control de acceso a la API: El API público para bots expone únicamente las operaciones necesarias (consultar estado, enviar movimiento), con comprobaciones de permisos para impedir acceso a datos de otros usuarios.
-
Red interna de Docker: MongoDB no expone puertos públicos; solo es accesible desde la red interna de contenedores (
docker network), reduciendo la superficie de ataque.
8.3. Comunicación entre Servicios
La comunicación entre todos los componentes del sistema sigue un patrón uniforme:
-
Protocolo: HTTP/REST en todos los intercambios.
-
Formato de datos: JSON en todos los mensajes, incluyendo la representación del estado del juego en notación YEN.
-
Sincronía: Las llamadas son síncronas (petición-respuesta). La
webappllama al serviciousers, que a su vez llama agameycuando necesita delegar lógica de juego. -
Documentación del API: El servicio
usersexpone su API documentada con Swagger/OpenAPI, permitiendo que los desarrolladores de bots conozcan los endpoints disponibles, sus parámetros y los formatos de respuesta esperados.
8.4. Estrategias de Bot
El servicio gamey implementa un sistema de bot con múltiples estrategias intercambiables, que el usuario puede elegir como nivel de dificultad:
-
Bot aleatorio: Elige una casilla válida aleatoria. Nivel de dificultad mínimo.
-
Bot MCTS (Monte Carlo Tree Search): Algoritmo probabilístico que simula miles de partidas aleatorias desde el estado actual para estimar estadísticamente la probabilidad de victoria de cada movimiento posible. Es el nivel de dificultad más alto. Se implementa con un límite de tiempo de respuesta para evitar bloqueos del contenedor.
La arquitectura del módulo gamey separa claramente el registro de bots (bot/registry) de la implementación de cada estrategia (bot/), facilitando la incorporación de nuevas estrategias sin modificar el núcleo del juego.
8.5. Monitorización y Observabilidad
Para garantizar la salud del sistema, se ha implementado una infraestructura de observabilidad transversal que cubre todos los entornos:
-
Recolección de métricas: Prometheus actúa como el recolector central, haciendo scraping periódico del endpoint
/metricsde los diferentes servicios instrumentados. Registra métricas de rendimiento como tiempos de respuesta, número de peticiones, errores HTTP y uso de recursos. -
Visualización: Grafana proporciona tableros de control (dashboards) para monitorizar en tiempo real el estado de los servicios, facilitando la detección temprana de fallos o degradaciones de rendimiento. Los dashboards se aprovisionan automáticamente como código (como volúmenes de configuración).
-
Trazabilidad de logs: Los servicios generan logs estructurados que permiten correlacionar eventos entre
webapp,usersygameypara diagnosticar problemas en flujos completos.
8.6. Calidad de Código y Testing
La calidad del código se garantiza de forma continua y transversal mediante:
-
Tests unitarios: Cada servicio tiene su suite de tests unitarios independiente (
npm testparawebappyusers,cargo testparagamey). Se verifica la lógica de negocio de forma aislada con mocks de dependencias. -
Tests de integración: Se prueba la comunicación entre servicios para verificar que los contratos del API se cumplen correctamente.
-
Tests end-to-end: La
webappincluye tests E2E (npm run test:e2e) que simulan la interacción completa de un usuario con el sistema a través del navegador. -
Análisis estático (SonarCloud): Integrado en el pipeline de CI/CD, analiza cada pull request en busca de code smells, duplicidades, vulnerabilidades de seguridad y cobertura de tests. Se publica un Quality Gate público con el estado del proyecto.
8.7. Proceso de Desarrollo y Gestión (GitHub Ecosystem)
Para asegurar la calidad del software y la organización del equipo, se utiliza el ecosistema de GitHub de manera integral:
-
Gestión de Tareas (Kanban): Se utiliza GitHub Projects con una metodología Kanban para visualizar el flujo de trabajo (To Do, In Progress, Done…). Esto permite el seguimiento en tiempo real del estado de cada funcionalidad.
-
Seguimiento de Tareas (Issues): Cada nueva funcionalidad, error o mejora se documenta mediante Issues, que sirven como unidad básica de trabajo y permiten la trazabilidad de los requisitos hasta el código.
-
Flujo de Trabajo (Pull Requests): El código no se integra directamente en la rama principal (
master, que está protegida). Se utilizan Pull Requests (PRs) para la revisión por parte de otros miembros del equipo, asegurando que el código cumpla con los estándares antes de ser fusionado. -
Actas de reuniones (Wiki): Las reuniones semanales de equipo y las reuniones extraordinarias quedan registradas en la Wiki del repositorio de GitHub, garantizando trazabilidad de las decisiones tomadas.
8.8. Tecnologías
El sistema adopta un enfoque polyglot (varios lenguajes y tecnologías), seleccionando la herramienta más adecuada para cada dominio del problema:
-
Motor de Juego de Alto Rendimiento (Rust): El servicio
gameyestá desarrollado en Rust para garantizar la seguridad de memoria (sin garbage collector, sin carreras de datos) y un alto rendimiento en la evaluación del árbol de juego. Rust también ofrece versatilidad al poder ejecutarse tanto en modo servidor HTTP como en modo CLI para pruebas. La documentación del motor se genera automáticamente concargo doc. -
Backend de Gestión (Node.js/Express): El servicio
usersutiliza un entorno basado en eventos y JavaScript/TypeScript para gestionar la lógica de usuario de forma ágil y escalable. Node.js es especialmente apropiado para APIs REST con operaciones de I/O intensivas (acceso a MongoDB, llamadas agamey). -
Frontend Moderno (React + Vite + TypeScript): La interfaz de usuario (
webapp) utiliza React para una gestión eficiente del estado de la UI, TypeScript para la seguridad de tipos en tiempo de compilación, y Vite como herramienta de construcción ultrarrápida en desarrollo. -
Base de Datos Documental (MongoDB): La flexibilidad del esquema JSON/BSON facilita la evolución del modelo de datos sin migraciones complejas, y su integración nativa con el ecosistema JavaScript/TypeScript simplifica el desarrollo del servicio
users. -
Contenedorización (Docker + Docker Compose): Todos los servicios se empaquetan en imágenes Docker, garantizando la portabilidad y reproducibilidad del entorno en desarrollo, pruebas y producción.
9. Decisiones de Arquitectura (ADR)
En esta sección se documentan las decisiones arquitectónicas fundamentales que rigen el diseño y desarrollo de Yovi_es4a, detallando su justificación y las alternativas consideradas.
9.1. ADR 1: Uso de MongoDB como Base de Datos
-
Estado: Aceptada.
-
Contexto: Se requiere un sistema de persistencia para almacenar los datos de los usuarios, partidas y estadísticas del juego que sea flexible y compatible con el ecosistema tecnológico actual.
-
Alternativas consideradas:
-
Bases de datos relacionales como MySQL o PostgreSQL: ofrecen esquemas rígidos y transacciones ACID completas, pero requieren migraciones complejas ante cambios del modelo de datos.
-
SQLite: sencilla para desarrollo local, pero no adecuada para entornos distribuidos en contenedores.
-
-
Justificación:
-
Compatibilidad con el stack: MongoDB utiliza formato BSON (variante de JSON), lo que facilita enormemente el flujo de datos con el frontend en React y el uso de TypeScript.
-
Integración con Rust: La seguridad de tipos de Rust permite deserializar documentos de MongoDB en
structscon una sola línea de código, garantizando datos válidos en el motorgamey. -
Facilidad de despliegue: Gracias a Docker, levantar una instancia de MongoDB es inmediato y reproducible, sin pasos de instalación manual.
-
Flexibilidad de esquema: Ideal para estructuras de datos en evolución, como las de un juego web en desarrollo iterativo, donde los campos de una partida o usuario pueden cambiar entre versiones sin necesidad de migraciones destructivas.
-
-
Consecuencias: Se espera mayor velocidad de desarrollo al no depender de esquemas rígidos. Como contrapartida, se renuncia a la consistencia transaccional fuerte entre colecciones, lo que es aceptable dado el dominio del problema.
9.2. ADR 2: Uso inicial de PlantUML para diagramación
-
Estado: Reemplazada (por ADR 3).
-
Contexto: Necesidad de una herramienta para crear los diagramas técnicos de la documentación arc42.
-
Alternativas consideradas:
-
Editores visuales como draw.io o Lucidchart.
-
-
Justificación:
-
Enfoque técnico: Es una herramienta basada en texto ("pseudo-código") recomendada en el ámbito académico y con buen soporte en entornos de CI/CD.
-
Mantenibilidad: El uso de texto plano facilita la realización de cambios rápidos y el control de versiones con Git (se puede hacer
diffentre versiones del diagrama).
-
-
Consecuencias: Permite la generación automática de diagramas visuales a partir de relaciones definidas por código, aunque carece de flexibilidad en la disposición visual manual, lo que provocó dificultades al representar arquitecturas complejas.
9.3. ADR 3: Adopción de draw.io para diagramas
-
Estado: Aceptada.
-
Contexto: Tras evaluar el uso de PlantUML en los primeros diagramas, se identificó la necesidad de una representación más libre, esquemática y visual de los componentes, especialmente para los diagramas de despliegue y contexto.
-
Alternativas consideradas:
-
PlantUML (mantenida como opción de respaldo para diagramas de secuencia).
-
Mermaid: Similar a PlantUML, basada en texto, con buen soporte en GitHub Markdown.
-
-
Justificación:
-
Intuitividad: Es una herramienta visual que no requiere aprendizaje previo para su manejo. Todos los miembros del equipo pueden contribuir a los diagramas independientemente de su perfil técnico.
-
Control Visual: Permite posicionar libremente los componentes (
webapp,users,gamey), facilitando la representación de relaciones jerárquicas y flujos de comunicación de forma más clara y esquemática que el código de PlantUML. -
Integración con GitHub: Los ficheros
.drawiose pueden almacenar directamente en el repositorio y visualizarse en GitHub Pages.
-
-
Consecuencias: Aunque requiere algo más de tiempo manual para la creación y no permite generación automática, resulta más cómoda, comunicativa y accesible para todo el equipo. Se usa conjuntamente con PlantUML para los diagramas de secuencia (vista de ejecución), donde la generación desde código sigue siendo ventajosa.
9.4. ADR 4: Implementación del motor del juego en Rust
-
Estado: Aceptada (impuesta por los requisitos del proyecto).
-
Contexto: La lógica del juego Y, incluyendo la validación de movimientos, la detección de victoria y la implementación de bots, requiere un alto rendimiento, especialmente para el algoritmo MCTS que simula miles de partidas.
-
Alternativas consideradas:
-
Node.js: Hubiera simplificado el stack tecnológico al unificar frontend y backend en JavaScript/TypeScript, pero ofrece menor rendimiento para tareas computacionalmente intensivas.
-
Python: Lenguaje más familiar para el equipo, con librerías de IA disponibles, pero con el overhead del intérprete y el GIL (Global Interpreter Lock) como limitantes.
-
-
Justificación:
-
Rendimiento: Rust compila a código nativo sin garbage collector, con rendimiento comparable a C/C++. Esto es crítico para el algoritmo MCTS, que requiere explorar miles de nodos del árbol de juego por segundo.
-
Seguridad de memoria: El sistema de ownership de Rust garantiza la ausencia de data races y errores de acceso a memoria en tiempo de compilación, reduciendo bugs difíciles de depurar.
-
Versatilidad: El servicio
gameypuede ejecutarse tanto como servidor HTTP (modo producción) como desde la línea de comandos (modo desarrollo y pruebas), gracias a la arquitectura modular del proyecto Rust. -
Aprendizaje: El proyecto sirve como oportunidad para el equipo de adquirir experiencia con un lenguaje de sistemas moderno y de alta demanda laboral.
-
-
Consecuencias: La curva de aprendizaje de Rust es significativa (gestión de lifetimes, ownership), lo que supuso un riesgo de retraso inicial. Se mitigó empezando con implementaciones simples y evolucionando gradualmente hacia algoritmos más complejos.
9.5. ADR 5: Arquitectura de microservicios con tres componentes independientes
-
Estado: Aceptada.
-
Contexto: El sistema necesita integrar tecnologías heterogéneas (React, Node.js, Rust) y permitir el desarrollo en paralelo por parte de los distintos miembros del equipo.
-
Alternativas consideradas:
-
Monolito: Una única aplicación que integre frontend, lógica de usuario y motor del juego. Más sencillo de desplegar, pero impide el uso de Rust para el motor (requisito del proyecto) e introduce acoplamiento entre responsabilidades.
-
Monorepo con microservicios: La solución adoptada: un único repositorio Git (
yovi_es4a) que contiene los tres servicios (webapp,users,gamey) con sus propiosDockerfiley scripts de build, orquestados pordocker-compose.yml.
-
-
Justificación:
-
Separación de responsabilidades: Cada servicio tiene una única responsabilidad bien definida: UI (webapp), gestión de usuarios y partidas (users), lógica del juego (gamey).
-
Desarrollo en paralelo: Los miembros del equipo pueden trabajar en servicios distintos sin interferencias, reduciendo conflictos de merge.
-
Tecnología apropiada por dominio: Permite usar Rust donde el rendimiento es crítico, Node.js para el API REST y React para la UI, sin compromisos.
-
Despliegue independiente: Cada servicio se puede actualizar, escalar o reiniciar de forma independiente.
-
-
Consecuencias: Aumenta la complejidad operacional (hay que gestionar múltiples servicios, redes Docker, configuraciones de entorno). Se mitiga mediante
docker-compose.ymlque define toda la topología en un solo fichero y un pipeline de CI/CD completamente automatizado.
9.6. ADR 6: Uso de MCTS como estrategia de bot de máxima dificultad
-
Estado: Aceptada.
-
Contexto: El bot del juego debe ofrecer al menos dos niveles de dificultad. Se necesita una estrategia de alto nivel que proporcione un oponente desafiante para usuarios avanzados.
-
Alternativas consideradas:
-
Minimax con poda alfa-beta: Algoritmo clásico para juegos de dos jugadores con suma cero. Garantiza el movimiento óptimo hasta una profundidad dada, pero el espacio de estados del Juego Y es muy grande, limitando la profundidad explorable.
-
Heurísticas ad-hoc: Reglas específicas del dominio (ej. priorizar el centro, bloquear al oponente). Más rápidas, pero menos efectivas para jugadores avanzados.
-
-
Justificación:
-
Adaptabilidad: MCTS no requiere una función heurística definida manualmente; aprende qué movimientos son buenos simulando partidas completas aleatoriamente (rollouts).
-
Escalabilidad de calidad: Cuanto más tiempo de cómputo se le concede, mejores decisiones toma. El límite de tiempo se puede ajustar para controlar el nivel de dificultad.
-
Idoneidad para el Juego Y: MCTS ha demostrado ser efectivo en juegos de tablero de alto factor de ramificación como el Juego Y, donde minimax con poda se queda corto.
-
-
Consecuencias: El algoritmo MCTS es computacionalmente intensivo y puede causar tiempos de respuesta elevados si no se limita. Se implementa un límite de tiempo (timeout) para garantizar que el servicio
gameysiempre responde dentro de un umbral aceptable, devolviendo el mejor movimiento encontrado hasta ese momento.
10. Requisitos de Calidad
En esta sección se evaluarán los requisitos de calidad del proyecto siguiendo el modelo ISO/IEC 25010, el cuál nos facilita una serie de puntos imprescindibles para cumplir los estándares internacionales de ingeniería del software.
10.1. Quality Tree
Adecuación funcional
-
Completitud funcional: Se cubren los requisitos de jugabilidad implementando las acciones propias del juego Y, competición contra un bot y contra otro usuario en local. SC8
-
Corrección funcional: Se contemplan las reglas de juego desde el motor, garantizando una validación precisa del estado de la partida en cada momento. Se guía al usuario a seguir correctamente el desarrollo de partida. SC1
Eficiencia de desempeño
-
Comportamiento en el tiempo: Se garantiza un tiempo de respuesta óptimo al utilizarse Rust en el motor del juego. Además de la implementación de una estrategia cuidada del algoritmo de respuesta.
-
Utilización de recursos: El despliegue mediante contenedores Docker permite una gestión eficiente de la memoria y la CPU para los tres subsistemas (webapp, users, gamey). SC4
-
Capacidad: Se limitan los tamaños de tablero dentro de un rango para que siga siendo jugable dentro de la configuración que el usuario escoja.
Compatibilidad
-
Facilidad para interoperar: El intercambio de información entre subsistemas se realiza estrictamente mediante mensajes JSON siguiendo la notación YEN, asegurando que el API sea compatible tanto con la WebApp como con bots externos.
-
Coexistencia: Los microservicios están clasificados en sus contenedores correspondientes y facilmente se levantan y conectan entre sí en el docker-compose.yml.
Usabilidad
-
Inteligibilidad: Dispone de una interfaz clara e intuitiva diseñada con React para facilitar su uso a todo tipo de usuario. Se busca tener un aspecto actualizado.
-
Capacidad de aprendizaje: El juego sigue reglas sencillas con facilidad de aprendizaje. La dificultad está presente en aprender qué estrategia seguir.
-
Operabilidad: La propia interfaz te guía durante el juego mostrándote de quién es el turno, las casillas disponibles y opciones disponibles. SC2
-
Protección contra errores de usuario: Aquellas acciones que desencadenarían algún fallo, como por ejemplo jugar fuera de tu propio turno, están deshabilitadas, previendo una mala práctica del juego.
-
Participación del usuario: Se dispone de una interfaz interactiva con distintas funciones para que el usuario además de jugar al juego pueda registrar usuario y disponer de sus estadísticas.
-
Accesibilidad: Cualquier persona de habla hispana puede acceder al juego. No tiene soporte de idiomas. SC3 El uso de un DNS permite que los usuarios accedan a la aplicación mediante un nombre legible (yovies4a.duckdns.org) en lugar de una dirección IP técnica y difícil de recordar. SC7
-
Asistencia al usuario: Dispone de una ayuda para entender qué hace cada componente en cada caso, además de tooltips y mensajes descriptivos.
-
Autodescripción: Se busca dejar lo más claro posible el uso de cada herramienta ya sea con un texto descriptivo en botones o dibujos que indiquen claramente su finalidad.
Fiabilidad
-
Madurez: A lo largo de todo el proyecto se utiliza SonarCloud para mantener cierta calidad de código. Se han realizado pruebas unitarias y de integración para garantizar la estabilidad del sistema.
-
Disponibilidad: Se utilizan las herramientas Prometheus y Grafana para monitorizar el estado de los microservicios y detectar posibles caídas o problemas de rendimiento.
Seguridad
-
Confidencialidad: Se implementa un sistema de registro apoyado por una base de datos para almacenar a los usuarios, los cuales se autenticarán para acceder a sus cuentas.
-
Integridad: Se implementa un grado más de seguiridad cifrando las contraseñas de los usuarios, así nosotros tampoco contamos explicitamente con estas. SC5
-
No repudio: Se guarda en la base de datos la interacción del usuario con la aplicación junto con una serie de datos estadísticos, por lo que el correo asociado con la cuenta guarda un registro de actividad.
Mantenibilidad
Portabilidad
-
Adaptabilidad: Al estar basado en Docker, el proyecto es independiente del sistema operativo, lo que facilita su despliegue en diferentes entornos.
-
Instalabilidad: Mediante scripts de npm y comandos de Cargo, se levanta el entorno al completo rápidamente, con todos los componentes ya configurados.
10.2. Quality Scenarios
A continuación se exponen distintos escenarios de uso identificados por un código, por ejemplo SC1. Este código se encontrará en el arbol de calidad en el apartado que lo satisface, si pinchas en él te redirige a requisito de calidad.
| ID | Atributo | Escenario |
|---|---|---|
Adecuación funcional |
Un usuario trata de colocar una ficha en un turno que no es el suyo. El sistema no le permite saltarse el turno. |
|
Usabilidad |
Un nuevo usuario juega por primera vez sin saber las reglas de turnos, la interfaz muestra claramente mediante identificadores visuales cuándo le toca. |
|
Usabilidad |
Una persona que no sabe español accede al juego. No tiene otra opción que jugar en español, lo que dificulta su experiencia de usuario. |
|
Eficiencia de desempeño |
Se quiere jugar una partida rápida, el juego responde rápido a los cambios de ventana y carga de componentes visuales. |
|
Seguridad |
Se accede con una clave no muy segura, se cifran las contraseñas por lo que se añade un grado de seguridad. |
|
Mantenibilidad |
Nos comunican que hay un nuevo requisito en la interfaz y que además se ha añadido una regla, son facilmente indentificables las zonas responsables de cada tarea. |
|
Accesibilidad |
Tratamos de compartir la aplicación con alguien y en vez de proporcionar una IP difícil de recordar le facilitamos su DNS, yovies4a.duckdns.org, lo que facilita su acceso. |
|
Adecuación funcional |
Un usuario quiere jugar contra otro usuario en local. El sistema establece turnos de juego para cada jugador en la misma máquina. |
11. Riesgos y Deudas Técnicas
En esta sección se describen los riesgos encontrados en el desarrollo del proyecto y las soluciones propuestas.
| Riesgo | Descripción | Solución |
|---|---|---|
Mezcla de lengueajes |
Para este proyecto se usa Rust, Node.js y React, añadiendo dificultad extra ya que utilizan lenguajes con los que no estamos familiarizados, además de que el proyecto tiene equipos marcados para sección. |
Estar al tanto revisando el trabajo todos de todos, respondiendo pull request y manteniendo en cada sección una documentación clara y un seguimiento del proyecto exhaustivo. |
Curva de aprendizaje de Rust |
Se trata de un lenguaje complejo con el que levantar un proyecto de cero sin conocer su sintaxis y funcionamiento puede suponer un retraso. |
Documentarse muy bien, tomar ejemplos de otros proyectos y apoyarse en la IA como guía. Se empezó implementando algoritmos con dificultades más leves para ir mejorándolos. |
Tiempos de carga elevados |
El juego utiliza un algoritmo de búsqueda en el que se valoran las mejores opciones recorriendo repetidamente un arbol, lo que puede costar tiempos elevados de carga y hacer que se cuelgue el contenedor. |
Implementar límites de tiempo de respuesta. |
Seguridad en el servicio de usuarios |
Para acceder al juego hay que pasar por una ventana de registro en la que el usuario debe introducir sus datos. |
Se implementan dos medidas, la primera de verificación de integridad, para que el usuario corrobore que tiene acceso al correo que está usando se emplea una verificación en dos pasos. La segunda es que en nuestra base de datos almacenamos codigos hash creados a partir de la contraseña del usuario, por lo que no disponemos de su contraseña real. Además de todo esto, la interfaz bloquea acciones que pueden desencadenar en error, como dejar campos vacíos. |
12. Glosario
| Term | Definition |
|---|---|
Arc42 |
Plantilla de arquitectura de software utilizada para estructurar y documentar las decisiones de diseño de este proyecto. |
Docker Compose |
Herramienta utilizada para orquestar la ejecución simultánea de los servicios webapp, users y gamey, definiendo sus redes y puertos en un solo archivo de configuración. |
SPA (Single Page Application) |
Arquitectura del frontend (webapp) construida con React y Vite, donde la aplicación se carga una sola vez y actualiza dinámicamente el contenido sin recargar la página. |
Coordenadas Baricéntricas |
Sistema de coordenadas (x, y, z) utilizado para representar posiciones en el tablero triangular. Cumplen la restricción x + y + z = N - 1, lo que facilita el cálculo de distancias a los lados del triángulo. |
MCTS (Monte Carlo Tree Search) |
Algoritmo probabilístico que decide el mejor movimiento ejecutando miles de partidas aleatorias desde el estado actual para estimar estadísticamente la probabilidad de victoria. |
YEN (Y Exchange Notation) |
Formato de serialización basado en JSON inspirado en FEN. Representa el estado completo de una partida (tablero, turno, jugadores) para su almacenamiento o transmisión. |
Hashing |
Proceso de transformar una contraseña en una cadena de caracteres irreversible mediante algoritmos (como bcrypt) para almacenarla de forma segura en la base de datos. |
2FA (Autenticación de Dos Factores) |
Capa de seguridad adicional que requiere que el usuario confirme su identidad a través de un segundo método (en nuestro caso, un enlace de verificación enviado por correo electrónico). |
Token |
Código único y temporal generado por el backend que se envía al usuario para validar una acción específica, como la activación de una cuenta. |
SMTP (Simple Mail Transfer Protocol) |
Protocolo estándar de red utilizado para el envío de correos electrónicos desde el microservicio de usuarios hacia los clientes. |
