# 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` 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.