diff --git a/docs/settings/frontend-erp-settings-module-integration-design.md b/docs/settings/frontend-erp-settings-module-integration-design.md new file mode 100644 index 00000000..6643d8e2 --- /dev/null +++ b/docs/settings/frontend-erp-settings-module-integration-design.md @@ -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/
/ + │ + ▼ +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. +``` diff --git a/docs/settings/frontend-erp-settings-system-design.md b/docs/settings/frontend-erp-settings-system-design.md new file mode 100644 index 00000000..465e317f --- /dev/null +++ b/docs/settings/frontend-erp-settings-system-design.md @@ -0,0 +1,1382 @@ +# 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 +