1383 lines
24 KiB
Markdown
1383 lines
24 KiB
Markdown
# Frontend ERP – Sistema modular de Settings
|
||
|
||
## 1. Propósito
|
||
|
||
Este documento define la arquitectura del sistema de **Configuración (`Settings`)** del ERP.
|
||
|
||
El objetivo es disponer de una única experiencia de configuración para la empresa activa sin convertir la aplicación base en conocedora de las opciones particulares de cada módulo.
|
||
|
||
Principio rector:
|
||
|
||
```txt
|
||
La aplicación conoce el sistema de Settings.
|
||
La aplicación NO conoce los settings concretos de cada módulo.
|
||
|
||
Cada módulo declara las opciones de configuración que aporta.
|
||
```
|
||
|
||
Este diseño debe integrarse con la arquitectura modular existente del frontend, manteniendo la separación entre routing, datos, controllers y UI.
|
||
|
||
---
|
||
|
||
## 2. Alcance
|
||
|
||
### 2.1 `/settings`
|
||
|
||
`/settings` representa exclusivamente:
|
||
|
||
```txt
|
||
Configuración de la empresa activa
|
||
```
|
||
|
||
Ejemplos potenciales:
|
||
|
||
```txt
|
||
/settings/company/details
|
||
/settings/billing/verifactu
|
||
/settings/billing/document-series
|
||
/settings/billing/certificates
|
||
```
|
||
|
||
Una modificación realizada aquí afecta a la empresa activa y, potencialmente, a todos los usuarios que trabajan con ella.
|
||
|
||
### 2.2 `/account`
|
||
|
||
La configuración personal del usuario queda fuera de este sistema:
|
||
|
||
```txt
|
||
/account
|
||
→ configuración personal del usuario
|
||
```
|
||
|
||
Ejemplos:
|
||
|
||
```txt
|
||
idioma
|
||
apariencia
|
||
preferencias personales
|
||
seguridad de cuenta
|
||
```
|
||
|
||
Por tanto:
|
||
|
||
```txt
|
||
/settings ≠ /account
|
||
```
|
||
|
||
No se introduce en esta fase ningún `scope: "company" | "user"`, porque `/settings` tiene un único ámbito semántico: la empresa activa.
|
||
|
||
---
|
||
|
||
## 3. Objetivos
|
||
|
||
El sistema debe permitir:
|
||
|
||
1. Disponer de una única entrada **Configuración** en la navegación principal.
|
||
2. Reunir en `/settings` configuraciones procedentes de múltiples módulos.
|
||
3. Permitir que varios módulos aporten opciones a una misma sección.
|
||
4. Mantener a cada módulo como propietario de sus páginas, lógica y datos.
|
||
5. Añadir una configuración nueva sin modificar el shell de Settings.
|
||
6. Soportar navegación directa mediante URL.
|
||
7. Aplicar permisos sobre opciones concretas.
|
||
8. Mantener una experiencia visual consistente.
|
||
9. Evitar un almacenamiento genérico de configuración.
|
||
10. Evitar un framework dinámico excesivamente complejo.
|
||
|
||
---
|
||
|
||
## 4. No objetivos
|
||
|
||
El sistema de Settings no debe convertirse en:
|
||
|
||
```txt
|
||
un almacén genérico key/value
|
||
un framework de formularios
|
||
un sistema de permisos
|
||
un router alternativo
|
||
un gestor de estado global
|
||
un registro genérico de componentes React
|
||
```
|
||
|
||
Tampoco debe decidir cómo persiste cada dominio su configuración.
|
||
|
||
Ejemplos:
|
||
|
||
```txt
|
||
VeriFactu → persistencia y reglas propias
|
||
Series documentales → módulo document-series
|
||
Datos de empresa → módulo propietario de company/identity
|
||
Certificados → módulo propietario correspondiente
|
||
```
|
||
|
||
Regla:
|
||
|
||
```txt
|
||
Settings framework ≠ Settings persistence
|
||
```
|
||
|
||
---
|
||
|
||
## 5. Principio de propiedad
|
||
|
||
La propiedad se divide en dos niveles.
|
||
|
||
### 5.1 Shell de Settings
|
||
|
||
Responsable de:
|
||
|
||
```txt
|
||
descubrimiento de configuraciones
|
||
agrupación por secciones
|
||
ordenación
|
||
navegación
|
||
layout
|
||
estado de sección/entrada activa
|
||
filtrado por permisos
|
||
```
|
||
|
||
### 5.2 Módulo propietario
|
||
|
||
Responsable de:
|
||
|
||
```txt
|
||
routing de su configuración
|
||
Page
|
||
Page Controller
|
||
Controllers
|
||
Entities
|
||
Hooks
|
||
API
|
||
validación
|
||
persistencia
|
||
reglas de negocio
|
||
UI específica
|
||
```
|
||
|
||
La arquitectura interna de cada setting debe seguir el flujo general del ERP:
|
||
|
||
```txt
|
||
API
|
||
→ DTO
|
||
→ Adapter
|
||
→ Entity
|
||
→ Hook
|
||
→ Controller
|
||
→ Page Controller
|
||
→ UI
|
||
```
|
||
|
||
Los controllers no deben conocer routing. La integración con URL/navegación sigue correspondiendo al Page Controller/Page.
|
||
|
||
---
|
||
|
||
## 6. Arquitectura general
|
||
|
||
```txt
|
||
apps/web
|
||
│
|
||
├── navegación principal
|
||
│ │
|
||
│ └── Configuración
|
||
│ │
|
||
│ ▼
|
||
│ /settings
|
||
│
|
||
├── Settings Shell
|
||
│ ├── SettingsLayout / SettingsPage
|
||
│ ├── SettingsNavigation
|
||
│ └── SettingsRegistry
|
||
│
|
||
└── módulos registrados
|
||
│
|
||
├──────────────────────────┬─────────────────────────┐
|
||
▼ ▼ ▼
|
||
customer-invoices document-series identity
|
||
│ │ │
|
||
└─ contribution └─ contribution └─ contribution
|
||
│ │ │
|
||
└───────────── Settings Registry ──────────────────┘
|
||
```
|
||
|
||
El shell consume metadatos declarativos, no implementaciones de dominio.
|
||
|
||
---
|
||
|
||
## 7. Contribuciones de módulos
|
||
|
||
Cada módulo puede declarar las opciones de configuración que aporta.
|
||
|
||
El punto natural es el `manifest.ts` del módulo, siempre que la auditoría del repositorio confirme que este es el contrato correcto para ampliar metadatos de módulo.
|
||
|
||
Conceptualmente:
|
||
|
||
```ts
|
||
export const customerInvoicesManifest = {
|
||
// configuración existente del módulo
|
||
|
||
settings: {
|
||
sections: [],
|
||
entries: [],
|
||
},
|
||
};
|
||
```
|
||
|
||
El contrato exacto debe adaptarse al shape real del manifest existente.
|
||
|
||
---
|
||
|
||
## 8. Secciones compartidas entre módulos
|
||
|
||
Una sección de Settings no pertenece necesariamente a un único módulo.
|
||
|
||
Ejemplo:
|
||
|
||
```txt
|
||
Facturación
|
||
├── VeriFactu customer-invoices
|
||
├── Series documentales document-series
|
||
└── Certificados módulo propietario correspondiente
|
||
```
|
||
|
||
Varios módulos pueden contribuir a:
|
||
|
||
```txt
|
||
sectionId = "billing"
|
||
```
|
||
|
||
sin conocerse entre ellos.
|
||
|
||
El registry se encarga de fusionar esas contribuciones.
|
||
|
||
---
|
||
|
||
## 9. Contratos conceptuales
|
||
|
||
### 9.1 Sección
|
||
|
||
```ts
|
||
export interface ModuleSettingsSectionContribution {
|
||
id: string;
|
||
labelKey: string;
|
||
order?: number;
|
||
}
|
||
```
|
||
|
||
### 9.2 Entrada
|
||
|
||
```ts
|
||
export interface ModuleSettingsEntryContribution {
|
||
id: string;
|
||
sectionId: string;
|
||
|
||
labelKey: string;
|
||
descriptionKey?: string;
|
||
|
||
path: string;
|
||
|
||
order?: number;
|
||
permission?: string;
|
||
}
|
||
```
|
||
|
||
### 9.3 Contribución completa
|
||
|
||
```ts
|
||
export interface ModuleSettingsContribution {
|
||
sections?: ModuleSettingsSectionContribution[];
|
||
entries?: ModuleSettingsEntryContribution[];
|
||
}
|
||
```
|
||
|
||
Este contrato debe mantenerse deliberadamente pequeño.
|
||
|
||
No añadir en V1 salvo necesidad real:
|
||
|
||
```txt
|
||
component
|
||
loader
|
||
icon renderer
|
||
badge provider
|
||
status resolver
|
||
search keywords
|
||
feature flag resolver
|
||
nested tree arbitrario
|
||
custom layout
|
||
```
|
||
|
||
---
|
||
|
||
## 10. Identidad de secciones
|
||
|
||
Las secciones deben utilizar IDs semánticos y estables.
|
||
|
||
Ejemplos:
|
||
|
||
```txt
|
||
company
|
||
billing
|
||
sales
|
||
purchases
|
||
users
|
||
integrations
|
||
```
|
||
|
||
No es necesario convertir inicialmente el conjunto en una unión TypeScript cerrada si eso dificulta la extensibilidad modular.
|
||
|
||
Ejemplo:
|
||
|
||
```ts
|
||
{
|
||
id: "billing",
|
||
labelKey: "settings.sections.billing",
|
||
order: 200,
|
||
}
|
||
```
|
||
|
||
Si dos módulos declaran `billing`, el registry debe reconocer que representan la misma sección.
|
||
|
||
---
|
||
|
||
## 11. Conflictos de secciones
|
||
|
||
El mismo `sectionId` no puede representar semánticas diferentes.
|
||
|
||
Ejemplo inválido:
|
||
|
||
```txt
|
||
billing + "Facturación"
|
||
billing + "Ventas"
|
||
```
|
||
|
||
Regla:
|
||
|
||
```txt
|
||
mismo sectionId
|
||
→ misma identidad semántica
|
||
→ labels compatibles
|
||
```
|
||
|
||
En desarrollo, el registry debe detectar conflictos en lugar de resolverlos silenciosamente.
|
||
|
||
---
|
||
|
||
## 12. Identidad de entradas
|
||
|
||
El `id` identifica una opción dentro del sistema de Settings.
|
||
|
||
Debe ser:
|
||
|
||
```txt
|
||
estable
|
||
semántico
|
||
independiente del texto visible
|
||
```
|
||
|
||
Ejemplos:
|
||
|
||
```txt
|
||
verifactu
|
||
document-series
|
||
certificates
|
||
company-details
|
||
```
|
||
|
||
Evitar:
|
||
|
||
```txt
|
||
setting1
|
||
optionA
|
||
config
|
||
```
|
||
|
||
Si existe riesgo real de colisión, el registry puede usar internamente una identidad compuesta:
|
||
|
||
```txt
|
||
moduleId + entryId
|
||
```
|
||
|
||
sin obligar a exponer esa representación al consumidor.
|
||
|
||
---
|
||
|
||
## 13. Routing
|
||
|
||
### Regla principal
|
||
|
||
Settings registra destinos de navegación, no componentes React.
|
||
|
||
Evitar:
|
||
|
||
```ts
|
||
{
|
||
id: "verifactu",
|
||
component: VerifactuSettingsPage,
|
||
}
|
||
```
|
||
|
||
Preferir:
|
||
|
||
```ts
|
||
{
|
||
id: "verifactu",
|
||
path: "/settings/billing/verifactu",
|
||
}
|
||
```
|
||
|
||
El módulo propietario continúa registrando su propia route.
|
||
|
||
### Motivo
|
||
|
||
```txt
|
||
Settings Registry
|
||
→ conoce navegación
|
||
|
||
Módulo
|
||
→ conoce página
|
||
```
|
||
|
||
Esto evita convertir Settings en un segundo router o sistema de carga dinámica de React.
|
||
|
||
---
|
||
|
||
## 14. Namespace de rutas
|
||
|
||
Convención objetivo:
|
||
|
||
```txt
|
||
/settings/:section/:setting
|
||
```
|
||
|
||
Ejemplos:
|
||
|
||
```txt
|
||
/settings/company/details
|
||
/settings/billing/verifactu
|
||
/settings/billing/document-series
|
||
/settings/billing/certificates
|
||
```
|
||
|
||
La ruta exacta debe verificarse contra el routing real antes de implementarla.
|
||
|
||
---
|
||
|
||
## 15. Ruta raíz `/settings`
|
||
|
||
La raíz puede:
|
||
|
||
```txt
|
||
redirigir a la primera configuración disponible
|
||
```
|
||
|
||
o presentar un índice/resumen de configuraciones.
|
||
|
||
La decisión final es de UX y puede tomarse al implementar el shell.
|
||
|
||
No debe contener lógica de dominio.
|
||
|
||
---
|
||
|
||
## 16. Settings Registry
|
||
|
||
El registry es la pieza responsable de combinar las contribuciones de todos los módulos.
|
||
|
||
Entrada conceptual:
|
||
|
||
```txt
|
||
ModuleManifest[]
|
||
```
|
||
|
||
Salida conceptual:
|
||
|
||
```ts
|
||
export interface SettingsRegistry {
|
||
sections: SettingsSection[];
|
||
}
|
||
|
||
export interface SettingsSection {
|
||
id: string;
|
||
labelKey: string;
|
||
order: number;
|
||
entries: SettingsEntry[];
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 17. Responsabilidades del registry
|
||
|
||
Debe:
|
||
|
||
```txt
|
||
recoger contribuciones
|
||
fusionar secciones comunes
|
||
validar IDs
|
||
detectar conflictos
|
||
ordenar secciones
|
||
ordenar entradas
|
||
filtrar entradas no disponibles por permisos
|
||
producir un resultado determinista
|
||
```
|
||
|
||
No debe:
|
||
|
||
```txt
|
||
consultar APIs de negocio
|
||
cargar configuración
|
||
persistir valores
|
||
renderizar formularios
|
||
resolver reglas fiscales
|
||
```
|
||
|
||
---
|
||
|
||
## 18. Registro declarativo, no imperativo
|
||
|
||
Preferir:
|
||
|
||
```ts
|
||
export const manifest = {
|
||
settings: ...,
|
||
};
|
||
```
|
||
|
||
frente a:
|
||
|
||
```ts
|
||
registerSetting(...);
|
||
registerSetting(...);
|
||
```
|
||
|
||
Ventajas:
|
||
|
||
- evita side effects durante imports;
|
||
- facilita validación;
|
||
- hace visible la superficie pública del módulo;
|
||
- permite inspección;
|
||
- permite ordenar antes de renderizar;
|
||
- encaja con una arquitectura basada en manifests.
|
||
|
||
---
|
||
|
||
## 19. Lazy loading
|
||
|
||
El metadata usado para construir la navegación debe ser ligero.
|
||
|
||
El shell no debería necesitar importar toda una página para saber que existe una opción.
|
||
|
||
```txt
|
||
manifest metadata
|
||
≠
|
||
page implementation
|
||
```
|
||
|
||
El routing del módulo puede mantener lazy loading si la infraestructura actual ya lo soporta.
|
||
|
||
---
|
||
|
||
## 20. Layout
|
||
|
||
Modelo recomendado:
|
||
|
||
```txt
|
||
┌───────────────────────────────────────────────────────────┐
|
||
│ Configuración │
|
||
│ Configura el comportamiento de la empresa activa │
|
||
├─────────────────┬─────────────────────────────────────────┤
|
||
│ │ │
|
||
│ Empresa │ │
|
||
│ Datos │ │
|
||
│ │ contenido del módulo │
|
||
│ Facturación │ │
|
||
│ VeriFactu │ │
|
||
│ Series │ │
|
||
│ Certificados │ │
|
||
│ │ │
|
||
│ Integraciones │ │
|
||
│ │ │
|
||
└─────────────────┴─────────────────────────────────────────┘
|
||
```
|
||
|
||
El panel izquierdo pertenece al framework.
|
||
|
||
El área de contenido pertenece a la ruta del módulo.
|
||
|
||
---
|
||
|
||
## 21. Sistema visual
|
||
|
||
El shell debe reutilizar los componentes estructurales Rdx existentes cuando sean aplicables.
|
||
|
||
Por ejemplo:
|
||
|
||
```txt
|
||
RdxPageContainer
|
||
RdxPageHeader
|
||
RdxPageStack
|
||
```
|
||
|
||
La infraestructura dependiente de routing, manifests, permisos o empresa activa no debe vivir en `packages/rdx-ui`.
|
||
|
||
`rdx-ui` puede contener únicamente piezas visuales genéricas y desacopladas.
|
||
|
||
---
|
||
|
||
## 22. Navegación principal
|
||
|
||
La aplicación debe exponer una sola entrada:
|
||
|
||
```txt
|
||
Configuración
|
||
```
|
||
|
||
El menú principal no debe contener directamente:
|
||
|
||
```txt
|
||
VeriFactu
|
||
Series
|
||
Certificados
|
||
Configuración de clientes
|
||
...
|
||
```
|
||
|
||
Estas opciones aparecen dentro de `/settings`.
|
||
|
||
```txt
|
||
App navigation
|
||
└── Configuración
|
||
└── SettingsNavigation
|
||
├── Empresa
|
||
├── Facturación
|
||
├── ...
|
||
```
|
||
|
||
---
|
||
|
||
## 23. Empresa activa
|
||
|
||
Todo `/settings` debe operar sobre la empresa activa.
|
||
|
||
No debe introducirse un segundo selector o una segunda fuente de verdad.
|
||
|
||
Conceptualmente:
|
||
|
||
```txt
|
||
active company changes
|
||
│
|
||
▼
|
||
Settings context changes
|
||
│
|
||
▼
|
||
module queries resolve data for new company
|
||
```
|
||
|
||
La implementación debe reutilizar la infraestructura de empresa activa existente en el ERP.
|
||
|
||
---
|
||
|
||
## 24. Cambio de empresa activa
|
||
|
||
Una página de configuración no debe conservar datos pertenecientes a la empresa anterior después de cambiar la empresa activa.
|
||
|
||
Debe resolverse mediante la infraestructura ya existente de:
|
||
|
||
```txt
|
||
company context
|
||
headers
|
||
query keys
|
||
query invalidation
|
||
```
|
||
|
||
No mediante estado duplicado dentro del framework Settings.
|
||
|
||
---
|
||
|
||
## 25. Persistencia
|
||
|
||
Regla fundamental:
|
||
|
||
```txt
|
||
Settings framework
|
||
≠
|
||
Settings persistence
|
||
```
|
||
|
||
No crear únicamente por este sistema:
|
||
|
||
```txt
|
||
settings table
|
||
settings(key, value)
|
||
GenericSettingsRepository
|
||
useSettings()
|
||
```
|
||
|
||
Cada dominio conserva su propia persistencia y validación.
|
||
|
||
---
|
||
|
||
## 26. Formularios
|
||
|
||
Cada setting mantiene sus propios formularios.
|
||
|
||
Ejemplo:
|
||
|
||
```txt
|
||
VerifactuSettingsPage
|
||
│
|
||
▼
|
||
VerifactuSettingsEditor
|
||
│
|
||
▼
|
||
React Hook Form
|
||
```
|
||
|
||
Settings no proporciona un `GenericSettingsForm`.
|
||
|
||
Los formularios deben seguir las convenciones ya consolidadas del ERP para fields y React Hook Form.
|
||
|
||
---
|
||
|
||
## 27. Guardado
|
||
|
||
No debe existir un botón global:
|
||
|
||
```txt
|
||
Guardar toda la configuración del ERP
|
||
```
|
||
|
||
Cada entrada mantiene su propia transacción de guardado.
|
||
|
||
Ejemplos:
|
||
|
||
```txt
|
||
/settings/billing/verifactu
|
||
→ Guardar VeriFactu
|
||
|
||
/settings/company/details
|
||
→ Guardar datos de empresa
|
||
```
|
||
|
||
Esto evita mezclar dominios y transacciones.
|
||
|
||
---
|
||
|
||
## 28. Errores
|
||
|
||
El shell gestiona únicamente errores estructurales del sistema Settings.
|
||
|
||
Ejemplos:
|
||
|
||
```txt
|
||
ruta inválida
|
||
entry inexistente
|
||
acceso no permitido al subtree
|
||
error de render del subtree
|
||
```
|
||
|
||
El módulo sigue gestionando errores de carga/guardado de su configuración mediante los patrones generales del ERP.
|
||
|
||
---
|
||
|
||
## 29. Permisos
|
||
|
||
Una entrada puede declarar opcionalmente:
|
||
|
||
```ts
|
||
permission?: string;
|
||
```
|
||
|
||
El shell reutiliza la infraestructura central de autorización para decidir si la entrada está disponible.
|
||
|
||
Ejemplos conceptuales:
|
||
|
||
```txt
|
||
VeriFactu
|
||
→ manage_verifactu_settings
|
||
|
||
Certificados
|
||
→ manage_company_certificates
|
||
```
|
||
|
||
Settings no interpreta el permiso ni implementa autorización propia.
|
||
|
||
---
|
||
|
||
## 30. Ocultar vs deshabilitar
|
||
|
||
Para una opción de Settings sin permiso, la decisión inicial es:
|
||
|
||
```txt
|
||
no mostrarla
|
||
```
|
||
|
||
La navegación representa capacidades administrativas disponibles.
|
||
|
||
Esto no sustituye la autorización backend.
|
||
|
||
---
|
||
|
||
## 31. Seguridad
|
||
|
||
Ocultar una entrada del menú no constituye autorización.
|
||
|
||
El backend debe seguir validando:
|
||
|
||
```txt
|
||
usuario
|
||
permiso
|
||
empresa activa
|
||
operación solicitada
|
||
```
|
||
|
||
El frontend únicamente adapta la experiencia de navegación.
|
||
|
||
---
|
||
|
||
## 32. i18n
|
||
|
||
Los manifests deben declarar claves, no textos hardcodeados:
|
||
|
||
```ts
|
||
labelKey
|
||
descriptionKey
|
||
```
|
||
|
||
Ejemplo:
|
||
|
||
```ts
|
||
labelKey: "customerInvoices.settings.verifactu.title";
|
||
```
|
||
|
||
El módulo propietario mantiene sus traducciones.
|
||
|
||
Las secciones compartidas deben utilizar claves semánticamente compatibles.
|
||
|
||
---
|
||
|
||
## 33. Ordenación
|
||
|
||
Cada sección y entrada puede declarar:
|
||
|
||
```ts
|
||
order?: number;
|
||
```
|
||
|
||
Ejemplo:
|
||
|
||
```txt
|
||
100 Empresa
|
||
200 Facturación
|
||
300 Ventas
|
||
400 Compras
|
||
500 Integraciones
|
||
```
|
||
|
||
Dentro de Facturación:
|
||
|
||
```txt
|
||
100 VeriFactu
|
||
200 Series documentales
|
||
300 Certificados
|
||
```
|
||
|
||
No usar orden alfabético como criterio principal porque los labels dependen del idioma.
|
||
|
||
Si `order` no existe, el resultado debe seguir siendo determinista mediante un valor por defecto y un desempate estable por `id`.
|
||
|
||
---
|
||
|
||
## 34. Conflictos
|
||
|
||
El registry debe detectar al menos en desarrollo:
|
||
|
||
### Section ID conflict
|
||
|
||
```txt
|
||
mismo id
|
||
labels incompatibles
|
||
```
|
||
|
||
### Entry ID conflict
|
||
|
||
```txt
|
||
misma identidad registrada más de una vez
|
||
```
|
||
|
||
### Path conflict
|
||
|
||
```txt
|
||
dos entries incompatibles apuntan a la misma ruta
|
||
```
|
||
|
||
### Missing section
|
||
|
||
```txt
|
||
entry apunta a una section inexistente
|
||
```
|
||
|
||
Los conflictos no deben resolverse silenciosamente.
|
||
|
||
---
|
||
|
||
## 35. Responsive
|
||
|
||
Desktop:
|
||
|
||
```txt
|
||
navegación lateral + contenido
|
||
```
|
||
|
||
Viewport estrecho:
|
||
|
||
```txt
|
||
navegación adaptada
|
||
→ selección/listado de settings
|
||
→ contenido
|
||
```
|
||
|
||
Debe mantenerse el mismo registry y las mismas rutas.
|
||
|
||
No crear dos sistemas de Settings diferentes.
|
||
|
||
---
|
||
|
||
## 36. Accesibilidad
|
||
|
||
La navegación debe usar semántica real:
|
||
|
||
```html
|
||
<nav>
|
||
<a>
|
||
```
|
||
|
||
Requisitos mínimos:
|
||
|
||
```txt
|
||
focus-visible
|
||
aria-current="page"
|
||
uso completo con teclado
|
||
jerarquía correcta de headings
|
||
estado activo perceptible sin depender solo del color
|
||
```
|
||
|
||
---
|
||
|
||
## 37. Deep links
|
||
|
||
Cada configuración debe ser direccionable directamente.
|
||
|
||
Ejemplo:
|
||
|
||
```txt
|
||
/settings/billing/verifactu
|
||
```
|
||
|
||
Debe funcionar con:
|
||
|
||
```txt
|
||
refresh
|
||
deep-link
|
||
bookmark
|
||
navegación interna
|
||
```
|
||
|
||
El estado activo se deriva de la URL, no de un `setSelectedSetting(...)` global.
|
||
|
||
---
|
||
|
||
## 38. Cambios sin guardar
|
||
|
||
El shell no debe inspeccionar ni gestionar globalmente formularios dirty de los módulos.
|
||
|
||
Cada página propietaria debe usar el mecanismo estándar del ERP para:
|
||
|
||
```txt
|
||
unsaved changes
|
||
navigation guard
|
||
cancel
|
||
```
|
||
|
||
---
|
||
|
||
## 39. Queries y caché
|
||
|
||
Cada módulo conserva sus query keys y estrategia de caché.
|
||
|
||
El framework no debe crear una query genérica:
|
||
|
||
```txt
|
||
["settings", ...]
|
||
```
|
||
|
||
para todos los dominios.
|
||
|
||
Ejemplos:
|
||
|
||
```txt
|
||
VeriFactu settings query key
|
||
→ customer-invoices
|
||
|
||
Document Series query keys
|
||
→ document-series
|
||
```
|
||
|
||
---
|
||
|
||
## 40. Caso piloto: VeriFactu
|
||
|
||
VeriFactu será el primer consumidor real del framework.
|
||
|
||
Conceptualmente:
|
||
|
||
```txt
|
||
customer-invoices
|
||
└── manifest
|
||
└── settings
|
||
├── section: billing
|
||
└── entry: verifactu
|
||
```
|
||
|
||
Ruta objetivo:
|
||
|
||
```txt
|
||
/settings/billing/verifactu
|
||
```
|
||
|
||
La ubicación física de su implementación debe definirse después de auditar el módulo real.
|
||
|
||
---
|
||
|
||
## 41. Independencia entre Settings y módulos
|
||
|
||
Debe cumplirse:
|
||
|
||
```txt
|
||
eliminar customer-invoices
|
||
→ desaparecen automáticamente sus settings
|
||
|
||
Settings continúa funcionando
|
||
```
|
||
|
||
Y también:
|
||
|
||
```txt
|
||
añadir módulo nuevo
|
||
→ puede aportar Settings
|
||
→ sin modificar SettingsPage
|
||
→ sin modificar SettingsNavigation
|
||
```
|
||
|
||
Este es el principal criterio de aceptación del sistema.
|
||
|
||
---
|
||
|
||
## 42. Independencia entre módulos
|
||
|
||
Un módulo no debe importar otro únicamente para registrar sus settings.
|
||
|
||
Incorrecto:
|
||
|
||
```txt
|
||
customer-invoices
|
||
→ importa document-series settings
|
||
```
|
||
|
||
Correcto:
|
||
|
||
```txt
|
||
customer-invoices manifest ─┐
|
||
├→ registry
|
||
document-series manifest ───┘
|
||
```
|
||
|
||
---
|
||
|
||
## 43. Anti-patterns prohibidos
|
||
|
||
### Configuración central hardcoded
|
||
|
||
```ts
|
||
const SETTINGS = [
|
||
VerifactuSettings,
|
||
DocumentSeriesSettings,
|
||
CertificateSettings,
|
||
];
|
||
```
|
||
|
||
### Registro central de componentes de dominio
|
||
|
||
```ts
|
||
{
|
||
component: VerifactuSettingsPage,
|
||
}
|
||
```
|
||
|
||
como API principal del registry.
|
||
|
||
### Persistencia genérica indiscriminada
|
||
|
||
```txt
|
||
settings
|
||
├── key
|
||
└── value
|
||
```
|
||
|
||
para almacenar configuraciones de dominios diferentes.
|
||
|
||
### Switch central
|
||
|
||
```ts
|
||
switch (setting.id) {
|
||
case "verifactu":
|
||
case "certificates":
|
||
}
|
||
```
|
||
|
||
### Imports cruzados por Settings
|
||
|
||
```txt
|
||
apps/web/settings
|
||
→ importa páginas concretas de todos los módulos
|
||
```
|
||
|
||
si el sistema modular de routing puede evitarlos.
|
||
|
||
### Routing o manifests en `rdx-ui`
|
||
|
||
No permitido.
|
||
|
||
---
|
||
|
||
## 44. Extensiones futuras posibles
|
||
|
||
Solo cuando aparezca necesidad real:
|
||
|
||
```txt
|
||
buscador de configuración
|
||
badges de estado
|
||
feature flags
|
||
keywords
|
||
settings favoritos
|
||
navegación reciente
|
||
secciones anidadas
|
||
links externos
|
||
estado "requiere atención"
|
||
```
|
||
|
||
No forman parte de V1.
|
||
|
||
---
|
||
|
||
## 45. Criterios de aceptación
|
||
|
||
El diseño se considera correctamente implementado si:
|
||
|
||
1. Añadir un setting nuevo no modifica el shell.
|
||
2. Eliminar un módulo elimina automáticamente sus settings.
|
||
3. Varios módulos pueden contribuir a la misma sección.
|
||
4. Cada setting tiene URL propia.
|
||
5. El módulo conserva control sobre sus datos y UI.
|
||
6. Settings no persiste datos de negocio.
|
||
7. `rdx-ui` no conoce routing ni manifests.
|
||
8. No existen imports cruzados entre módulos por Settings.
|
||
9. La empresa activa es el único scope de `/settings`.
|
||
10. `/account` permanece independiente.
|
||
11. El resultado del registry es determinista.
|
||
12. Los conflictos de metadata se detectan en desarrollo.
|
||
|
||
---
|
||
|
||
## 46. Fases de implementación recomendadas
|
||
|
||
### Fase 0 — Auditoría
|
||
|
||
Investigar sin modificar código:
|
||
|
||
```txt
|
||
manifest actual
|
||
module registry
|
||
routing composition
|
||
sidebar
|
||
active company
|
||
permissions
|
||
i18n
|
||
layouts
|
||
```
|
||
|
||
### Fase 1 — Contrato de contribuciones
|
||
|
||
Añadir únicamente:
|
||
|
||
```txt
|
||
module manifest
|
||
→ settings metadata
|
||
```
|
||
|
||
y el registry correspondiente.
|
||
|
||
### Fase 2 — Shell de Settings
|
||
|
||
Implementar:
|
||
|
||
```txt
|
||
/settings
|
||
SettingsLayout
|
||
SettingsNavigation
|
||
agrupación por sección
|
||
routing
|
||
permissions
|
||
```
|
||
|
||
Sin introducir todavía lógica de dominios concretos.
|
||
|
||
### Fase 3 — Consumidor piloto
|
||
|
||
Integrar VeriFactu como primera contribución real.
|
||
|
||
### Fase 4 — Segundo módulo
|
||
|
||
Integrar una configuración aportada por otro módulo, preferentemente `document-series`, para validar que dos módulos contribuyen a `billing` sin conocerse.
|
||
|
||
### Fase 5 — Consolidación
|
||
|
||
Solo después revisar abstracciones comunes, tests y documentación del UI Kit.
|
||
|
||
---
|
||
|
||
## 47. Tests mínimos
|
||
|
||
### Registry
|
||
|
||
Debe comprobar:
|
||
|
||
```txt
|
||
fusiona secciones
|
||
ordena entries
|
||
detecta IDs duplicados
|
||
detecta conflictos
|
||
respeta permisos
|
||
resultado determinista
|
||
```
|
||
|
||
### Routing
|
||
|
||
Debe comprobar:
|
||
|
||
```txt
|
||
deep-link directo
|
||
ruta inexistente
|
||
navegación entre entries
|
||
refresh
|
||
```
|
||
|
||
### UI
|
||
|
||
Con Testing Library:
|
||
|
||
```txt
|
||
navegación accesible
|
||
aria-current
|
||
entry visible/no visible por permisos
|
||
render del contenido de la route
|
||
```
|
||
|
||
No testear implementación interna de cada módulo desde Settings.
|
||
|
||
---
|
||
|
||
## 48. Decisiones consolidadas
|
||
|
||
```txt
|
||
/settings
|
||
→ configuración de la empresa activa
|
||
```
|
||
|
||
```txt
|
||
/account
|
||
→ configuración personal del usuario
|
||
```
|
||
|
||
```txt
|
||
Una única entrada "Configuración"
|
||
en la navegación principal.
|
||
```
|
||
|
||
```txt
|
||
Varios módulos pueden contribuir
|
||
a una misma sección.
|
||
```
|
||
|
||
```txt
|
||
La aplicación base no conoce
|
||
los settings específicos de los módulos.
|
||
```
|
||
|
||
```txt
|
||
Los módulos declaran sus settings
|
||
mediante metadata.
|
||
```
|
||
|
||
```txt
|
||
Settings registra navegación,
|
||
no implementaciones React.
|
||
```
|
||
|
||
```txt
|
||
Cada dominio conserva
|
||
su propia persistencia.
|
||
```
|
||
|
||
```txt
|
||
Settings no pertenece a rdx-ui.
|
||
```
|
||
|
||
```txt
|
||
VeriFactu será el primer consumidor real.
|
||
```
|
||
|
||
---
|
||
|
||
## 49. Pendientes que requieren auditoría
|
||
|
||
No deben cerrarse sin inspeccionar el repositorio:
|
||
|
||
```txt
|
||
shape exacto de manifest.ts
|
||
ubicación física del SettingsRegistry
|
||
forma de agregar manifests
|
||
routing modular actual
|
||
sistema real de permisos
|
||
fuente concreta de active company
|
||
API de traducciones en manifests
|
||
estrategia de lazy routes
|
||
ruta exacta del SettingsLayout
|
||
mecanismo de ErrorBoundary del shell
|
||
```
|
||
|
||
---
|
||
|
||
## 50. Regla mental final
|
||
|
||
```txt
|
||
App
|
||
→ conoce Settings
|
||
|
||
Settings
|
||
→ conoce contribuciones
|
||
|
||
Contribución
|
||
→ conoce metadata
|
||
|
||
Módulo
|
||
→ conoce dominio
|
||
|
||
Ruta
|
||
→ conecta Settings con el módulo
|
||
```
|
||
|
||
Criterio principal:
|
||
|
||
```txt
|
||
Añadir una opción de configuración desde un módulo
|
||
NO debe requerir modificar el shell de Settings.
|
||
```
|