3.4 KiB
Arquitectura backend
Estado: NORMATIVO. Esta es la fuente de verdad de la arquitectura general del backend.
Stack y principios
El backend usa Node.js, TypeScript, Express, MariaDB, Sequelize v6, Zod v4, PNPM y Turborepo. Las versiones soportadas se consultan en el package.json raíz y en los paquetes del workspace.
Se aplica DDD pragmático y Clean Architecture sin convertir cada principio en una capa adicional. Las decisiones favorecen SOLID, KISS, YAGNI, SSOT, fail fast, programación defensiva y claridad semántica antes que abstracciones prematuras.
Result representa fallos esperables; Maybe representa ausencia semántica. Las excepciones no son el flujo normal de validación.
Capas y dirección de dependencias
Infrastructure → Application → Domain
- Domain no conoce Application ni Infrastructure. Contiene agregados, entidades, Value Objects e invariantes.
- Application conoce Domain, Core y contratos necesarios. Orquesta casos de uso y servicios, pero no conoce Express, Sequelize ni modelos ORM.
- Infrastructure implementa puertos y contiene HTTP, Sequelize, mappers de persistencia y composition roots.
- common contiene contratos compartibles entre backend y web, especialmente DTOs de API. No es una vía para filtrar infraestructura.
Quedan prohibidas las dependencias en dirección inversa, en especial Application → Infrastructure.
Responsabilidades de aplicación e infraestructura
Los casos de uso orquestan, gestionan transacciones cuando corresponde, delegan en servicios y devuelven Result. No contienen lógica HTTP ni acceden a Sequelize directamente.
Los repositorios pertenecen a Infrastructure, gestionan una responsabilidad o agregado concreto y usan mappers de persistencia. Un mapper de persistencia bidireccional expone típicamente toPersistence() y toDomain(); Infrastructure reconstruye con rehydrate(). La creación funcional se realiza con create() y valida invariantes.
Los builders de salida materializan contratos definidos por schemas Zod. Son deterministas, no acceden a repositorios y pueden convertir Value Objects a primitivas o Maybe a null.
Referencias normativas relacionadas
- Inyección de dependencias
- Flujo HTTP y entrada a Application
- DTOs y schemas
- Límites entre módulos
- Pruebas backend
Alcance empresarial de persistencia
Toda mutación de entidad empresarial debe expresar el alcance en el puerto y en la condición
efectiva de escritura, no solo en una lectura previa. El patrón actualizado de Customers/catálogos/
proformas es update(companyId, aggregate, transaction) con WHERE id AND company_id.
No incluir company_id entre campos reasignables. Los puertos save(aggregate, transaction)
de series/recurrencias llevan el alcance inmutable en el agregado: tampoco pueden hacer un upsert
por PK que traslade la raíz a otra empresa. La lectura interna de colisión no autoriza la escritura.
Cero filas exige distinguir ausencia de no-op usando únicamente el mismo alcance y transacción;
no revelar existencia en otra empresa. Comprobar la raíz antes de sustituir sus hijos. Conservar
resolvers de pertenencia, invariantes y auditoría. Companies es la propia raíz empresarial: su PK
es la empresa y no necesita una columna company_id artificial.