Contexto#
Las organizaciones con varias sedes acaban operando sobre una colección de herramientas que no se hablan entre sí: una hoja de cálculo para las personas, otra para las cuentas, un grupo de WhatsApp para coordinar, y la memoria de quien lleva más años para todo lo demás.
El problema no es la falta de software. Es que cada dato vive en un sitio distinto y nadie sabe cuál es el bueno. Cuando alguien pregunta cuántas personas hay activas, o cuánto se recaudó el mes pasado, la respuesta depende de a quién se le pregunte.
SIGEDReino nace para que exista una sola fuente de verdad, con las particularidades de este dominio: varias organizaciones independientes sobre la misma plataforma, jerarquías internas que determinan quién ve qué, y dinero de por medio, que no admite aproximaciones.
Restricciones#
- Multi-tenant desde el día uno. No es una funcionalidad futura: cada organización debe ser incapaz de ver datos de otra, y eso condiciona el modelo de datos y el de seguridad desde la primera línea.
- Tres clientes, un solo dominio. Panel administrativo, portal público y app móvil. Mantener tres definiciones del mismo concepto era garantía de que divergirían.
- Equipo pequeño. Las decisiones que exigen operación continua —bases que administrar, infraestructura que vigilar— se pagan en tiempo que no se dedica a producto.
- Dominio que todavía se está entendiendo. Varios módulos cambiaron de forma durante la construcción, así que la arquitectura tenía que tolerar que el negocio cambiara de opinión.
Arquitectura#
Monorepo con pnpm y Turborepo. Un backend NestJS con arquitectura hexagonal por módulo, tres aplicaciones cliente, y paquetes compartidos que llevan el contrato y las primitivas de dominio.
Cada módulo del backend tiene la misma estructura, y una única regla la
sostiene: domain/ no importa nada, application/ importa domain/,
infrastructure/ importa ambas. Nunca al revés.
Ejecución#
Veinte módulos de dominio —personas, membresías, tesorería, gobierno, eventos, notificaciones, facturación, entre otros—, cada uno con sus entidades, sus casos de uso y sus códigos de error propios.
Los casos de uso devuelven un Result en lugar de lanzar excepciones. Una regla
de negocio incumplida no es un error del programa, es un resultado posible; y
tratarla como excepción obliga a envolver medio código en try/catch para
distinguir "el gasto no estaba pendiente" de "la base de datos se cayó".
Los tres clientes consumen el mismo api-contracts, así que renombrar un campo
rompe su build en el mismo commit. Con una trampa que costó encontrar: el
backend externaliza ese paquete al empaquetar, de modo que puede importar sus
tipos pero no sus valores en tiempo de ejecución. Los enums que necesita
viven duplicados en su dominio, con un test que falla si las dos copias
divergen.
La interfaz sale de un design system propio: uno para web sobre Radix y Tailwind, otro nativo sobre NativeWind. No comparten componentes —no pueden— pero sí tokens, escala tipográfica y nombres de variantes.
Resultado#
El sistema está en desarrollo activo, con los módulos de identidad, personas, membresías y tesorería operativos en entorno de pruebas.
Lo que ya se puede afirmar es estructural: veinte módulos con fronteras verificadas por herramienta, tres aplicaciones que comparten dominio sin duplicarlo, y tres idiomas cuya paridad valida un test en cada ejecución. Las cifras de uso llegarán cuando el sistema entre en producción, y este caso se actualizará entonces con datos reales en lugar de proyecciones.