FactuGES_ERP/docs/architecture/backend-architecture.md

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

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.