Documentación de settings

This commit is contained in:
David Arranz 2026-08-11 18:02:16 +02:00
parent a0bd39c2a5
commit 4b041db8da
2 changed files with 1996 additions and 0 deletions

View File

@ -0,0 +1,614 @@
# 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:
```txt
customer-invoices
→ VeriFactu
document-series
→ Series documentales
identity/company
→ Datos de empresa
módulo de certificados
→ Certificados
```
---
## 2. Principio operativo
```txt
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:
```txt
id de sección
label
descripción
orden
path
permiso
```
No conoce:
```txt
DTO
Entity
Controller
formulario
endpoint
reglas de negocio
```
### Módulo
Conoce:
```txt
routing concreto
Page/Page Controller
controllers
shared/api
shared/adapters
shared/entities
shared/hooks
validación
persistencia
reglas de negocio
```
---
## 4. Flujo completo
```txt
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:
```txt
API → DTO → Adapter → Entity → Hook → Controller → Page Controller → UI
```
---
## 5. Metadata mínima del módulo
Contrato conceptual:
```ts
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:
```ts
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:
```ts
{
id: "verifactu",
component: VerifactuSettingsPage,
}
```
Correcto conceptualmente:
```ts
{
id: "verifactu",
path: "/settings/billing/verifactu",
}
```
Y en el routing propio del módulo:
```txt
/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:
```txt
[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:
```txt
integrar contexto externo
componer controllers
integrar navegación si aplica
exponer API estructurada a la Page
```
No debe:
```txt
transportar DTO
realizar llamadas API directas
contener lógica visual
```
---
## 9. Controller
Responsable de:
```txt
estado del caso de uso
formulario
submit
validaciones de flujo
side effects
coordinación con hooks de shared
```
No debe:
```txt
usar useParams/useNavigate directamente
usar DTO
conocer el SettingsRegistry
```
---
## 10. Shared
Una configuración de módulo reutiliza las reglas generales de `shared/`.
```txt
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:
```txt
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:
```txt
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:
```ts
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:
```ts
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:
```txt
layout
navegación
título general de Configuración
```
El módulo proporciona:
```txt
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:
```txt
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:
```txt
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:
```txt
/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
```txt
billing
└── VeriFactu
```
### document-series
```txt
billing
└── Series documentales
```
Resultado:
```txt
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:
```txt
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:
```txt
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:
```txt
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
```txt
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:
```txt
Si para añadir una nueva configuración hay que modificar SettingsPage,
SettingsNavigation o un switch central, la integración está mal diseñada.
```

File diff suppressed because it is too large Load Diff