FactuGES_ERP/docs/settings/frontend-erp-settings-module-integration-design.md
2026-08-11 18:02:16 +02:00

10 KiB
Raw Blame History

Frontend ERP – Integración de módulos con Settings

1. Propósito

Este documento complementa Frontend ERP – Sistema modular de Settings y define cómo debe integrarse un módulo funcional con /settings sin acoplarse al shell de aplicación ni a otros módulos.

Aplica a módulos actuales y futuros que necesiten exponer configuración de la empresa activa.

Ejemplos:

customer-invoices
  → VeriFactu

document-series
  → Series documentales

identity/company
  → Datos de empresa

módulo de certificados
  → Certificados

2. Principio operativo

Módulo
→ declara metadata de Settings
→ registra su propia route
→ implementa su propia Page
→ mantiene su propia persistencia

El shell únicamente descubre y presenta la opción.


3. Separación de responsabilidades

Settings shell

Conoce:

id de sección
label
descripción
orden
path
permiso

No conoce:

DTO
Entity
Controller
formulario
endpoint
reglas de negocio

Módulo

Conoce:

routing concreto
Page/Page Controller
controllers
shared/api
shared/adapters
shared/entities
shared/hooks
validación
persistencia
reglas de negocio

4. Flujo completo

Module manifest
      │
      │ settings contribution
      ▼
SettingsRegistry
      │
      ▼
SettingsNavigation
      │
      │ usuario navega
      ▼
/settings/<section>/<entry>
      │
      ▼
Route del módulo
      │
      ▼
Settings Page del módulo
      │
      ▼
Page Controller
      │
      ▼
Controller
      │
      ▼
shared/hooks
      │
      ▼
shared/api

La cadena de datos del módulo sigue siendo:

API → DTO → Adapter → Entity → Hook → Controller → Page Controller → UI

5. Metadata mínima del módulo

Contrato conceptual:

export interface ModuleSettingsSectionContribution {
  id: string;
  labelKey: string;
  order?: number;
}

export interface ModuleSettingsEntryContribution {
  id: string;
  sectionId: string;

  labelKey: string;
  descriptionKey?: string;

  path: string;

  order?: number;
  permission?: string;
}

Ejemplo conceptual:

export const customerInvoicesManifest = {
  settings: {
    sections: [
      {
        id: "billing",
        labelKey: "settings.sections.billing",
        order: 200,
      },
    ],

    entries: [
      {
        id: "verifactu",
        sectionId: "billing",
        labelKey: "customerInvoices.settings.verifactu.title",
        descriptionKey: "customerInvoices.settings.verifactu.description",
        path: "/settings/billing/verifactu",
        order: 100,
        permission: "customerInvoices.settings.verifactu.manage",
      },
    ],
  },
};

El shape definitivo debe adaptarse al manifest real del repositorio.


6. Regla de routing

Una contribución de Settings no debe registrar un componente React directamente.

Incorrecto:

{
  id: "verifactu",
  component: VerifactuSettingsPage,
}

Correcto conceptualmente:

{
  id: "verifactu",
  path: "/settings/billing/verifactu",
}

Y en el routing propio del módulo:

/settings/billing/verifactu
→ VerifactuSettingsPage

El shell y el módulo se acoplan únicamente mediante una ruta estable.


7. Ubicación de código dentro del módulo

La ubicación concreta debe seguir la estructura real del módulo.

Dirección conceptual recomendada:

[module]/
├── manifest.ts
├── [module]-routes.tsx
├── shared/
│   ├── api/
│   ├── adapters/
│   ├── entities/
│   └── hooks/
│
└── settings/
    └── [setting]/
        ├── controllers/
        ├── entities/
        ├── ui/
        └── index.ts

No introducir esta estructura si el módulo real ya tiene una convención equivalente mejor establecida.


8. Page Controller

Una página de settings debe seguir la misma regla que el resto del ERP.

Responsabilidades del Page Controller:

integrar contexto externo
componer controllers
integrar navegación si aplica
exponer API estructurada a la Page

No debe:

transportar DTO
realizar llamadas API directas
contener lógica visual

9. Controller

Responsable de:

estado del caso de uso
formulario
submit
validaciones de flujo
side effects
coordinación con hooks de shared

No debe:

usar useParams/useNavigate directamente
usar DTO
conocer el SettingsRegistry

10. Shared

Una configuración de módulo reutiliza las reglas generales de shared/.

shared/api
→ transporte remoto

shared/adapters
→ DTO ↔ Entity cuando corresponda

shared/entities
→ contratos frontend

shared/hooks
→ React Query

El hecho de que la UI aparezca bajo /settings no cambia estas responsabilidades.


11. Persistencia

Cada módulo decide su persistencia.

No utilizar por defecto un almacenamiento genérico de Settings.

Ejemplos:

VeriFactu
→ configuración persistida del dominio correspondiente

Series documentales
→ agregado DocumentSeries

