16 KiB
📚 Sistema de Gestión de Contenido - Documentación Completa
Versión: 1.0.0
Fecha: 2025-01-06
Estado: ✅ Completado
📋 Tabla de Contenidos
- Resumen Ejecutivo
- Arquitectura del Sistema
- Componentes Principales
- Flujo de Datos
- API y Endpoints
- Content Pack
- ContentAdapter
- Enlaces Bidireccionales
- Sistema de Cache
- Testing
- Guía de Uso
- 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:
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:
{
"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 relacionadagetProtocolForGuide(guideId)- Obtiene protocolo relacionadogetProtocolRelations(protocolId)- Obtiene todas las relacionesgetGuideRelations(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
- App inicia →
ContentAdapterFactoryse inicializa ExternalContentAdapterintenta cargar Content Pack:- Primero desde IndexedDB (cache)
- Si no hay cache o está expirado, descarga desde API
- Guarda en cache
- Si falla, usa
LocalContentAdapter(datos locales)
Uso en Páginas
- Página necesita contenido → Llama a
contentAdapter.getProtocol(id) ContentAdapterFactorydevuelve el adapter activo- Adapter busca en su fuente (pack o local)
- Retorna contenido o
null(fallback)
Actualización del Pack
- Backend genera nuevo pack → Guarda en
storage/content-pack/ - Frontend detecta nueva versión (hash diferente)
- Descarga nuevo pack
- Actualiza cache
🌐 API y Endpoints
Content Pack
GET /api/content-pack/latest.json
Obtiene el Content Pack más reciente.
Respuesta:
{
"version": "1.0.0",
"generatedAt": "2025-01-06T12:00:00Z",
"hash": "sha256:...",
"content": {...},
"media": {...}
}
Headers:
ETag: Hash del packCache-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:
- On-the-fly: Si no existe archivo, se genera al solicitar
- Programado: Se puede generar periódicamente (cron job)
- Manual: Desde admin panel
Estructura de Contenido
Cada item en el pack tiene esta estructura:
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
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:
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á disponibletestGetProtocols()- Verifica obtención de protocolostestGetDrugs()- Verifica obtención de fármacostestGetGuides()- Verifica obtención de guíastestProtocolToGuideRelations()- Verifica relacionestestContentPackCache()- Verifica cache
Ejecutar Tests
import { runAllBasicTests, formatTestResults } from '@/utils/testing-helpers';
const results = runAllBasicTests();
console.log(formatTestResults(results));
📖 Guía de Uso
Para Desarrolladores
Obtener Contenido
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
import { useProtocolAdapter, useGuideAdapter } from '@/services/content-adapter';
function MyComponent() {
const { protocol, isLoading, isExternal } = useProtocolAdapter('rcp-adulto-svb');
if (isLoading) return <div>Cargando...</div>;
if (!protocol) return <div>No encontrado</div>;
return (
<div>
<h1>{protocol.title}</h1>
{isExternal && <span>Contenido Externo</span>}
</div>
);
}
Obtener Relaciones
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
- Acceder al Admin Panel
- Ir a "Content Pack"
- Hacer clic en "Generar Pack"
- El pack se genera y se guarda automáticamente
Verificar Cache
- Abrir DevTools (F12)
- Ir a Application → IndexedDB
- Verificar
guia-tes-content→content-pack
🔧 Troubleshooting
El Content Pack no se carga
Síntomas:
- No aparece badge "Externo"
- Contenido siempre es local
Soluciones:
- Verificar que el backend está corriendo
- Verificar endpoint
/api/content-pack/latest.json - Revisar consola del navegador para errores
- Verificar que el pack se genera correctamente
Cache no funciona
Síntomas:
- El pack se descarga cada vez
- No se guarda en IndexedDB
Soluciones:
- Verificar permisos de IndexedDB en el navegador
- Verificar que hay espacio disponible
- Revisar consola para errores
- El sistema fallback a localStorage automáticamente
Enlaces bidireccionales no funcionan
Síntomas:
- Enlaces no aparecen
- Enlaces rotos
Soluciones:
- Verificar que el mapeo existe en
protocol-guide-manual-mapping.ts - Verificar que las IDs coinciden
- Revisar consola para errores
- 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
- Compresión del Pack: Comprimir JSON antes de enviar
- Differential Updates: Solo actualizar cambios
- Service Worker: Cache más agresivo
- Analytics: Tracking de uso del contenido
- 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