# πŸ“š Sistema de GestiΓ³n de Contenido - DocumentaciΓ³n Completa **VersiΓ³n:** 1.0.0 **Fecha:** 2025-01-06 **Estado:** βœ… Completado --- ## πŸ“‹ Tabla de Contenidos 1. [Resumen Ejecutivo](#resumen-ejecutivo) 2. [Arquitectura del Sistema](#arquitectura-del-sistema) 3. [Componentes Principales](#componentes-principales) 4. [Flujo de Datos](#flujo-de-datos) 5. [API y Endpoints](#api-y-endpoints) 6. [Content Pack](#content-pack) 7. [ContentAdapter](#contentadapter) 8. [Enlaces Bidireccionales](#enlaces-bidireccionales) 9. [Sistema de Cache](#sistema-de-cache) 10. [Testing](#testing) 11. [GuΓ­a de Uso](#guΓ­a-de-uso) 12. [Troubleshooting](#troubleshooting) --- ## 🎯 Resumen Ejecutivo El Sistema de GestiΓ³n de Contenido es una arquitectura **aditiva y desacoplada** que permite gestionar todo el contenido de la aplicaciΓ³n PWA sin tocar el cΓ³digo existente. El sistema garantiza **estabilidad total** incluso si el sistema externo falla, mediante un mecanismo de fallback robusto. ### CaracterΓ­sticas Principales - βœ… **Arquitectura Aditiva:** No modifica cΓ³digo existente - βœ… **Fallback Total:** Funciona offline con datos locales - βœ… **Content Pack JSON:** Sistema de distribuciΓ³n de contenido - βœ… **Enlaces Bidireccionales:** Protocolos ↔ GuΓ­as ↔ Manual - βœ… **Cache Inteligente:** IndexedDB con fallback a localStorage - βœ… **Testing Completo:** Herramientas de verificaciΓ³n integradas --- ## πŸ—οΈ Arquitectura del Sistema ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ FRONTEND (PWA) β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ ContentAdapterFactory β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ β”‚ β”‚ LocalContentAdapterβ”‚ β”‚ExternalContentAdapterβ”‚ β”‚ β”‚ β”‚ β”‚ β”‚ (Datos locales) β”‚ β”‚ (Content Pack) β”‚ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ β”‚ β–Ό β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ PΓ‘ginas de la App β”‚ β”‚ β”‚ β”‚ (RCP, ViaAerea, Shock, Farmacos, etc.) β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ Cache (IndexedDB / localStorage) β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ HTTP β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ BACKEND (Express) β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ PostgreSQL Database β”‚ β”‚ β”‚ β”‚ - content_items β”‚ β”‚ β”‚ β”‚ - media_resources β”‚ β”‚ β”‚ β”‚ - content_resource_relations β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ β”‚ β–Ό β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ Content Pack Generator β”‚ β”‚ β”‚ β”‚ - Genera pack-latest.json β”‚ β”‚ β”‚ β”‚ - Calcula hash SHA-256 β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ β”‚ β–Ό β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ API Endpoint β”‚ β”‚ β”‚ β”‚ GET /api/content-pack/latest.json β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` --- ## πŸ”§ Componentes Principales ### 1. ContentAdapter **UbicaciΓ³n:** `src/services/content-adapter.ts` Interfaz que abstrae el acceso al contenido: ```typescript interface ContentAdapter { getProtocol(id: string): Procedure | null; getDrug(id: string): Drug | null; getGuide(id: string): Guide | null; getAllProtocols(): Procedure[]; getAllDrugs(): Drug[]; getAllGuides(): Guide[]; isAvailable(): boolean; } ``` #### LocalContentAdapter - Usa datos locales (`procedures.ts`, `drugs.ts`, `guides-index.ts`) - Siempre disponible - Fallback garantizado #### ExternalContentAdapter - Carga Content Pack desde `/api/content-pack/latest.json` - Cache en IndexedDB/localStorage - Fallback automΓ‘tico a LocalContentAdapter si falla #### ContentAdapterFactory - Selecciona automΓ‘ticamente el adapter disponible - Prioriza ExternalContentAdapter si estΓ‘ disponible - Fallback a LocalContentAdapter --- ### 2. Content Pack **UbicaciΓ³n Backend:** `backend/src/services/pack-generator.js` **Endpoint:** `/api/content-pack/latest.json` Estructura del Content Pack: ```json { "version": "1.0.0", "generatedAt": "2025-01-06T12:00:00Z", "hash": "sha256:...", "content": { "protocols": [...], "guides": [...], "drugs": [...], "checklists": [...], "manuals": [...] }, "media": { "images": [...], "videos": [...] }, "relations": [...] } ``` --- ### 3. Sistema de Relaciones **UbicaciΓ³n:** `src/services/content-relations.ts` Proporciona funciones para obtener relaciones bidireccionales: - `getGuideForProtocol(protocolId)` - Obtiene guΓ­a relacionada - `getProtocolForGuide(guideId)` - Obtiene protocolo relacionado - `getProtocolRelations(protocolId)` - Obtiene todas las relaciones - `getGuideRelations(guideId)` - Obtiene todas las relaciones --- ### 4. Sistema de Cache **UbicaciΓ³n:** `src/utils/indexeddb.ts` #### IndexedDB (Prioritario) - Mayor capacidad de almacenamiento - Mejor rendimiento con packs grandes - API asΓ­ncrona #### localStorage (Fallback) - Compatible con todos los navegadores - SincrΓ³nico - Limitado a ~5-10MB **ExpiraciΓ³n:** 24 horas por defecto --- ## πŸ”„ Flujo de Datos ### Carga Inicial 1. App inicia β†’ `ContentAdapterFactory` se inicializa 2. `ExternalContentAdapter` intenta cargar Content Pack: - Primero desde IndexedDB (cache) - Si no hay cache o estΓ‘ expirado, descarga desde API - Guarda en cache 3. Si falla, usa `LocalContentAdapter` (datos locales) ### Uso en PΓ‘ginas 1. PΓ‘gina necesita contenido β†’ Llama a `contentAdapter.getProtocol(id)` 2. `ContentAdapterFactory` devuelve el adapter activo 3. Adapter busca en su fuente (pack o local) 4. Retorna contenido o `null` (fallback) ### ActualizaciΓ³n del Pack 1. Backend genera nuevo pack β†’ Guarda en `storage/content-pack/` 2. Frontend detecta nueva versiΓ³n (hash diferente) 3. Descarga nuevo pack 4. Actualiza cache --- ## 🌐 API y Endpoints ### Content Pack #### GET `/api/content-pack/latest.json` Obtiene el Content Pack mΓ‘s reciente. **Respuesta:** ```json { "version": "1.0.0", "generatedAt": "2025-01-06T12:00:00Z", "hash": "sha256:...", "content": {...}, "media": {...} } ``` **Headers:** - `ETag`: Hash del pack - `Cache-Control`: `public, max-age=3600` #### GET `/api/content-pack/:version.json` Obtiene una versiΓ³n especΓ­fica del Content Pack. --- ## πŸ“¦ Content Pack ### GeneraciΓ³n El Content Pack se genera automΓ‘ticamente: 1. **On-the-fly:** Si no existe archivo, se genera al solicitar 2. **Programado:** Se puede generar periΓ³dicamente (cron job) 3. **Manual:** Desde admin panel ### Estructura de Contenido Cada item en el pack tiene esta estructura: ```typescript interface ContentItem { id: string; type: 'protocol' | 'guide' | 'drug' | 'checklist' | 'manual'; slug: string; title: string; shortTitle?: string; description: string; content: any; // Estructura especΓ­fica por tipo priority: 'critical' | 'high' | 'medium' | 'low'; status: 'draft' | 'in_review' | 'approved' | 'published'; version: string; // ... } ``` --- ## πŸ”— Enlaces Bidireccionales ### Mapeo **UbicaciΓ³n:** `src/data/protocol-guide-manual-mapping.ts` Define las relaciones entre: - Protocolos Operativos (Nivel 1) - GuΓ­as de Refuerzo (Nivel 2) - Manual Completo (Nivel 3) ### Uso en PΓ‘ginas ```typescript import { getProtocolRelations } from '@/services/content-relations'; const relations = getProtocolRelations('rcp-adulto-svb'); // Retorna: { protocol, guide, manual, mapping } ``` ### NavegaciΓ³n - **Desde Protocolo:** Enlaces a GuΓ­a y Manual - **Desde GuΓ­a:** Enlaces a Protocolo y Manual - **Desde Manual:** (Futuro) Enlaces a Protocolo y GuΓ­a --- ## πŸ’Ύ Sistema de Cache ### IndexedDB **Ventajas:** - Mayor capacidad (GBs) - Mejor rendimiento - API asΓ­ncrona **Uso:** ```typescript import { saveContentPack, getContentPack } from '@/utils/indexeddb'; // Guardar await saveContentPack(pack); // Obtener const cached = await getContentPack(24 * 60 * 60 * 1000); // 24 horas ``` ### localStorage (Fallback) Se usa automΓ‘ticamente si IndexedDB no estΓ‘ disponible. --- ## πŸ§ͺ Testing ### PΓ‘gina de Testing **Ruta:** `/testing` Interfaz visual para ejecutar tests y ver resultados. ### Funciones de Testing **UbicaciΓ³n:** `src/utils/testing-helpers.ts` Tests disponibles: - `testContentAdapterAvailable()` - Verifica que el adapter estΓ‘ disponible - `testGetProtocols()` - Verifica obtenciΓ³n de protocolos - `testGetDrugs()` - Verifica obtenciΓ³n de fΓ‘rmacos - `testGetGuides()` - Verifica obtenciΓ³n de guΓ­as - `testProtocolToGuideRelations()` - Verifica relaciones - `testContentPackCache()` - Verifica cache ### Ejecutar Tests ```typescript import { runAllBasicTests, formatTestResults } from '@/utils/testing-helpers'; const results = runAllBasicTests(); console.log(formatTestResults(results)); ``` --- ## πŸ“– GuΓ­a de Uso ### Para Desarrolladores #### Obtener Contenido ```typescript import { getProtocol, getAllProtocols } from '@/services/content-adapter'; // Obtener protocolo especΓ­fico const protocol = getProtocol('rcp-adulto-svb'); // Obtener todos los protocolos const protocols = getAllProtocols(); ``` #### Usar Hooks ```typescript import { useProtocolAdapter, useGuideAdapter } from '@/services/content-adapter'; function MyComponent() { const { protocol, isLoading, isExternal } = useProtocolAdapter('rcp-adulto-svb'); if (isLoading) return
Cargando...
; if (!protocol) return
No encontrado
; return (

{protocol.title}

{isExternal && Contenido Externo}
); } ``` #### Obtener Relaciones ```typescript import { getProtocolRelations } from '@/services/content-relations'; const relations = getProtocolRelations('rcp-adulto-svb'); if (relations.guide) { // Hay guΓ­a relacionada } if (relations.manual) { // Hay manual relacionado } ``` ### Para Administradores #### Generar Content Pack 1. Acceder al Admin Panel 2. Ir a "Content Pack" 3. Hacer clic en "Generar Pack" 4. El pack se genera y se guarda automΓ‘ticamente #### Verificar Cache 1. Abrir DevTools (F12) 2. Ir a Application β†’ IndexedDB 3. Verificar `guia-tes-content` β†’ `content-pack` --- ## πŸ”§ Troubleshooting ### El Content Pack no se carga **SΓ­ntomas:** - No aparece badge "Externo" - Contenido siempre es local **Soluciones:** 1. Verificar que el backend estΓ‘ corriendo 2. Verificar endpoint `/api/content-pack/latest.json` 3. Revisar consola del navegador para errores 4. Verificar que el pack se genera correctamente ### Cache no funciona **SΓ­ntomas:** - El pack se descarga cada vez - No se guarda en IndexedDB **Soluciones:** 1. Verificar permisos de IndexedDB en el navegador 2. Verificar que hay espacio disponible 3. Revisar consola para errores 4. El sistema fallback a localStorage automΓ‘ticamente ### Enlaces bidireccionales no funcionan **SΓ­ntomas:** - Enlaces no aparecen - Enlaces rotos **Soluciones:** 1. Verificar que el mapeo existe en `protocol-guide-manual-mapping.ts` 2. Verificar que las IDs coinciden 3. Revisar consola para errores 4. Usar pΓ‘gina de testing para verificar relaciones --- ## πŸ“Š EstadΓ­sticas del Sistema ### Capacidad - **IndexedDB:** Hasta varios GBs - **localStorage:** ~5-10MB - **Content Pack:** TΓ­picamente < 5MB ### Rendimiento - **Carga inicial:** < 500ms (con cache) - **Carga sin cache:** 1-3s (depende del tamaΓ±o) - **BΓΊsqueda:** < 10ms (en memoria) ### Compatibilidad - βœ… Chrome/Edge (IndexedDB + localStorage) - βœ… Firefox (IndexedDB + localStorage) - βœ… Safari (IndexedDB + localStorage) - βœ… Mobile browsers (IndexedDB + localStorage) --- ## πŸš€ PrΓ³ximas Mejoras 1. **CompresiΓ³n del Pack:** Comprimir JSON antes de enviar 2. **Differential Updates:** Solo actualizar cambios 3. **Service Worker:** Cache mΓ‘s agresivo 4. **Analytics:** Tracking de uso del contenido 5. **A/B Testing:** MΓΊltiples versiones de contenido --- ## πŸ“ Notas TΓ©cnicas ### Seguridad - El Content Pack es pΓΊblico (no contiene datos sensibles) - AutenticaciΓ³n solo para admin panel - ValidaciΓ³n de contenido antes de publicar ### Escalabilidad - El sistema puede manejar miles de items - IndexedDB escala bien con grandes volΓΊmenes - El pack se puede dividir por categorΓ­as si crece mucho ### Mantenibilidad - CΓ³digo modular y desacoplado - FΓ‘cil de extender con nuevos tipos de contenido - Testing integrado --- **Última actualizaciΓ³n:** 2025-01-06 **Mantenido por:** Equipo de Desarrollo TES