2026-08-11 16:02:16 +00:00
# Frontend ERP – Integración de módulos con Settings
2026-08-11 16:15:05 +00:00
## 1. Estado del documento
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
Estado: **DISEÑO V1 AJUSTADO A LA ARQUITECTURA REAL**
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
Este documento complementa **Frontend ERP – Sistema modular de Settings** y define cómo un módulo frontend publica una opción de configuración empresarial.
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
La V1 se ajusta al funcionamiento real del monorepo:
2026-08-11 16:02:16 +00:00
```txt
2026-08-11 16:15:05 +00:00
IModuleClient[]
→ routing modular existente
→ shell de aplicación
2026-08-11 16:02:16 +00:00
```
2026-08-11 16:15:05 +00:00
Settings amplía metadata de módulo; no crea un segundo sistema de módulos ni un router paralelo.
2026-08-11 16:02:16 +00:00
---
## 2. Principio operativo
```txt
Módulo
2026-08-11 16:15:05 +00:00
→ declara una entry de Settings en su manifest
2026-08-11 16:02:16 +00:00
→ registra su propia route
→ implementa su propia Page
→ mantiene su propia persistencia
2026-08-11 16:15:05 +00:00
Shell
→ agrega entries
→ agrupa por sección central
→ muestra navegación
2026-08-11 16:02:16 +00:00
```
2026-08-11 16:15:05 +00:00
La integración entre shell y módulo se realiza por metadata + ruta.
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
Nunca por import directo de una Page desde `apps/web` .
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
---
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
## 3. Alcance
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
Este documento aplica a configuraciones de la empresa activa publicadas bajo:
2026-08-11 16:02:16 +00:00
```txt
2026-08-11 16:15:05 +00:00
/settings
2026-08-11 16:02:16 +00:00
```
2026-08-11 16:15:05 +00:00
No aplica a:
2026-08-11 16:02:16 +00:00
```txt
2026-08-11 16:15:05 +00:00
/account
preferencias personales
localStorage de UI
configuración técnica del frontend
2026-08-11 16:02:16 +00:00
```
2026-08-11 16:15:05 +00:00
---
## 4. Arquitectura de módulo existente
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
La arquitectura base de los módulos permanece intacta.
2026-08-11 16:02:16 +00:00
```txt
2026-08-11 16:15:05 +00:00
[module]/
├── manifest.ts
├── [module]-routes.tsx
├── index.ts
├── shared/
└── casos de uso
2026-08-11 16:02:16 +00:00
```
2026-08-11 16:15:05 +00:00
Para una configuración:
2026-08-11 16:02:16 +00:00
```txt
2026-08-11 16:15:05 +00:00
Route
→ Page
→ Page Controller
→ Controller
→ shared/hooks
→ shared/api
2026-08-11 16:02:16 +00:00
```
2026-08-11 16:15:05 +00:00
Flujo de datos:
2026-08-11 16:02:16 +00:00
```txt
2026-08-11 16:15:05 +00:00
API
→ DTO
→ Adapter
→ Entity
→ Hook
→ Controller
→ Page Controller
→ UI
2026-08-11 16:02:16 +00:00
```
2026-08-11 16:15:05 +00:00
Settings no introduce excepciones a estas reglas.
2026-08-11 16:02:16 +00:00
---
2026-08-11 16:15:05 +00:00
## 5. Manifest como extension point
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
Los manifests reales implementan `IModuleClient` .
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
Actualmente el contrato ya expone metadata del módulo y `routes()` .
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
V1 añade metadata opcional de Settings.
Contrato conceptual mínimo:
```ts
2026-08-11 16:02:16 +00:00
export interface ModuleSettingsEntryContribution {
id: string;
sectionId: string;
labelKey: string;
path: string;
2026-08-11 16:15:05 +00:00
}
export interface ModuleSettingsContribution {
entries: ModuleSettingsEntryContribution[];
}
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
export interface IModuleClient {
// contrato existente
settings?: ModuleSettingsContribution;
2026-08-11 16:02:16 +00:00
}
```
2026-08-11 16:15:05 +00:00
El shape definitivo debe implementarse respetando el fichero real:
```txt
modules/core/src/web/lib/modules/module-client.interface.ts
```
No duplicar `ModuleMetadata` , routing ni tipos ya existentes.
---
## 6. Qué declara un módulo
Una entry V1 contiene únicamente:
```txt
id
sectionId
labelKey
path
```
2026-08-11 16:02:16 +00:00
Ejemplo conceptual:
```ts
2026-08-11 16:15:05 +00:00
export const CustomerInvoicesModuleManifest: IModuleClient = {
// metadata y routes existentes
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
settings: {
2026-08-11 16:02:16 +00:00
entries: [
{
id: "verifactu",
sectionId: "billing",
2026-08-11 16:15:05 +00:00
labelKey: "settings.verifactu.title",
2026-08-11 16:02:16 +00:00
path: "/settings/billing/verifactu",
},
],
},
};
```
2026-08-11 16:15:05 +00:00
No añadir en V1:
```txt
descriptionKey
order
permission
component
icon
loader
featureFlag
badge
```
salvo que una necesidad real aparezca durante el piloto y se documente antes.
---
## 7. Secciones
Los módulos **no declaran secciones en V1** .
Las secciones son un catálogo del shell.
Ejemplo:
```txt
company
billing
```
Un módulo solo referencia:
```ts
sectionId: "billing";
```
Esto permite:
```txt
customer-invoices
→ billing / VeriFactu
document-series
→ billing / Series documentales
```
sin imports entre módulos y sin duplicar metadata de sección.
Si un módulo usa un `sectionId` inexistente, la agregación debe detectarlo en desarrollo/test.
---
## 8. i18n de la entry
El proyecto registra traducciones por namespace de módulo.
Por tanto:
```txt
manifest.name
→ namespace i18n
entry.labelKey
→ key dentro de ese namespace
```
Ejemplo:
```ts
labelKey: "settings.verifactu.title";
```
No es necesario repetir el namespace en la key si el agregador ya conoce el módulo propietario.
Las labels de las secciones pertenecen al shell.
2026-08-11 16:02:16 +00:00
---
2026-08-11 16:15:05 +00:00
## 9. Routing
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
La entry de Settings no contiene un componente React.
2026-08-11 16:02:16 +00:00
Incorrecto:
```ts
{
id: "verifactu",
component: VerifactuSettingsPage,
}
```
2026-08-11 16:15:05 +00:00
Correcto:
2026-08-11 16:02:16 +00:00
```ts
{
id: "verifactu",
path: "/settings/billing/verifactu",
}
```
2026-08-11 16:15:05 +00:00
El mismo módulo debe registrar una route real para ese path mediante su infraestructura actual.
La entry y la route deben permanecer alineadas.
---
## 10. Subtree `/settings/*`
El router actual todavía no dispone de un `SettingsLayout` compartido.
La V1 del shell debe añadir esa capacidad.
Desde el punto de vista del módulo, la regla es:
> Registrar una route compatible con el namespace `/settings/...` y con el mecanismo que el shell defina para montar esas routes bajo `SettingsLayout`.
2026-08-12 11:31:31 +00:00
Implementación V1:
```txt
buildSettingsRoute(...)
→ rama /settings
→ SettingsLayout
→ buildModuleRoutes(..., pathPrefix: "settings")
```
Las routes de módulos bajo `/settings/...` se recortan y anidan bajo el shell sin crear un router paralelo.
2026-08-11 16:15:05 +00:00
No crear dentro del módulo:
2026-08-11 16:02:16 +00:00
```txt
2026-08-11 16:15:05 +00:00
SettingsRouter
nested RouterProvider
routing alternativo
2026-08-11 16:02:16 +00:00
```
---
2026-08-11 16:15:05 +00:00
## 11. Ubicación de código
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
No se impone una nueva estructura rígida en V1.
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
El código debe respetar la convención real del módulo.
Una posible organización, si encaja con el módulo, es:
2026-08-11 16:02:16 +00:00
```txt
2026-08-11 16:15:05 +00:00
[module]/src/web/
2026-08-11 16:02:16 +00:00
├── manifest.ts
├── [module]-routes.tsx
└── settings/
└── [setting]/
├── controllers/
├── entities/
├── ui/
└── index.ts
```
2026-08-11 16:15:05 +00:00
Esto es una recomendación, no una norma estructural.
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
Si el módulo ya posee una organización equivalente más consistente, debe reutilizarse.
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
---
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
## 12. Page Controller
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
La Page Controller mantiene las responsabilidades normales:
2026-08-11 16:02:16 +00:00
```txt
2026-08-11 16:15:05 +00:00
leer contexto de routing si aplica
2026-08-11 16:02:16 +00:00
componer controllers
2026-08-11 16:15:05 +00:00
exponer estado y acciones a Page
2026-08-11 16:02:16 +00:00
```
No debe:
```txt
2026-08-11 16:15:05 +00:00
consultar DTOs
llamar API directamente
conocer buildSettingsEntries()
conocer SettingsNavigation
2026-08-11 16:02:16 +00:00
```
2026-08-11 16:15:05 +00:00
Los controllers de dominio siguen sin usar `useParams` ni `useNavigate` .
2026-08-11 16:02:16 +00:00
---
2026-08-11 16:15:05 +00:00
## 13. Controller
2026-08-11 16:02:16 +00:00
Responsable de:
```txt
estado del caso de uso
formulario
2026-08-11 16:15:05 +00:00
builders/Params
2026-08-11 16:02:16 +00:00
submit
validaciones de flujo
side effects
2026-08-11 16:15:05 +00:00
coordinación con shared hooks
2026-08-11 16:02:16 +00:00
```
2026-08-11 16:15:05 +00:00
No debe conocer:
2026-08-11 16:02:16 +00:00
```txt
2026-08-11 16:15:05 +00:00
IModuleClient
Settings shell
metadata de navegación
router
DTO
2026-08-11 16:02:16 +00:00
```
---
2026-08-11 16:15:05 +00:00
## 14. Shared
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
El hecho de estar bajo `/settings` no altera `shared/` .
2026-08-11 16:02:16 +00:00
```txt
shared/api
→ transporte remoto
shared/adapters
2026-08-11 16:15:05 +00:00
→ DTO → Entity
2026-08-11 16:02:16 +00:00
shared/entities
→ contratos frontend
shared/hooks
→ React Query
```
2026-08-11 16:15:05 +00:00
No ubicar metadata de Settings en `shared/` .
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
La metadata pertenece al manifest del módulo.
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
---
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
## 15. Empresa activa
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
Todo setting bajo `/settings` opera sobre la empresa activa.
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
El módulo debe reutilizar:
2026-08-11 16:02:16 +00:00
```txt
2026-08-11 16:15:05 +00:00
IdentityAuthSessionProvider
activeCompanyStorage
X-Company-Id
RequireCompany guard
```
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
No debe:
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
```txt
añadir companyId a la URL solo por ser Settings
crear selector local de company
crear un contexto alternativo de company
2026-08-11 16:02:16 +00:00
```
2026-08-11 16:15:05 +00:00
Las operaciones remotas deben seguir el mismo mecanismo de tenant que el resto del ERP.
2026-08-11 16:02:16 +00:00
---
2026-08-11 16:15:05 +00:00
## 16. React Query y cambio de empresa
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
Las query keys actuales del proyecto no incluyen `companyId` .
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
El cambio de empresa resetea globalmente React Query.
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
Un setting debe seguir ese patrón y no introducir una estrategia particular salvo que se rediseñe globalmente la política tenant/cache del ERP.
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
Criterio:
2026-08-11 16:02:16 +00:00
```txt
2026-08-11 16:15:05 +00:00
cambiar empresa
→ nunca mostrar datos de la empresa anterior
2026-08-11 16:02:16 +00:00
```
---
2026-08-11 16:15:05 +00:00
## 17. Persistencia
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
Cada setting conserva su persistencia de dominio.
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
Ejemplos:
```txt
VeriFactu
→ dominio VeriFactu/customer-invoices
Series documentales
→ document-series
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
Datos empresa
→ identity/company
```
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
No crear:
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
```txt
GenericSettingsRepository
settings key/value
localStorage de negocio
```
2026-08-11 16:02:16 +00:00
---
2026-08-11 16:15:05 +00:00
## 18. UI
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
El shell proporciona:
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
```txt
SettingsLayout
SettingsNavigation
título/estructura general
```
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
El módulo proporciona:
```txt
título de la configuración
contenido
formularios
acciones
loading/error
2026-08-11 16:02:16 +00:00
```
2026-08-11 16:15:05 +00:00
No duplicar el sidebar de Settings dentro de la Page del módulo.
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
Usar el sistema visual Rdx vigente.
2026-08-11 16:02:16 +00:00
---
2026-08-11 16:15:05 +00:00
## 19. Formularios
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
Aplican las mismas reglas de fields del resto del ERP.
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
Inputs nativos simples:
2026-08-11 16:02:16 +00:00
```txt
2026-08-11 16:15:05 +00:00
register
2026-08-11 16:02:16 +00:00
```
2026-08-11 16:15:05 +00:00
Controles complejos:
2026-08-11 16:02:16 +00:00
```txt
2026-08-11 16:15:05 +00:00
Controller / useController
2026-08-11 16:02:16 +00:00
```
2026-08-11 16:15:05 +00:00
Mantener:
```txt
Field
FormFieldLabel
FieldDescription
FieldError
```
No crear `GenericSettingsField` ni `GenericSettingsForm` .
2026-08-11 16:02:16 +00:00
---
2026-08-11 16:15:05 +00:00
## 20. Guardado
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
Cada entry guarda de forma independiente.
2026-08-11 16:02:16 +00:00
Ejemplo:
```txt
2026-08-11 16:15:05 +00:00
/settings/billing/verifactu
→ formulario propio
→ mutation propia
→ persistencia propia
2026-08-11 16:02:16 +00:00
```
2026-08-11 16:15:05 +00:00
No existe un submit global para `/settings` .
2026-08-11 16:02:16 +00:00
---
2026-08-11 16:15:05 +00:00
## 21. Loading y errores
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
La Page del módulo mantiene responsabilidad sobre:
2026-08-11 16:02:16 +00:00
```txt
loading inicial
error inicial
2026-08-11 16:15:05 +00:00
retry
2026-08-11 16:02:16 +00:00
refetch error
submit error
validation errors
```
2026-08-11 16:15:05 +00:00
Debe usar los patrones generales existentes, como `PageErrorState` y `ErrorAlert` , cuando corresponda.
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
El shell no interpreta errores de dominio.
2026-08-11 16:02:16 +00:00
---
2026-08-11 16:15:05 +00:00
## 22. Unsaved changes
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
Cada módulo gestiona sus cambios sin guardar.
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
No existe un dirty state global de Settings.
2026-08-11 16:02:16 +00:00
---
2026-08-11 16:15:05 +00:00
## 23. Deep linking
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
La route debe funcionar directamente:
2026-08-11 16:02:16 +00:00
```txt
/settings/billing/verifactu
```
2026-08-11 16:15:05 +00:00
sin visitar antes `/settings` .
Debe ser compatible con:
```txt
refresh
bookmark
deep link
```
2026-08-11 16:02:16 +00:00
---
2026-08-11 16:15:05 +00:00
## 24. Permisos
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
En V1 no se exige `permission` en metadata porque el frontend todavía no dispone de un sistema operativo de filtrado de navegación/route guards por permiso.
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
Existe el tipo:
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
```ts
PermissionCode = string;
2026-08-11 16:02:16 +00:00
```
2026-08-11 16:15:05 +00:00
Cuando se implemente infraestructura frontend real, el contrato podrá evolucionar a:
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
```ts
permission?: PermissionCode;
2026-08-11 16:02:16 +00:00
```
2026-08-11 16:15:05 +00:00
Reglas futuras:
2026-08-11 16:02:16 +00:00
```txt
2026-08-11 16:15:05 +00:00
frontend
→ oculta navegación no disponible
backend
→ sigue autorizando siempre
```
No implementar permisos específicos de Settings antes de disponer del mecanismo global.
---
## 25. Orden
`order` no forma parte obligatoria de V1.
Mientras exista un único piloto, el shell puede usar orden determinista sencillo.
Cuando dos o más módulos contribuyan realmente a una misma sección, se revisará si hace falta:
```ts
order?: number;
2026-08-11 16:02:16 +00:00
```
2026-08-11 16:15:05 +00:00
No depender del orden accidental de imports.
2026-08-11 16:02:16 +00:00
---
2026-08-11 16:15:05 +00:00
## 26. Caso piloto: VeriFactu
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
`customer-invoices` es el primer consumidor previsto.
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
La integración de Settings de VeriFactu debe limitarse inicialmente a:
2026-08-11 16:02:16 +00:00
```txt
2026-08-11 16:15:05 +00:00
manifest entry
route bajo /settings/billing/verifactu
Page
Page Controller
controllers/shared del dominio
2026-08-11 16:02:16 +00:00
```
2026-08-11 16:15:05 +00:00
No trasladar al shell conocimiento de:
```txt
obligada/exenta
renovación
certificados
AEAT
régimen
calificación
causas de exención
```
Todo eso se diseñará en el documento específico de VeriFactu.
---
## 27. Segundo consumidor recomendado
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
Después de VeriFactu, integrar una entry real de otro módulo, preferentemente `document-series` .
Objetivo:
2026-08-11 16:02:16 +00:00
```txt
2026-08-11 16:15:05 +00:00
billing
├── VeriFactu customer-invoices
└── Series documentales document-series
2026-08-11 16:02:16 +00:00
```
2026-08-11 16:15:05 +00:00
Este segundo consumidor valida que:
- las secciones centrales funcionan;
- las entries son realmente modulares;
- no hay imports cruzados;
- la agregación no depende de un único módulo.
Solo entonces evaluar `order` , conflictos u otras extensiones.
2026-08-11 16:02:16 +00:00
---
2026-08-11 16:15:05 +00:00
## 28. Checklist para añadir una entry
2026-08-11 16:02:16 +00:00
### Manifest
2026-08-11 16:15:05 +00:00
- [ ] Usa `settings.entries` .
- [ ] `id` es estable y semántico.
- [ ] `sectionId` existe en el catálogo del shell.
- [ ] `labelKey` existe en el namespace del módulo.
- [ ] `path` es absoluto y estable.
- [ ] No registra un componente React.
2026-08-11 16:02:16 +00:00
### Routing
2026-08-11 16:15:05 +00:00
- [ ] Existe una route real que corresponde a `path` .
- [ ] Funciona por deep-link.
- [ ] Se integra con el subtree `/settings/*` .
- [ ] No crea un RouterProvider propio.
2026-08-11 16:02:16 +00:00
### Arquitectura
- [ ] API → DTO → Adapter → Entity → Hook → Controller → Page Controller → UI.
2026-08-11 16:15:05 +00:00
- [ ] No hay DTOs en controller/UI.
2026-08-11 16:02:16 +00:00
- [ ] No hay routing en controller.
2026-08-11 16:15:05 +00:00
- [ ] `shared/` no conoce Settings.
- [ ] El dominio no conoce `IModuleClient` .
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
### Empresa
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
- [ ] Usa empresa activa existente.
- [ ] No añade `companyId` a la route.
- [ ] No introduce selector alternativo.
- [ ] Cambiar empresa no conserva datos stale.
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
### UI
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
- [ ] No duplica `SettingsNavigation` .
- [ ] Usa Rdx cuando corresponda.
- [ ] Soporta teclado y `focus-visible` .
- [ ] Maneja loading/error correctamente.
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
### Persistencia
2026-08-11 16:02:16 +00:00
2026-08-11 16:15:05 +00:00
- [ ] Usa persistencia del dominio.
- [ ] No crea storage genérico de Settings.
- [ ] No usa localStorage para configuración empresarial.
2026-08-11 16:02:16 +00:00
---
2026-08-11 16:15:05 +00:00
## 29. Anti-patterns
2026-08-11 16:02:16 +00:00
No hacer:
```txt
2026-08-11 16:15:05 +00:00
apps/web importa VerifactuSettingsPage
module settings declara component
SettingsRouter paralelo
SettingsRegistry con estado global
secciones declaradas por cada módulo en V1
GenericSettingsForm
GenericSettingsRepository
SettingsProvider global
companyId duplicado en URL
selector de empresa dentro del setting
imports entre módulos para agrupar entries
switch(setting.id) para renderizar Pages
2026-08-11 16:02:16 +00:00
```
---
2026-08-11 16:15:05 +00:00
## 30. Criterio de validación
La integración de un módulo es correcta si:
2026-08-11 16:02:16 +00:00
```txt
2026-08-11 16:15:05 +00:00
1. el shell descubre su entry desde IModuleClient;
2. el shell no importa su Page;
3. la route pertenece al módulo;
4. el módulo no conoce SettingsNavigation;
5. shared no conoce Settings;
6. los datos pertenecen a la empresa activa;
7. el backend conserva la autorización;
8. la persistencia sigue siendo del dominio;
9. eliminar el módulo elimina su entry;
10. añadir otra entry no obliga a modificar SettingsLayout.
2026-08-11 16:02:16 +00:00
```
2026-08-11 16:15:05 +00:00
---
## 31. Regla mental final
2026-08-11 16:02:16 +00:00
```txt
2026-08-11 16:15:05 +00:00
Manifest
→ declara que la configuración existe
Shell
→ la muestra
Router
→ lleva hasta ella
Módulo
→ la implementa
Dominio
→ la persiste
2026-08-11 16:02:16 +00:00
```
2026-08-11 16:15:05 +00:00
Si para añadir una Page de configuración hay que modificar `SettingsLayout` , importar su componente en `apps/web` o añadir un `switch` central, la integración está mal diseñada.