FactuGES_ERP/docs/architecture/backend-architecture.md

55 lines
3.4 KiB
Markdown
Raw Normal View History

# 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
```text
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](./dependency-injection.md)
- [Flujo HTTP y entrada a Application](./http-request-flow.md)
- [DTOs y schemas](./dto-guidelines.md)
- [Límites entre módulos](./module-boundaries.md)
- [Pruebas backend](./testing-guidelines.md)
2026-10-16 17:00:01 +00:00
## 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.