- 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.
4.2 KiB
Arquitectura backend
Objetivo
Definir responsabilidades, contratos y límites del backend. La dirección general de dependencias está en visión general.
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:
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.
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.