Datos de empresa
→ Company/Identity

La navegación compartida no implica almacenamiento compartido.


12. Empresa activa

Toda configuración integrada en /settings pertenece a la empresa activa.

Un módulo no debe introducir su propio selector de empresa si la aplicación ya dispone de contexto global.

La query/mutation debe usar la infraestructura existente para resolver la empresa activa.

Cuando cambie la empresa activa:

los datos visibles deben corresponder a la nueva empresa

La implementación exacta depende de cómo estén construidas actualmente las query keys, headers y mecanismos de invalidación.


13. Permisos

La contribución puede declarar:

permission?: string;

El permiso solo controla la disponibilidad de la navegación frontend.

La operación backend debe seguir autorizándose independientemente.

Un módulo no debe implementar un segundo sistema de permisos para Settings.


14. i18n

La metadata debe usar claves de traducción.

Ejemplo:

labelKey: "customerInvoices.settings.verifactu.title";
descriptionKey: "customerInvoices.settings.verifactu.description";

El módulo mantiene sus traducciones.

La sección compartida puede usar una key común del shell si el diseño final establece un catálogo global de secciones.


15. UI

La página del módulo debe usar el sistema visual Rdx vigente.

El shell proporciona:

layout
navegación
título general de Configuración

El módulo proporciona:

título específico
contenido
formularios
acciones
loading/error states

Evitar duplicar dentro del módulo el sidebar global de Settings.


16. Guardado

Cada setting debe guardar de forma independiente.

Ejemplo:

VeriFactu
[Cancelar] [Guardar]

No existe un submit global de /settings.

Si la pantalla tiene varios bloques pero forman una única configuración transaccional, el módulo puede resolverlos con un único formulario/controlador.


17. Loading y errores

El módulo conserva responsabilidad sobre:

loading inicial
error inicial
refetch error
submit error
validation errors
retry

El shell no interpreta errores de dominio.

Debe reutilizarse el patrón consolidado de PageErrorState, ErrorAlert y errores de formulario cuando corresponda.


18. Unsaved changes

Cada módulo es responsable de avisar o bloquear navegación cuando existan cambios no guardados.

No crear un estado dirty global dentro del Settings shell.


19. Deep linking

Una entrada debe ser accesible directamente por URL.

Ejemplo:

/settings/billing/verifactu

El módulo no debe depender de que el usuario haya visitado antes /settings.


20. Varias contribuciones a una misma sección

Ejemplo:

customer-invoices

billing
└── VeriFactu

document-series

billing
└── Series documentales

Resultado:

Facturación
├── VeriFactu
└── Series documentales

Los módulos no se importan entre sí.


21. Caso piloto: VeriFactu

El primer setting real será VeriFactu.

Su contribución debe limitarse a metadata:

section
entry
path
orden
permiso si existe

La implementación funcional de VeriFactu debe documentarse en un documento específico posterior.

Este documento específico deberá explicar:

estado/configuración de la empresa
onboarding inicial
valores por defecto de facturación
certificados si pertenecen al mismo dominio
snapshot de IssuedInvoice
API
DTOs
Entities
controllers
UI

sin redefinir el framework de Settings.


22. Checklist para añadir un setting nuevo

Manifest

  • Declara sección si es necesaria.
  • Declara entry con id estable.
  • Usa labelKey.
  • Usa descriptionKey si aporta valor.
  • Declara path estable.
  • Declara order cuando importe el orden semántico.
  • Declara permission solo si existe permiso real.

Routing

  • La route pertenece al módulo.
  • Funciona mediante deep-link.
  • No requiere estado previo del shell.

Arquitectura

  • API → DTO → Adapter → Entity → Hook → Controller → Page Controller → UI.
  • No hay DTO en UI/controller.
  • No hay routing en controller.
  • No hay dependencia del SettingsRegistry en dominio/shared.

UI

  • Usa sistema visual Rdx.
  • No duplica SettingsNavigation.
  • Soporta teclado y focus-visible.
  • Maneja loading/error/empty correctamente.

Empresa

  • Usa la empresa activa existente.
  • No introduce un selector paralelo.
  • El cambio de empresa no deja datos stale de la anterior.

Seguridad

  • La navegación respeta permisos frontend.
  • El backend valida autorización de forma independiente.

23. Anti-patterns

No hacer:

importar SettingsPage desde el shell
registrar componentes React como metadata principal
crear un GenericSettingsForm
crear un GenericSettingsRepository
usar localStorage para configuración de negocio
crear otro selector de company
hacer imports entre módulos para agrupar settings
usar un switch central por setting

24. Regla mental final

El módulo declara que su setting existe.
El shell decide cómo descubrirlo y mostrarlo.
El router decide cómo llegar.
El módulo decide cómo funciona.

Criterio de validación:

Si para añadir una nueva configuración hay que modificar SettingsPage,
SettingsNavigation o un switch central, la integración está mal diseñada.