- Updated "Ficha del proyecto UECKO.md" to clarify architectural boundaries and continuity rules. - Revised "README.md" to enhance structure and clarify sources of truth for documentation. - Improved "backend.md" with clearer definitions of responsibilities and architectural layers. - Streamlined "convenciones.md" to emphasize naming conventions and TypeScript best practices. - Enhanced "datos-persistencia.md" to specify persistence rules and data integrity measures. - Updated "frontend.md" to define frontend rules and state management practices. - Refined "testing.md" to clarify testing levels and validation processes. - Revised "vision-general.md" to outline system architecture and module boundaries more clearly.
48 lines
4.2 KiB
Markdown
48 lines
4.2 KiB
Markdown
# Arquitectura backend
|
|
|
|
## Objetivo
|
|
|
|
Definir responsabilidades, contratos y límites del backend. La dirección general de dependencias está en [visión general](vision-general.md).
|
|
|
|
## Capas y composición
|
|
|
|
Domain no conoce Application ni Infrastructure. Application depende de Domain, contratos y Core; no conoce Express, Sequelize ni modelos ORM. Infrastructure depende de Application, Domain y Core.
|
|
|
|
Cada módulo construye explícitamente sus dependencias en su composition root. No se permite Service Locator, DI implícita o mágica ni importar Infrastructure interna de otro módulo.
|
|
|
|
## Entrada, DTOs y contratos HTTP
|
|
|
|
Zod es la fuente única de verdad de los contratos HTTP. Los tipos se infieren mediante `z.infer<typeof Schema>` y no se mantienen interfaces manuales equivalentes. Cada endpoint dispone de DTOs de request y response; los decimales exactos no viajan como `number`.
|
|
|
|
Los schemas expresan semánticamente UUID, fechas, timestamps, porcentajes, importes y cantidades. Deben distinguir campo omitido, `null`, cadena vacía y colección vacía. No se mezclan validación de transporte y lógica de negocio; `.default()` y `.transform()` solo se usan en DTOs de negocio cuando estén justificados.
|
|
|
|
El flujo habitual es:
|
|
|
|
```text
|
|
RequestDTO → UseCase({ dto, context }) → InputMapper → Value Objects / Props
|
|
```
|
|
|
|
`RequestMapper → Command` es opcional y solo procede ante una adaptación HTTP real, como combinar `body`, `params` y `query`. No se crea solo para renombrar campos que Application volverá a transformar.
|
|
|
|
## Application y Domain
|
|
|
|
Los casos de uso orquestan, gestionan transacciones cuando corresponde, delegan en servicios de aplicación, devuelven `Result` y construyen respuestas mediante builders o mappers de salida. No contienen lógica HTTP, ORM, modelos Sequelize ni responsabilidades de controller, repositorio o Infrastructure; tampoco construyen agregados directamente desde DTOs HTTP.
|
|
|
|
Los servicios de aplicación son pequeños, explícitos y de responsabilidad concreta. Se evitan nombres genéricos como `Manager`, `GenericService`, `CommandService`, `BaseRepository` o `Helper` sin semántica.
|
|
|
|
Se usan los patrones del proyecto: `Result` para operaciones que pueden fallar, `Maybe` para ausencia semántica y `Collection` cuando el dominio requiere comportamiento propio para un conjunto homogéneo. Los fallos de negocio esperables no se representan mediante excepciones, `null`, arrays ni tipos ad hoc cuando corresponda uno de esos patrones.
|
|
|
|
`create()` representa creación funcional: valida invariantes, puede fallar y devuelve `Result`. `rehydrate()` reconstruye persistencia válida: no valida creación, no genera eventos y no devuelve `Result`. Infrastructure usa `rehydrate()`; Application y Domain usan `create()` para instancias nuevas. `update()` no usa ninguna de las dos, y los Value Objects se reconstruyen con `create()`.
|
|
|
|
## Repositorios, mappers y respuestas
|
|
|
|
Cada repositorio gestiona un agregado o responsabilidad concreta, no se comparte entre módulos ni se expone como API pública. Los detalles de ORM permanecen en Infrastructure. Los mappers de persistencia e invariantes de almacenamiento se definen en [datos y persistencia](datos-persistencia.md).
|
|
|
|
Los snapshot builders materializan el DTO de salida exacto y se tipan con el tipo inferido del schema. Son deterministas, sin lógica de negocio ni acceso a repositorios o Infrastructure; pueden transformar `Maybe` en `null`, Value Objects en primitivas y enums internos en valores del contrato. No se crean interfaces `I*Snapshot` que dupliquen DTOs.
|
|
|
|
## Errores, seguridad y API
|
|
|
|
Los errores esperables son tipados y predecibles. Domain y Application se mapean a HTTP en Infrastructure sin exponer SQL, stack traces, detalles internos ni información sensible. No se ocultan fallos, no se convierten en éxito para continuar y el logging no sustituye su tratamiento.
|
|
|
|
Toda entrada externa se valida. La autorización se verifica además de la autenticación; no se confía en permisos, compañía o identificadores enviados por el cliente sin contrastarlos con el contexto autenticado. Las consultas y mutaciones preservan aislamiento multiempresa. La idempotencia se aplica a operaciones repetibles según su semántica.
|