# 📐 MODELO DE DATOS CANÓNICO - SISTEMA DE CONTENIDO **Versión:** 1.0.0 **Fecha:** 2025-01-06 **Estado:** FASE 4 - Base de Contenido --- ## 🎯 PROPÓSITO Este documento define el **modelo de datos canónico** para el sistema de gestión de contenido externo de la app TES. **Características:** - ✅ Completamente desacoplado del código de la app - ✅ No modifica `procedures.ts`, `drugs.ts` ni componentes existentes - ✅ Diseñado para durabilidad (10+ años) - ✅ Optimizado para uso real de TES en guardia - ✅ Soporta formación continua y referencia profesional --- ## 🏗️ ARQUITECTURA DEL MODELO ``` ┌─────────────────────────────────────────┐ │ CONTENT ITEM (Base) │ │ ┌─────────┬─────────┬──────────────┐ │ │ │Protocol │ Guide │ Manual │ │ │ │ Drug │ Checklist│ │ │ │ └─────────┴─────────┴──────────────┘ │ └─────────────────────────────────────────┘ │ │ (asociación) ▼ ┌─────────────────────────────────────────┐ │ MEDIA RESOURCE │ │ ┌─────────┬─────────┐ │ │ │ Image │ Video │ │ │ └─────────┴─────────┘ │ └─────────────────────────────────────────┘ │ │ (versión) ▼ ┌─────────────────────────────────────────┐ │ CONTENT VERSION │ │ (Historial y rollback) │ └─────────────────────────────────────────┘ │ │ (auditoría) ▼ ┌─────────────────────────────────────────┐ │ AUDIT LOG │ │ (Trazabilidad completa) │ └─────────────────────────────────────────┘ ``` --- ## 📋 ENTIDADES PRINCIPALES ### 1. ContentItem **Descripción:** Entidad base que representa todo el contenido del sistema. **Tipos:** - `protocol`: Protocolos operativos (RCP, OVACE, ABCDE, etc.) - `guide`: Guías formativas (8 secciones) - `manual`: Capítulos del manual completo - `drug`: Fármacos del vademécum - `checklist`: Checklists reutilizables **Campos Clave:** | Campo | Tipo | Descripción | Ejemplo | |-------|------|-------------|---------| | `id` | UUID | Identificador único | `550e8400-e29b-41d4-a716-446655440000` | | `type` | enum | Tipo de contenido | `protocol` | | `slug` | string | Slug para URLs | `rcp-adulto-svb` | | `title` | string | Título completo | `RCP Adulto - Soporte Vital Básico` | | `clinical_context` | enum | Contexto clínico | `RCP` | | `usage_type` | enum | Tipo de uso | `operativo` | | `priority` | enum | Prioridad clínica | `critica` | | `status` | enum | Estado | `published` | | `source_guideline` | enum | Fuente clínica | `ERC` | | `version` | string | Versión semántica | `1.0.0` | | `content` | JSONB | Contenido específico | Ver secciones siguientes | **Ejemplo Real: RCP Adulto SVB** ```typescript { id: "550e8400-e29b-41d4-a716-446655440000", type: "protocol", slug: "rcp-adulto-svb", title: "RCP Adulto - Soporte Vital Básico", short_title: "RCP Adulto SVB", description: "Protocolo de reanimación cardiopulmonar básica en adultos", clinical_context: "RCP", usage_type: "operativo", priority: "critica", status: "published", source_guideline: "ERC", source_year: 2021, source_url: "https://www.erc.edu/...", version: "1.0.0", latest_version: "1.0.0", content: { // Ver ProtocolContent }, tags: ["rcp", "svb", "adulto", "emergencia", "critica"], category: "soporte_vital", created_at: "2025-01-01T00:00:00Z", updated_at: "2025-01-06T12:00:00Z" } ``` --- ### 2. ProtocolContent **Descripción:** Contenido específico para protocolos operativos. **Estructura:** ```typescript interface ProtocolContent { steps: ProtocolStep[]; // Pasos operativos ordenados checklist?: { // Checklist integrado enabled: boolean; title?: string; items: ChecklistItem[]; }; inline_doses?: InlineDose[]; // Dosis inline context_tools?: ContextTool[]; // Herramientas de contexto clinical_sources?: ClinicalSource[]; // Fuentes clínicas warnings?: string[]; // Advertencias críticas key_points?: string[]; // Puntos clave equipment?: string[]; // Equipamiento necesario drugs?: string[]; // Referencias a fármacos age_group?: 'adulto' | 'pediatrico' | 'neonatal' | 'todos'; estimated_duration?: string; // Duración estimada } ``` **Ejemplo: Paso de Protocolo** ```typescript { order: 7, text: "Iniciar compresiones torácicas: 30 compresiones", critical: true, equipment: ["DEA"], time_estimate: "20-30s", notes: "Profundidad 5-6 cm, frecuencia 100-120/min" } ``` --- ### 3. GuideContent **Descripción:** Contenido específico para guías formativas (8 secciones). **Estructura:** ```typescript interface GuideContent { sections: GuideSection[]; // Siempre 8 secciones related_protocol_id?: string; // Protocolo operativo relacionado related_manual_ids?: string[]; // Capítulos de manual relacionados learning_objectives?: string[]; // Objetivos de aprendizaje prerequisites?: string[]; // Prerrequisitos target_audience?: string[]; // Audiencia objetivo estimated_time?: string; // Tiempo total estimado } ``` **Ejemplo: Sección de Guía** ```typescript { numero: 4, titulo: "Medios Visuales y Demostración", markdown: "# Medios Visuales...", estimated_time: "10 min", resources: { images: ["660e8400-..."], videos: ["660e8400-..."], links: [ { title: "ERC Guidelines", url: "https://..." } ] } } ``` --- ### 4. MediaResource **Descripción:** Recurso multimedia (imagen o vídeo). **Tipos:** - `image`: Infografías, diagramas, fotografías - `video`: Vídeos demostrativos, formativos **Campos Clave:** | Campo | Tipo | Descripción | Ejemplo | |-------|------|-------------|---------| | `id` | UUID | Identificador único | `660e8400-...` | | `type` | enum | Tipo de recurso | `image` | | `file_url` | string | URL completa | `https://...supabase.co/...` | | `title` | string | Título | `Posición de Manos - RCP Adulto` | | `alt_text` | string | Texto alternativo | `Posición correcta de manos...` | | `priority` | enum | Prioridad | `critica` | | `usage_type` | array | Tipos de uso | `["operativo", "formativo"]` | | `tags` | array | Tags | `["rcp", "adulto", "compresiones"]` | **Ejemplo: Imagen** ```typescript { id: "660e8400-e29b-41d4-a716-446655440000", type: "image", file_url: "https://[project].supabase.co/storage/v1/object/public/infografias/rcp/rcp_posicion_manos_adulto.png", filename: "rcp_posicion_manos_adulto.png", path: "/assets/infografias/rcp/rcp_posicion_manos_adulto.png", title: "Posición de Manos - RCP Adulto", alt_text: "Posición correcta de manos para compresiones torácicas RCP adulto", caption: "Posición correcta de manos para compresiones torácicas", tags: ["rcp", "adulto", "compresiones", "posicion", "operativo"], block: "bloque-4-soporte-vital", priority: "critica", usage_type: ["operativo"], width: 1200, height: 800, format: "png", file_size: 245678, status: "published" } ``` **Ejemplo: Vídeo** ```typescript { id: "660e8400-e29b-41d4-a716-446655440002", type: "video", file_url: "https://[project].supabase.co/storage/v1/object/public/videos/rcp/rcp_adulto_svb.mp4", thumbnail_url: "https://[project].supabase.co/storage/v1/object/public/videos/rcp/rcp_adulto_svb_thumb.jpg", filename: "rcp_adulto_svb.mp4", path: "/assets/videos/rcp/rcp_adulto_svb.mp4", title: "RCP Adulto SVB - Técnica Completa", alt_text: "Vídeo demostrativo RCP Adulto SVB", caption: "Técnica completa de RCP Adulto SVB", tags: ["rcp", "adulto", "svb", "video", "operativo"], block: "bloque-4-soporte-vital", priority: "critica", usage_type: ["operativo"], duration_seconds: 45, video_format: "mp4", file_size: 5242880, status: "published" } ``` --- ### 5. ContentResourceAssociation **Descripción:** Asociación entre contenido y recursos multimedia. **Propósito:** - Define dónde se muestra un recurso en un contenido - Permite múltiples asociaciones (mismo recurso en diferentes secciones) - Define prioridad y criticidad **Ejemplo:** ```typescript { id: "770e8400-e29b-41d4-a716-446655440000", content_item_id: "550e8400-e29b-41d4-a716-446655440000", // RCP Adulto SVB media_resource_id: "660e8400-e29b-41d4-a716-446655440000", // Imagen posición manos section: "pasos", position: 7, placement: "inline", caption: "Posición correcta de manos para compresiones", is_critical: true, priority: "critica" } ``` **Secciones Comunes:** - `pasos`: En pasos de protocolo - `checklist`: En checklist integrado - `guia_seccion_1` a `guia_seccion_8`: En secciones de guía - `manual_intro`: En introducción de manual - `manual_contenido`: En contenido principal de manual --- ### 6. ContentVersion **Descripción:** Versión histórica de un ContentItem. **Propósito:** - Versionado semántico (1.2.3) - Rollback a versiones anteriores - Historial de cambios **Ejemplo:** ```typescript { id: "880e8400-e29b-41d4-a716-446655440000", content_item_id: "550e8400-e29b-41d4-a716-446655440000", version: "1.1.0", content: { // Contenido de esta versión }, change_summary: "Añadido paso de verificación de seguridad, actualizado checklist", is_breaking: false, created_by: "editor-123", created_at: "2025-01-10T10:00:00Z", is_active: false } ``` --- ### 7. AuditLog **Descripción:** Registro de auditoría de todas las acciones. **Propósito:** - Trazabilidad completa - Cumplimiento normativo - Análisis de uso **Ejemplo:** ```typescript { id: "990e8400-e29b-41d4-a716-446655440000", entity_type: "content_item", entity_id: "550e8400-e29b-41d4-a716-446655440000", action: "publish", user_id: "user-456", user_role: "editor", metadata: { previous_status: "approved", new_status: "published", version: "1.0.0" }, timestamp: "2025-01-06T12:00:00Z" } ``` --- ## 🔗 RELACIONES ENTRE ENTIDADES ### Diagrama de Relaciones ``` ContentItem (1) ──< (N) ContentResourceAssociation (N) >── (1) MediaResource │ │ (1) │ └──< (N) ContentVersion ContentItem (1) ──< (N) AuditLog MediaResource (1) ──< (N) AuditLog ContentVersion (1) ──< (N) AuditLog ``` ### Relaciones Bidireccionales **Protocolo ↔ Guía:** - Protocolo tiene `related_guide_ids[]` - Guía tiene `related_protocol_id` **Manual ↔ Protocolo/Guía:** - Manual tiene `related_protocol_ids[]` y `related_guide_ids[]` - Protocolo/Guía tienen `related_manual_ids[]` --- ## 📊 EJEMPLOS REALES COMPLETOS ### Ejemplo 1: Protocolo RCP Adulto SVB Ver `docs/CONTENT_PACK_SPEC.md` sección "Ejemplo Completo" ### Ejemplo 2: Guía ABCDE Formativa ```typescript { id: "550e8400-e29b-41d4-a716-446655440010", type: "guide", slug: "abcde-operativo", title: "ABCDE Operativo", description: "Guía de refuerzo para comprender el enfoque ABCDE", clinical_context: "ABCDE", usage_type: "formativo", priority: "alta", status: "published", source_guideline: "MANUAL_TES_DIGITAL", version: "1.0.0", content: { sections: [ { numero: 1, titulo: "Introducción y Contexto", markdown: "# Introducción...", resources: { images: ["660e8400-..."] // Infografía introducción } }, // ... 7 secciones más ], related_protocol_id: "550e8400-...", // ABCDE Operativo learning_objectives: [ "Comprender ABCDE como estructura mental", "Aplicar ABCDE en todas las emergencias" ] }, related_protocol_ids: ["550e8400-..."], tags: ["abcde", "evaluacion", "formacion"] } ``` ### Ejemplo 3: Fármaco Adrenalina ```typescript { id: "550e8400-e29b-41d4-a716-446655440020", type: "drug", slug: "adrenalina", title: "Adrenalina (Epinefrina)", description: "Fármaco de primera línea en PCR y anafilaxia", clinical_context: "FARMACOLOGIA", usage_type: "referencia", priority: "critica", status: "published", source_guideline: "ERC", source_year: 2021, version: "1.0.0", content: { generic_name: "Adrenalina", trade_name: "Adrenalina", category: "cardiovascular", presentation: "Ampollas 1mg/1ml", adult_dose: "1mg IV cada 3-5 min (PCR)", pediatric_dose: "0.01 mg/kg IV cada 3-5 min (PCR)", routes: ["IV", "IO", "IM"], indications: ["PCR", "Anafilaxia", "Shock anafiláctico"], contraindications: ["Hipersensibilidad"], side_effects: ["Taquicardia", "Hipertensión"], notes: [ "Primera línea en PCR", "En anafilaxia: 0.3-0.5 mg IM" ], critical_points: [ "NO diluir en PCR", "Administrar lo antes posible" ] }, tags: ["adrenalina", "epinefrina", "pcr", "anafilaxia", "critica"] } ``` --- ## ✅ VALIDACIONES Y CONSTRAINTS ### Validaciones de Contenido 1. **ContentItem:** - `slug` debe ser único - `version` debe seguir semver (1.2.3) - `status` debe ser válido según flujo - `clinical_context` debe ser válido 2. **ProtocolContent:** - `steps` debe tener al menos 1 paso - `steps[].order` debe ser secuencial (1, 2, 3...) - `checklist.items` debe tener al menos 1 item si `enabled: true` 3. **GuideContent:** - `sections` debe tener exactamente 8 secciones - `sections[].numero` debe ser 1-8 - `sections[].markdown` no debe estar vacío 4. **MediaResource:** - `file_url` debe ser URL válida - `alt_text` no debe estar vacío (accesibilidad) - Si `type: 'video'`, `duration_seconds` debe estar presente 5. **ContentResourceAssociation:** - `content_item_id` debe existir - `media_resource_id` debe existir - `section` + `position` debe ser único por `content_item_id` --- ## 🔍 BÚSQUEDA Y FILTRADO ### Índices Recomendados 1. **Búsqueda de texto:** - `title`, `description`, `tags` → Índice GIN (full-text search) 2. **Filtrado por tipo:** - `type`, `usage_type`, `status`, `priority` → Índices B-tree 3. **Búsqueda por contexto:** - `clinical_context`, `category` → Índices B-tree 4. **Relaciones:** - `related_*_ids` → Índices GIN (array search) --- ## 📚 REFERENCIAS - **Interfaces TypeScript:** `admin-panel/shared/types/content-canonical.ts` - **Schema SQL:** `docs/SUPABASE_SCHEMA.sql` - **Content Pack Spec:** `docs/CONTENT_PACK_SPEC.md` - **Plan Técnico:** `docs/PLAN_TECNICO_SISTEMA_CONTENIDO.md` --- **Fin del Documento**