615 lines
10 KiB
Markdown
615 lines
10 KiB
Markdown
# 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.
|
||
```
|