Skip to main content

Visión general del sistema

ABA está pensado como una cadena de capas donde cada una tiene una sola responsabilidad — el backend nunca decide, solo despacha.

NavegadorReact SPA — cookies JWT + XSRF-TOKEN
NginxProxy inverso, TLS, rate limiting
.NET 9 Web API"Tonto pero no débil" — auth, rate limiting, despacho
SQL Server"MasterControl" — toda la lógica como SPs/Vistas

Desde MasterControl se dirige el aprovisionamiento real en MySQL (motor externo — una base + un usuario por estudiante).

Por qué dos motores de base de datos

  • SQL Server (MasterControl) es el plano de control: usuarios, auditoría, y el registro de cada base de datos aprovisionada. Corre dentro del presupuesto de RAM del VPS junto al backend y Nginx.
  • MySQL es el motor de destino de cada base de datos por estudiante — es el "producto" que la plataforma entrega. Es externo al stack principal: el presupuesto de RAM del VPS ya está totalmente asignado a SQL Server + backend + Nginx + sistema operativo, así que agregar un segundo motor pesado en el mismo lugar lo rompería. El backend se conecta a él con una cuenta administrativa de privilegios mínimos, nunca con permisos globales (GRANT ALL ... ON *.*).

Repository Pattern + Inversión de Dependencias

Los controllers del backend dependen únicamente de interfaces (Repositories/Interfaces/). Las implementaciones concretas (Repositories/SqlServer/*) no hacen nada más que invocar Stored Procedures y mapear el resultado a un DTO. Ningún controller ni service abre una conexión SQL directamente ni concatena texto SQL — todo pasa por una llamada parametrizada a un SP.

ControllerRecibe el request, valida forma
InterfaceRepositories/Interfaces/ — lo único que el controller conoce
Implementación SqlServerRepositories/SqlServer/ — invoca el SP, nada más
Stored ProcedureValida reglas de negocio, calcula, decide, audita

Esto significa que agregar una fuente de datos nueva (o cambiar de motor algún día) es cuestión de escribir una nueva implementación de la interfaz — el resto del sistema no se entera.

Ciclo de vida de una base aprovisionada

El estado de una base de datos en MasterControl refleja la realidad en MySQL, nunca una suposición:

EstadoSignificado
PENDIENTEReservado en MasterControl, aún no confirmado en MySQL.
ACTIVAExiste y funciona en MySQL.
error_aprovisionamientoMySQL falló al crear la base; un servicio de reintento la reintenta automáticamente cada 5 minutos con la misma contraseña ya generada.
cuota_excedidaSuperó su límite de espacio; se le revoca escritura en MySQL hasta que el uso vuelva a bajar.

Ninguna base queda marcada como activa en MasterControl sin existir realmente en MySQL — si el paso de aprovisionamiento en MySQL falla, el registro en el plano de control se revierte en la misma operación. No hay estados intermedios inconsistentes.

Seguí con Database-Centric para el porqué de este diseño.