From 8c738048166d067fa07feed68a2eccb96701e2fd Mon Sep 17 00:00:00 2001 From: David Date: Thu, 17 Sep 2026 23:00:38 +0200 Subject: [PATCH] =?UTF-8?q?Mejorar=20la=20documentaci=C3=B3n=20de=20arquit?= =?UTF-8?q?ectura=20y=20convenciones=20del=20proyecto?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AGENTS.md | 2 +- docs/Ficha del proyecto UECKO.md | 10 +++------- docs/arquitectura/backend.md | 24 ++++++++++++------------ docs/arquitectura/convenciones.md | 10 ++++++++++ docs/arquitectura/datos-persistencia.md | 10 +++++----- docs/arquitectura/frontend.md | 8 ++++---- docs/arquitectura/vision-general.md | 4 ++-- 7 files changed, 37 insertions(+), 31 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 61bba47..8661b20 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -77,7 +77,7 @@ Añadir o actualizar tests cuando cambie comportamiento observable. Informar exa Un refactor preserva comportamiento salvo indicación expresa. Para uno grande: auditar, identificar consumidores, dividir en fases y validar entre ellas. -Antes de eliminar legacy, buscar referencias en todo el monorepo y revisar imports, rutas, entry points, composition roots, DI, modelos, repositorios, mappers, tests, scripts y documentación. Eliminar solo lo demostrado como no utilizado y documentar referencias residuales justificadas. +Antes de eliminar legacy, buscar referencias en todo el monorepo y revisar imports, rutas, entry points, composition roots, DI, modelos, repositorios, mappers, tests, scripts y documentación. Cuando resulte relevante, clasificar las referencias como activas, legacy no cableado, migraciones, documentación, tests o falsos positivos. Eliminar solo lo demostrado como no utilizado, documentar referencias residuales justificadas y ejecutar las validaciones relevantes después. No modificar manualmente archivos generados; utilizar su procedimiento oficial y no incluir artefactos no relacionados. diff --git a/docs/Ficha del proyecto UECKO.md b/docs/Ficha del proyecto UECKO.md index 7961d7e..4aa3cc8 100644 --- a/docs/Ficha del proyecto UECKO.md +++ b/docs/Ficha del proyecto UECKO.md @@ -62,7 +62,7 @@ La aplicación y la base de datos deben mantenerse separadas conceptualmente: * Una actualización de la aplicación no puede sobrescribir ni eliminar información operativa o histórica. * Los datos deben sobrevivir a cualquier cambio de versión. * Los cambios de estructura de datos deben realizarse mediante actualizaciones controladas. -* Antes de modificar la estructura de datos debe existir una copia de seguridad recuperable. +* Antes de modificar la estructura de datos debe existir una copia de seguridad recuperable y un mecanismo de restauración o rollback que no dependa de conocimientos técnicos del usuario Máster. * Las nuevas versiones no pueden exigir reintroducir manualmente datos históricos. * Las ampliaciones futuras deben integrarse sobre la base existente sin reconstruir usuarios, históricos ni datos comunes. * Las migraciones de datos y actualizaciones deben quedar registradas. @@ -160,16 +160,12 @@ El respaldo técnico y los documentos funcionales de Oficina Comercial y Oficina ## 8. Restricciones importantes -* No debe perderse información existente como consecuencia de una actualización. +Toda actualización debe cumplir los límites de continuidad, preservación del histórico, backup, rollback y validación Beta definidos en la sección de Arquitectura. + * No deben sobrescribirse ni eliminarse usuarios, expedientes, OF, tareas, imputaciones de tiempo, errores, históricos, registros de actividad ni configuraciones funcionales durante una actualización. -* Debe mantenerse compatibilidad con los datos existentes entre versiones. -* Ninguna evolución futura debe requerir la reintroducción manual de datos históricos. -* Antes de cualquier cambio estructural de base de datos debe existir una copia de seguridad recuperable. * Toda actualización debe realizar una copia automática de seguridad cuando corresponda. -* Debe existir un mecanismo de restauración o rollback que no dependa de conocimientos técnicos del usuario Máster. * La aplicación debe impedir la instalación de paquetes de actualización no válidos o incompatibles. * En la primera etapa, las actualizaciones se distribuyen como paquetes completos de versión, no como conjuntos de archivos sueltos. -* Las modificaciones relevantes deben poder validarse en Beta antes de pasar a Producción. * El perfil Informática / Soporte no debe modificar por defecto reglas funcionales del negocio. * El perfil Desarrollador no debe modificar directamente datos de Producción fuera de los mecanismos previstos. * Los módulos no deben modificar datos propiedad de otros módulos salvo permiso expreso. diff --git a/docs/arquitectura/backend.md b/docs/arquitectura/backend.md index cdca42c..ef98caf 100644 --- a/docs/arquitectura/backend.md +++ b/docs/arquitectura/backend.md @@ -6,15 +6,15 @@ Definir responsabilidades, contratos y límites del backend. La dirección gener ## 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. +Domain no debe conocer Application ni Infrastructure. Application debe depender de Domain, contratos y Core; no debe conocer Express, Sequelize ni modelos ORM. Infrastructure puede depender 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. +Cada módulo debe construir 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`. +Zod se establece como fuente única de verdad de los contratos HTTP. Los tipos deben inferirse mediante `z.infer` y no se mantienen interfaces manuales equivalentes. Cada endpoint debe disponer 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. +Los schemas deben expresar semánticamente UUID, fechas, timestamps, porcentajes, importes y cantidades, y 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. Los subschemas solo se reutilizan cuando sean realmente estables y compartidos. El flujo habitual es: @@ -26,22 +26,22 @@ RequestDTO → UseCase({ dto, context }) → InputMapper → Value Objects / Pro ## 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 casos de uso deben orquestar, gestionar transacciones cuando corresponde, delegar en servicios de aplicación, devolver `Result` y construir 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. +Los servicios de aplicación deben ser 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. +Se establecen 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()`. +`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 debe usar `rehydrate()`; Application y Domain deben usar `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). +Cada repositorio debe gestionar un agregado o responsabilidad concreta, no compartirse entre módulos ni exponerse como API pública. No se crean repositorios base genéricos sin necesidad demostrada. Los detalles de ORM deben permanecer 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. +Los snapshot builders deben materializar el DTO de salida exacto y tiparse con el tipo inferido del schema, de modo que un cambio incompatible del schema produzca un error de compilación. 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. +Los errores esperables deben ser tipados y predecibles. Domain y Application se mapean a HTTP en Infrastructure sin exponer SQL, stack traces, detalles internos ni información sensible. Los errores deben conservar contexto suficiente para diagnosticar el fallo. No se ocultan fallos, no se convierten en éxito para continuar y el logging no sustituye su tratamiento. Las APIs y servicios deben mantener observabilidad suficiente para investigar fallos relevantes sin exponer información sensible. -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. +Toda entrada externa debe validarse. 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 deben preservar aislamiento multiempresa. La idempotencia se aplica a operaciones repetibles según su semántica. diff --git a/docs/arquitectura/convenciones.md b/docs/arquitectura/convenciones.md index 8bf7631..68a88dc 100644 --- a/docs/arquitectura/convenciones.md +++ b/docs/arquitectura/convenciones.md @@ -10,6 +10,16 @@ Las convenciones existentes del área prevalecen sobre introducir una variación aislada. +## Principios de diseño + +Aplicar pragmáticamente SOLID, Clean Code, DRY, KISS, YAGNI, SSOT, Fail Fast, programación defensiva, inmutabilidad cuando resulte adecuada, idempotencia, menor privilegio y observabilidad en APIs y servicios. Son criterios de diseño, no motivos por sí solos para refactorizar código ajeno ni crear abstracciones prematuras; prevalecen los patrones existentes adecuados y el contexto. + +```text +claridad y explicitud + > +abstracción prematura +``` + ## TypeScript Preservar la seguridad de tipos. Usar `import type` para símbolos utilizados exclusivamente como tipos y mantenerlos en la cabecera; no usar imports runtime innecesarios ni referencias inline salvo en `.d.ts`, module augmentation, código generado o casos técnicamente justificados. diff --git a/docs/arquitectura/datos-persistencia.md b/docs/arquitectura/datos-persistencia.md index 8bb835d..086ed4b 100644 --- a/docs/arquitectura/datos-persistencia.md +++ b/docs/arquitectura/datos-persistencia.md @@ -6,20 +6,20 @@ Definir las reglas de persistencia, integridad y evolución de datos. MariaDB y ## Límites de persistencia -Sequelize y sus modelos permanecen en Infrastructure; no forman contratos públicos ni se acceden desde Domain o Application. Cada repositorio gestiona un agregado o responsabilidad concreta y usa un mapper bidireccional por agregado: +Sequelize y sus modelos deben permanecer en Infrastructure; no forman contratos públicos ni se acceden desde Domain o Application. Los nombres de tablas y columnas deben mantenerse coherentes con las convenciones existentes del proyecto. Cada repositorio gestiona un agregado o responsabilidad concreta y usa un mapper bidireccional por agregado: ```ts toPersistence(); toDomain(); ``` -El mapper traduce representación de dominio y persistida, sin añadir lógica de negocio. Infrastructure reconstruye entidades mediante `rehydrate()`. +El mapper debe traducir representación de dominio y persistida, sin añadir lógica de negocio. Infrastructure reconstruye entidades mediante `rehydrate()`. ## Transacciones e integridad -Las operaciones agregadas se ejecutan en transacción cuando deben ser atómicas. Al modificar persistencia o lógica transaccional se comprueban atomicidad, consistencia, rollback, concurrencia, aislamiento, integridad referencial y compatibilidad con datos existentes. Una escritura satisfactoria no garantiza por sí sola que haya terminado la operación funcional completa. +Las operaciones agregadas deben ejecutarse en transacción cuando deben ser atómicas. Al modificar persistencia o lógica transaccional se comprueban atomicidad, consistencia, rollback, concurrencia, aislamiento, integridad referencial y compatibilidad con datos existentes. Una escritura satisfactoria no garantiza por sí sola que haya terminado la operación funcional completa. -Las invariantes críticas se refuerzan también en base de datos cuando resulte razonable. Las consultas y mutaciones preservan el aislamiento por `companyId` y `branchId` cuando corresponda y usan consultas parametrizadas o APIs seguras de Sequelize. +Las invariantes críticas se refuerzan también en base de datos cuando resulte razonable. Las consultas y mutaciones deben preservar el aislamiento por `companyId` y `branchId` cuando corresponda y usar consultas parametrizadas o APIs seguras de Sequelize. ## Concurrencia e idempotencia @@ -31,7 +31,7 @@ No usar `JSON.stringify` para detectar cambios de dominio; los Value Objects se Los cambios estructurales se realizan mediante mecanismos controlados. Las migraciones preservan datos e histórico, no exigen reintroducción manual de información y son idempotentes cuando el procedimiento lo requiera. No eliminar columnas, tablas o datos legacy sin auditoría previa. -Las actualizaciones no destruyen ni sobrescriben datos operativos o históricos. Antes de un cambio estructural debe existir copia de seguridad recuperable; cuando corresponda, la actualización realiza copia automática y permite restauración o rollback sin depender de conocimientos técnicos del usuario Máster. Las migraciones y actualizaciones quedan registradas. Los cambios relevantes se validan en Beta antes de Producción. +Las reglas funcionales de continuidad del histórico, actualización sin pérdida, backup, rollback y validación Beta se definen en la [Ficha del proyecto UECKO](../Ficha%20del%20proyecto%20UECKO.md). Para cumplirlas, la persistencia debe proporcionar mecanismos técnicos de copia recuperable y restauración o rollback antes de cambios estructurales cuando corresponda; las migraciones y actualizaciones deben quedar registradas. Los cambios relevantes deben poder validarse en Beta antes de Producción. No se elimina físicamente información con histórico cuando proceda desactivarla, incluidos tareas y grupos funcionales. Deben preservarse usuarios, expedientes, OF, tareas, imputaciones, errores, históricos, actividad, configuraciones y trazabilidad. diff --git a/docs/arquitectura/frontend.md b/docs/arquitectura/frontend.md index 2c321c4..1f0d617 100644 --- a/docs/arquitectura/frontend.md +++ b/docs/arquitectura/frontend.md @@ -6,14 +6,14 @@ Definir las reglas de frontend. React, TanStack Query, TanStack Table, React Hoo ## Estado y datos remotos -Las operaciones de servidor permanecen en TanStack Query. No duplicar estado remoto en estado local sin necesidad; las query keys siguen la convención existente y, tras mutaciones, la caché se invalida o actualiza explícitamente. No introducir efectos para derivar durante render estado que pueda calcularse directamente. +Las operaciones de servidor deben permanecer en TanStack Query. No duplicar estado remoto en estado local sin necesidad; las query keys deben seguir la convención existente y, tras mutaciones, la caché se invalida o actualiza explícitamente. No introducir efectos para derivar durante render estado que pueda calcularse directamente. ## Formularios y componentes -Los formularios usan React Hook Form y Zod conforme a los patrones existentes. Los componentes evitan responsabilidad monolítica: se extraen responsabilidades cuando exista una frontera semántica clara, no para ocultar JSX trivial. Usar shadcn/ui y Tailwind según los patrones del área. +Los formularios deben usar React Hook Form y Zod conforme a los patrones existentes. Los componentes evitan responsabilidad monolítica: se extraen responsabilidades cuando exista una frontera semántica clara, no para ocultar JSX trivial. Usar shadcn/ui y Tailwind según los patrones del área. ## UI, accesibilidad e internacionalización -La interfaz contempla estados `disabled`, `loading`, `empty` y `error`, conserva acciones no disponibles deshabilitadas cuando la UX requiera mostrarlas y preserva comportamiento responsive y accesibilidad. +La interfaz debe contemplar estados `disabled`, `loading`, `empty` y `error`, conservar acciones no disponibles deshabilitadas cuando la UX requiera mostrarlas y preservar comportamiento responsive y accesibilidad. -Los textos visibles se mantienen en `es` y `en` cuando el área use i18n; no se insertan directamente en ese caso. Las columnas monetarias usan `tabular-nums` cuando corresponda. +Los textos visibles deben mantenerse en `es` y `en` cuando el área use i18n; no se insertan directamente en ese caso. Las columnas monetarias usan `tabular-nums` cuando corresponda. diff --git a/docs/arquitectura/vision-general.md b/docs/arquitectura/vision-general.md index c8d06ba..477f355 100644 --- a/docs/arquitectura/vision-general.md +++ b/docs/arquitectura/vision-general.md @@ -12,7 +12,7 @@ Los módulos pueden consultar información ajena cuando sea necesario, pero solo ## Estilo y límites -El backend sigue DDD pragmático, Clean Architecture y arquitectura hexagonal. Se priorizan claridad y explicitud frente a abstracción prematura; esos principios no justifican crear capas, adaptadores, factories, genéricos, eventos o contenedores de DI sin una necesidad actual. +La arquitectura definida para el backend sigue DDD pragmático, Clean Architecture y arquitectura hexagonal. Se priorizan claridad y explicitud frente a abstracción prematura; esos principios no justifican crear capas, adaptadores, factories, genéricos, eventos o contenedores de DI sin una necesidad actual. La dirección general de dependencias es: @@ -28,7 +28,7 @@ Infrastructure depende de Application, Domain y Core ``` -Cada módulo mantiene su propio composition root, que construye explícitamente sus dependencias. No se permite Service Locator ni DI implícita o mágica. Antes de cambiar una frontera arquitectónica se deben identificar productores, consumidores y efectos derivados. +Cada módulo debe mantener su propio composition root, que construya explícitamente sus dependencias. No se permite Service Locator ni DI implícita o mágica. Antes de cambiar una frontera arquitectónica se deben identificar productores, consumidores y efectos derivados. ## Límites transversales