codigo0/docs/MODELO_DATOS_CANONICO_DEFINITIVO.md

39 KiB

📐 MODELO DE DATOS CANÓNICO DEFINITIVO

Proyecto: Guía TES - Sistema de Gestión de Contenido
Fuente de Verdad: FASE B - Matriz Maestra de Contenidos (15 temas críticos)
Fecha: 2025-01-06
Arquitecto: Sistema de Contenido
Estado: DEFINITIVO


🎯 PRINCIPIOS FUNDAMENTALES

Este modelo es la ÚNICA FUENTE DE VERDAD para el sistema de contenidos. Se basa en:

  1. FASE B validada: Los 15 temas críticos confirmados
  2. Separación de capas: Operativa, Formativa, Referencia (NUNCA mezclar)
  3. Versionado completo: Todo contenido es versionable y reversible
  4. Trazabilidad total: Auditoría completa de todas las acciones
  5. Validación clínica: Workflow de validación con roles TES/Medico/Formador
  6. Offline-first: Todo debe funcionar sin conexión
  7. SCORM-ready: Guías formativas exportables a SCORM 1.2

📊 ENTIDADES PRINCIPALES

1. CONTENIDO (ContentItem)

Definición: Cualquier pieza de contenido del sistema: protocolos, guías, manual, fármacos, checklists.

Regla de Oro: Cada ContentItem pertenece a UNA SOLA capa funcional (operativa, formativa, referencia). NUNCA mezclar.

1.1 Identificación y Clasificación

ContentItem {
  // ============================================
  // IDENTIFICACIÓN ÚNICA
  // ============================================
  id: UUID                    // ID único e inmutable (generado por BD)
  slug: String                // Identificador legible único (ej: "control-hemorragias-externas")
  version: String             // Versión semántica actual (ej: "1.2.3")
  latest_version: String      // Última versión disponible (ej: "1.2.3")
  is_latest: Boolean          // ¿Es la última versión? (derivado)
  
  // ============================================
  // CLASIFICACIÓN POR TIPO
  // ============================================
  type: Enum                  // 'protocol' | 'guide' | 'manual' | 'drug' | 'checklist'
  
  // ============================================
  // CLASIFICACIÓN CLÍNICA (FASE B)
  // ============================================
  // Basado en los 15 temas críticos de FASE B
  clinical_topic: Enum        // 'hemorragias_externas' | 'torniquetes' | 'convulsiones' |
                              // 'aspiracion_secreciones' | 'ventilacion_ambu' | 
                              // 'reevaluacion_abcde' | 'valoracion_secundaria_sample' |
                              // 'shock_hipovolemico' | 'shock_septico' | 'ictus_completo' |
                              // 'trauma_politrauma' | 'tce' | 'alteracion_conciencia' |
                              // 'vademecum_tes' | 'preparacion_intubacion'
  
  category: String            // Categoría general (ej: "soporte_vital", "trauma", "farmacologia")
  subcategory: String?        // Subcategoría específica (ej: "hemorragia", "shock", "rcp")
  
  // ============================================
  // CAPA FUNCIONAL (CRÍTICO: NO MEZCLAR)
  // ============================================
  functional_layer: Enum      // 'operativa' | 'formativa' | 'referencia'
  
  // Regla: Un ContentItem SOLO puede tener contenido de UNA capa
  // Ejemplo: Un protocolo es SIEMPRE operativa, una guía es SIEMPRE formativa
  
  // ============================================
  // METADATOS BÁSICOS
  // ============================================
  title: String               // Título completo (ej: "Control de Hemorragias Externas")
  short_title: String?        // Título corto para UI (ej: "Hemorragias")
  description: String         // Descripción breve (1-2 líneas)
  keywords: String[]          // Palabras clave para búsqueda
  
  // ============================================
  // CONTENIDO ESPECÍFICO (JSON flexible)
  // ============================================
  content: JSON               // Estructura específica por tipo y capa (ver secciones siguientes)
  
  // ============================================
  // PRIORIDAD Y CLASIFICACIÓN CLÍNICA
  // ============================================
  priority: Enum              // 'critical' | 'high' | 'medium' | 'low'
  clinical_priority: Enum?    // Prioridad clínica específica (si aplica)
  age_group: Enum?            // 'adulto' | 'pediatrico' | 'neonatal' | 'todos'
  
  // ============================================
  // ESTADO Y VALIDACIÓN
  // ============================================
  status: Enum                // 'draft' | 'in_review' | 'approved' | 'published' | 'archived'
  
  // Workflow de validación (ver entidad ValidationWorkflow)
  validation_status: Enum?   // 'pending' | 'validated' | 'rejected'
  validated_by: UUID?         // Usuario que validó (TES, Médico, Formador)
  validated_at: Timestamp?   // Fecha de validación
  validation_expires_at: Timestamp?  // Fecha de expiración de validación
  
  // ============================================
  // RELACIONES CON OTRO CONTENIDO
  // ============================================
  // Relaciones bidireccionales (ver entidad ContentRelation)
  related_content_ids: UUID[] // IDs de contenido relacionado (derivado de ContentRelation)
  
  // Relaciones específicas por tipo (para facilitar queries)
  related_protocol_ids: UUID[]    // Si es guía, protocolos relacionados
  related_guide_ids: UUID[]       // Si es protocolo, guías relacionadas
  related_manual_ids: UUID[]      // Si es protocolo/guía, manual relacionado
  
  // ============================================
  // RECURSOS MULTIMEDIA ASOCIADOS
  // ============================================
  // Relaciones con recursos (ver entidad ContentResourceRelation)
  media_resource_ids: UUID[] // IDs de recursos asociados (derivado)
  
  // ============================================
  // SCORM (Solo para guías formativas)
  // ============================================
  scorm_enabled: Boolean      // ¿Tiene versión SCORM disponible?
  scorm_package_id: UUID?     // ID del paquete SCORM generado (ver entidad SCORMPackage)
  scorm_version: String?      // Versión SCORM (ej: "1.2")
  
  // ============================================
  // FUENTE Y TRAZABILIDAD
  // ============================================
  source_guideline: Enum      // 'ERC' | 'SEMES' | 'AHA' | 'INTERNO' | 'MANUAL_TES_DIGITAL'
  source_reference: String?   // Referencia específica (ej: "BLOQUE_03_6_CONTROL_HEMORRAGIAS.md")
  source_year: Integer?       // Año de la fuente
  source_url: String?         // URL de la fuente (si aplica)
  
  // ============================================
  // METADATOS DE GESTIÓN
  // ============================================
  created_by: UUID             // Usuario que creó
  created_at: Timestamp       // Fecha de creación
  updated_by: UUID             // Usuario que actualizó
  updated_at: Timestamp        // Fecha de última actualización
  published_by: UUID?          // Usuario que publicó
  published_at: Timestamp?     // Fecha de publicación (si está published)
  
  // ============================================
  // METADATOS ADICIONALES (JSON flexible)
  // ============================================
  metadata: JSON               // {
                                //   "tiempo_lectura": 15,        // minutos
                                //   "dificultad": "intermedio",  // basico | intermedio | avanzado
                                //   "checklist_mode": true,      // Si tiene modo checklist
                                //   "secciones_count": 8,        // Para guías
                                //   "steps_count": 10,           // Para protocolos
                                //   ...
                                // }
}

1.2 Estructura de content por Tipo y Capa

PROTOCOLO OPERATIVO (type='protocol', functional_layer='operativa'):

{
  "steps": [
    {
      "order": 1,
      "text": "Texto del paso",
      "critical": false,              // ¿Es paso crítico?
      "verification": "¿Verificación opcional?",
      "warnings": ["Advertencia 1"],
      "media_resource_ids": ["uuid-imagen-paso"]
    }
  ],
  "warnings": ["Advertencia global 1"],
  "key_points": ["Punto clave 1"],
  "equipment": [
    {
      "name": "Equipo 1",
      "required": true,
      "media_resource_id": "uuid-imagen-equipo"
    }
  ],
  "drugs": ["Fármaco 1", "Fármaco 2"],
  "checklist_mode": true,            // ¿Tiene modo checklist?
  "checklist_steps": [
    {
      "order": 1,
      "text": "Paso checklist",
      "critical": true
    }
  ],
  "category": "soporte_vital",
  "subcategory": "rcp",
  "age_group": "adulto"
}

GUÍA FORMATIVA (type='guide', functional_layer='formativa'):

{
  "secciones": [
    {
      "numero": 1,
      "titulo": "Introducción y Contexto",
      "archivo": "SECCION_01_NOMBRE.md",
      "ruta": "/docs/consolidado/SECCION_01_NOMBRE.md",
      "contenido_markdown": "...",    // Contenido Markdown completo
      "tiempo_estimado": 5,            // minutos
      "media_resource_ids": ["uuid-imagen-1", "uuid-video-1"]
    }
  ],
  "protocolo_operativo": {
    "id": "uuid-protocolo",
    "slug": "control-hemorragias",
    "titulo": "Control de Hemorragias Externas",
    "ruta": "/protocolos/control-hemorragias"
  },
  "scorm_available": true,
  "tiempo_total_estimado": 40,
  "objetivos_aprendizaje": [
    "Objetivo 1",
    "Objetivo 2"
  ]
}

MANUAL REFERENCIA (type='manual', functional_layer='referencia'):

{
  "parte": 1,
  "parte_nombre": "Fundamentos y Evaluación Inicial",
  "bloque": 0,
  "bloque_nombre": "Fundamentos de Emergencias Prehospitalarias",
  "capitulo": "1.1.1",
  "ruta_archivo": "/manual/BLOQUE_XX/ARCHIVO.md",
  "ruta_url": "/manual/parte-i/bloque-0/1.1.1",
  "contenido_markdown": "...",
  "nivel_dificultad": "basico",       // basico | intermedio | avanzado
  "importancia": "alta",              // alta | media | baja
  "tiempo_lectura": 15,               // minutos
  "navegacion": {
    "anterior": "1.0.1",
    "siguiente": "1.1.2",
    "relacionados": ["1.1.2", "1.1.3"]
  }
}

FÁRMACO REFERENCIA (type='drug', functional_layer='referencia'):

{
  "generic_name": "Nombre genérico",
  "trade_name": "Nombre comercial",
  "category": "cardiovascular",
  "presentation": "Presentación",
  "adult_dose": "Dosis adulto",
  "pediatric_dose": "Dosis pediátrica",
  "routes": ["IV", "IM"],
  "dilution": "Dilución",
  "indications": ["Indicación 1"],
  "contraindications": ["Contraindicación 1"],
  "side_effects": ["Efecto adverso 1"],
  "antidote": "Antídoto",
  "notes": ["Nota 1"],
  "critical_points": ["Punto crítico TES 1"],
  "source": "Fuente"
}

CHECKLIST OPERATIVA (type='checklist', functional_layer='operativa'):

{
  "phase": "pre_escena",              // 'inicio_turno' | 'pre_escena' | 'post_servicio'
  "sections": [
    {
      "id": "seccion-1",
      "title": "Título sección",
      "category": "oxigeno",
      "items": [
        {
          "id": "item-1",
          "text": "Texto del item",
          "critical": false
        }
      ],
      "notes": "Notas opcionales"
    }
  ]
}

2. RECURSOS MULTIMEDIA (MediaResource)

Definición: Imágenes, vídeos y otros recursos visuales asociados al contenido.

MediaResource {
  // ============================================
  // IDENTIFICACIÓN
  // ============================================
  id: UUID                    // ID único
  filename: String            // Nombre del archivo (ej: "hemorragia_presion_directa.jpg")
  path: String                // Ruta relativa en servidor (ej: "/storage/media/images/hemorragia/...")
  url: String?                // URL pública completa (si está en CDN)
  thumbnail_url: String?      // URL del thumbnail (para vídeos)
  
  // ============================================
  // TIPO Y FORMATO
  // ============================================
  type: Enum                  // 'image' | 'video' | 'audio' | 'document'
  format: String              // 'jpg' | 'png' | 'svg' | 'webp' | 'mp4' | 'webm' | 'pdf'
  mime_type: String           // 'image/jpeg', 'video/mp4', etc.
  
  // ============================================
  // METADATOS VISUALES
  // ============================================
  alt: String                 // Texto alternativo (accesibilidad - OBLIGATORIO)
  caption: String?            // Caption opcional
  title: String?              // Título del recurso
  
  // ============================================
  // CLASIFICACIÓN
  // ============================================
  functional_layer: Enum[]    // ['operativa'] | ['formativa'] | ['referencia'] | 
                              // ['operativa', 'formativa'] (puede usarse en múltiples capas)
  
  clinical_topic: Enum?       // Mismo enum que ContentItem (si aplica a tema específico)
  category: String?           // Categoría (ej: "hemorragia", "rcp")
  tags: String[]              // Tags para búsqueda
  
  // ============================================
  // DIMENSIONES Y TAMAÑO
  // ============================================
  width: Integer?             // Ancho (para imágenes/vídeos)
  height: Integer?            // Alto (para imágenes/vídeos)
  file_size: Integer          // Tamaño en bytes
  duration: Integer?          // Duración en segundos (para vídeos/audio)
  
  // ============================================
  // PRIORIDAD Y USO
  // ============================================
  priority: Enum              // 'critical' | 'high' | 'medium' | 'low'
  usage_context: Enum[]      // ['operativo'] | ['formativo'] | ['referencia'] | 
                              // ['operativo', 'formativo'] (dónde se usa)
  
  // ============================================
  // FUENTE Y ATRIBUCIÓN
  // ============================================
  source: String?             // Fuente del recurso
  attribution: String?        // Atribución si es necesario
  license: String?            // Licencia (ej: "CC BY 4.0", "Propietario")
  
  // ============================================
  // ESTADO
  // ============================================
  status: Enum                // 'draft' | 'approved' | 'published' | 'archived'
  
  // ============================================
  // METADATOS DE GESTIÓN
  // ============================================
  uploaded_by: UUID           // Usuario que subió
  uploaded_at: Timestamp      // Fecha de subida
  updated_at: Timestamp       // Fecha de última actualización
  
  // ============================================
  // METADATOS ADICIONALES
  // ============================================
  metadata: JSON              // {
                                //   "original_filename": "...",
                                //   "compression": "lossy",
                                //   "color_space": "RGB",
                                //   ...
                                // }
}

3. RELACIONES CONTENIDO ⇄ RECURSOS (ContentResourceRelation)

Definición: Asociación entre contenido y recursos multimedia con contexto.

ContentResourceRelation {
  id: UUID
  content_id: UUID            // FK a ContentItem
  resource_id: UUID           // FK a MediaResource
  
  // ============================================
  // CONTEXTO DE LA RELACIÓN
  // ============================================
  context: String?            // Dónde se usa:
                              // - Para protocolos: "step-3", "checklist-item-5", "header"
                              // - Para guías: "seccion-2", "introduccion", "caso-clinico-1"
                              // - Para manual: "capitulo-1.1.1", "figura-3"
  
  placement: Enum             // 'inline' | 'before' | 'after' | 'modal' | 'sidebar'
  order: Integer?             // Orden de aparición (si hay múltiples en mismo contexto)
  
  // ============================================
  // PRIORIDAD Y CRITICIDAD
  // ============================================
  is_primary: Boolean         // ¿Es recurso principal? (para destacar)
  is_critical: Boolean        // ¿Es crítico para comprensión?
  priority: Enum              // 'critical' | 'high' | 'medium' | 'low'
  
  // ============================================
  // METADATOS
  // ============================================
  caption_override: String?   // Caption específico para este contexto (sobrescribe el del recurso)
  created_at: Timestamp
  created_by: UUID
}

4. RELACIONES CONTENIDO ⇄ CONTENIDO (ContentRelation)

Definición: Relaciones bidireccionales entre contenidos (Protocolo ↔ Guía ↔ Manual).

ContentRelation {
  id: UUID
  source_content_id: UUID     // FK a ContentItem (origen)
  target_content_id: UUID     // FK a ContentItem (destino)
  
  // ============================================
  // TIPO DE RELACIÓN
  // ============================================
  relation_type: Enum         // 'protocol_to_guide' | 'guide_to_protocol' |
                              // 'protocol_to_manual' | 'guide_to_manual' |
                              // 'manual_to_protocol' | 'manual_to_guide' |
                              // 'related' (contenido relacionado genérico)
  
  // ============================================
  // BIDIRECCIONALIDAD
  // ============================================
  is_bidirectional: Boolean   // ¿Es bidireccional?
                              // Si true, se crea automáticamente la relación inversa
  
  // ============================================
  // METADATOS
  // ============================================
  order: Integer?             // Orden de aparición (si hay múltiples relaciones)
  label: String?              // Etiqueta opcional (ej: "Guía formativa relacionada")
  metadata: JSON?              // {
                                //   "description": "Relación entre protocolo y guía",
                                //   "auto_generated": true,
                                //   ...
                                // }
  
  created_at: Timestamp
  created_by: UUID
}

Reglas:

  • Si is_bidirectional = true, el sistema crea automáticamente la relación inversa
  • Las relaciones protocol_to_guide y guide_to_protocol son siempre bidireccionales
  • Las relaciones protocol_to_manual y guide_to_manual pueden ser unidireccionales

5. VERSIONADO (ContentVersion)

Definición: Historial de versiones de contenido para versionado semántico y rollback.

ContentVersion {
  id: UUID
  content_id: UUID            // FK a ContentItem (versión actual)
  version: String             // Versión semántica (ej: "1.2.3")
  previous_version_id: UUID?  // FK a ContentVersion (versión anterior)
  
  // ============================================
  // CONTENIDO DE LA VERSIÓN
  // ============================================
  content: JSON               // Snapshot completo del contenido en esta versión
  content_hash: String        // Hash SHA-256 del contenido (para detectar cambios)
  
  // ============================================
  // CAMBIOS
  // ============================================
  change_summary: String       // Resumen de cambios (ej: "Añadido paso de torniquete")
  change_details: JSON        // Detalles de cambios:
                              // {
                              //   "added": ["step-5"],
                              //   "modified": ["step-3"],
                              //   "deleted": [],
                              //   "fields_changed": ["title", "content.steps"]
                              // }
  
  change_type: Enum           // 'major' | 'minor' | 'patch'
                              // - major: Cambios incompatibles (ej: estructura diferente)
                              // - minor: Nuevas funcionalidades compatibles
                              // - patch: Correcciones compatibles
  
  is_breaking: Boolean        // ¿Es cambio incompatible? (derivado de change_type)
  
  // ============================================
  // METADATOS
  // ============================================
  created_at: Timestamp
  created_by: UUID
  published_at: Timestamp?    // Fecha de publicación de esta versión
  published_by: UUID?         // Usuario que publicó esta versión
  
  // ============================================
  // ESTADO
  // ============================================
  is_active: Boolean          // ¿Es la versión activa? (solo una por content_id)
}

Reglas de Versionado:

  • Versionado semántico: MAJOR.MINOR.PATCH
  • Cada cambio crea una nueva versión
  • Solo una versión puede estar is_active = true por content_id
  • Las versiones anteriores se mantienen para rollback

6. VALIDACIÓN Y WORKFLOW (ValidationWorkflow)

Definición: Workflow completo de validación clínica con historial.

ValidationWorkflow {
  id: UUID
  content_id: UUID            // FK a ContentItem
  
  // ============================================
  // ESTADO ACTUAL
  // ============================================
  current_status: Enum        // 'draft' | 'submitted' | 'in_review' | 
                              // 'approved' | 'rejected' | 'published'
  
  // ============================================
  // HISTORIAL COMPLETO
  // ============================================
  history: JSON[]             // Array de eventos ordenados:
                              // [
                              //   {
                              //     "status": "draft",
                              //     "timestamp": "2025-01-06T10:00:00Z",
                              //     "user_id": "uuid",
                              //     "user_role": "editor_clinico",
                              //     "notes": "Creación inicial"
                              //   },
                              //   {
                              //     "status": "submitted",
                              //     "timestamp": "2025-01-06T11:00:00Z",
                              //     "user_id": "uuid",
                              //     "user_role": "editor_clinico",
                              //     "notes": "Enviado para revisión"
                              //   },
                              //   {
                              //     "status": "in_review",
                              //     "timestamp": "2025-01-06T12:00:00Z",
                              //     "user_id": "uuid",
                              //     "user_role": "tes_validador",
                              //     "reviewer_id": "uuid",
                              //     "notes": "En revisión por TES"
                              //   },
                              //   {
                              //     "status": "approved",
                              //     "timestamp": "2025-01-06T14:00:00Z",
                              //     "user_id": "uuid",
                              //     "user_role": "tes_validador",
                              //     "reviewer_id": "uuid",
                              //     "notes": "Aprobado para publicación"
                              //   }
                              // ]
  
  // ============================================
  // EVENTOS ESPECÍFICOS (para queries rápidas)
  // ============================================
  submitted_at: Timestamp?
  submitted_by: UUID?
  reviewed_at: Timestamp?
  reviewed_by: UUID?
  reviewer_role: Enum?        // 'tes_validador' | 'medico' | 'formador'
  approved_at: Timestamp?
  approved_by: UUID?
  rejected_at: Timestamp?
  rejected_by: UUID?
  rejection_reason: String?
  
  // ============================================
  // VALIDACIÓN CLÍNICA
  // ============================================
  clinical_validation: JSON?  // {
                                //   "validated_by_tes": true,
                                //   "validated_by_medico": false,
                                //   "validated_by_formador": true,
                                //   "validation_notes": "...",
                                //   "compliance_checklist": {
                                //     "protocolo_correcto": true,
                                //     "recursos_asociados": true,
                                //     "relaciones_correctas": true
                                //   }
                                // }
  
  // ============================================
  // METADATOS
  // ============================================
  updated_at: Timestamp
}

Workflow de Estados:

draft → submitted → in_review → approved → published
  ↓         ↓           ↓
rejected  rejected   rejected

7. SCORM (SCORMPackage)

Definición: Paquetes SCORM generados desde guías formativas.

SCORMPackage {
  id: UUID
  content_id: UUID            // FK a ContentItem (type='guide', functional_layer='formativa')
  
  // ============================================
  // IDENTIFICACIÓN SCORM
  // ============================================
  scorm_version: String       // '1.2' (versión SCORM soportada)
  package_id: String          // ID único del paquete SCORM
  title: String               // Título del paquete
  
  // ============================================
  // ARCHIVO
  // ============================================
  package_path: String        // Ruta al archivo ZIP del paquete
  package_url: String?        // URL pública del paquete
  package_size: Integer       // Tamaño en bytes
  package_hash: String        // Hash SHA-256 del paquete
  
  // ============================================
  // METADATOS SCORM
  // ============================================
  metadata: JSON              // {
                                //   "organization": "TES Digital",
                                //   "identifier": "uuid",
                                //   "title": "Guía de Refuerzo: RCP Adulto SVB",
                                //   "description": "...",
                                //   "mastery_score": 80,
                                //   "time_limit_action": "exit,message",
                                //   "launch_data": "...",
                                //   "max_time_allowed": "PT40M",
                                //   "prerequisites": "..."
                                // }
  
  // ============================================
  // ESTADO
  // ============================================
  status: Enum                // 'generating' | 'ready' | 'error' | 'archived'
  generation_error: String?   // Mensaje de error si falló la generación
  
  // ============================================
  // METADATOS DE GESTIÓN
  // ============================================
  generated_at: Timestamp
  generated_by: UUID
  updated_at: Timestamp
}

Reglas:

  • Solo guías formativas pueden tener paquetes SCORM
  • Un ContentItem puede tener múltiples versiones SCORM (una por versión del contenido)
  • El paquete se genera automáticamente cuando scorm_enabled = true y el contenido está published

8. USUARIOS Y ROLES (User)

Definición: Usuarios del panel de administración con roles y permisos granulares.

User {
  id: UUID
  email: String               // Email único
  username: String            // Nombre de usuario
  password_hash: String       // Hash de contraseña (bcrypt)
  
  // ============================================
  // ROLES
  // ============================================
  role: Enum                  // 'super_admin' | 'admin' | 
                              // 'editor_clinico' | 'editor_formativo' |
                              // 'revisor' | 'viewer' |
                              // 'tes_validador' | 'formador' | 'medico'
  
  // ============================================
  // PERMISOS GRANULARES (JSON)
  // ============================================
  permissions: JSON           // {
                                //   "content": {
                                //     "create": true,
                                //     "edit": true,
                                //     "delete": false,
                                //     "publish": false,
                                //     "validate": true
                                //   },
                                //   "media": {
                                //     "upload": true,
                                //     "delete": false
                                //   },
                                //   "scorm": {
                                //     "generate": true,
                                //     "export": true
                                //   },
                                //   "validation": {
                                //     "approve": true,
                                //     "reject": true
                                //   },
                                //   "admin": {
                                //     "manage_users": false,
                                //     "manage_roles": false
                                //   }
                                // }
  
  // ============================================
  // ESTADO
  // ============================================
  is_active: Boolean
  last_login: Timestamp?
  
  // ============================================
  // METADATOS
  // ============================================
  created_at: Timestamp
  updated_at: Timestamp
}

Roles y Permisos por Defecto:

Rol Descripción Permisos Clave
super_admin Administrador total Todos los permisos
admin Administrador Gestión de contenido y usuarios
editor_clinico Editor contenido clínico Crear/editar protocolos, fármacos
editor_formativo Editor contenido formativo Crear/editar guías formativas
revisor Revisor general Revisar y aprobar contenido
tes_validador Validador TES Validar contenido operativo
medico Médico validador Validar contenido clínico
formador Formador Validar contenido formativo
viewer Solo lectura Ver contenido

9. AUDITORÍA (AuditLog)

Definición: Registro completo de todas las acciones del sistema.

AuditLog {
  id: UUID
  entity_type: String         // 'content_item' | 'media_resource' | 
                              // 'content_relation' | 'content_version' |
                              // 'scorm_package' | 'user' | 'validation_workflow'
  
  entity_id: UUID             // ID de la entidad afectada
  
  // ============================================
  // ACCIÓN
  // ============================================
  action: Enum                // 'create' | 'update' | 'delete' |
                              // 'publish' | 'unpublish' | 'archive' |
                              // 'approve' | 'reject' | 'submit' |
                              // 'validate' | 'generate_scorm' |
                              // 'upload_media' | 'delete_media'
  
  action_details: JSON?       // Detalles específicos de la acción:
                              // {
                              //   "fields_changed": ["title", "content"],
                              //   "old_value": {...},
                              //   "new_value": {...},
                              //   "reason": "..."
                              // }
  
  // ============================================
  // USUARIO Y CONTEXTO
  // ============================================
  user_id: UUID               // FK a User
  user_role: String           // Rol del usuario (snapshot al momento de la acción)
  ip_address: String?         // IP desde la que se realizó la acción
  user_agent: String?         // User agent del navegador
  
  // ============================================
  // METADATOS
  // ============================================
  timestamp: Timestamp        // Fecha y hora exacta
  metadata: JSON?             // Metadatos adicionales:
                              // {
                              //   "session_id": "...",
                              //   "request_id": "...",
                              //   "duration_ms": 150,
                              //   ...
                              // }
}

Reglas:

  • Todas las acciones importantes se registran
  • Los logs nunca se eliminan (solo se archivan)
  • Los logs son inmutables (no se pueden modificar)

🔗 RELACIONES ENTRE ENTIDADES

ContentItem (1) ──< (N) ContentResourceRelation (N) >── (1) MediaResource
ContentItem (1) ──< (N) ContentRelation (N) >── (1) ContentItem
ContentItem (1) ──< (N) ContentVersion
ContentItem (1) ──< (1) ValidationWorkflow
ContentItem (1) ──< (N) SCORMPackage
User (1) ──< (N) ContentItem (created_by, updated_by, published_by)
User (1) ──< (N) MediaResource (uploaded_by)
User (1) ──< (N) AuditLog

📦 EXPORTACIÓN A CONTENT PACK JSON

El Content Pack se genera desde estas entidades siguiendo esta estructura:

{
  "metadata": {
    "version": "1.0.0",
    "generated_at": "2025-01-06T12:00:00Z",
    "hash": "sha256:...",
    "total_items": 150,
    "total_resources": 200,
    "source": "server"
  },
  "content": {
    "protocols": [
      // ContentItem donde:
      //   type='protocol' AND functional_layer='operativa' AND status='published'
      // Incluye: id, slug, title, short_title, description, content, priority, etc.
    ],
    "guides": [
      // ContentItem donde:
      //   type='guide' AND functional_layer='formativa' AND status='published'
    ],
    "drugs": [
      // ContentItem donde:
      //   type='drug' AND functional_layer='referencia' AND status='published'
    ],
    "checklists": [
      // ContentItem donde:
      //   type='checklist' AND functional_layer='operativa' AND status='published'
    ],
    "manuals": [
      // ContentItem donde:
      //   type='manual' AND functional_layer='referencia' AND status='published'
    ]
  },
  "media": {
    "images": [
      // MediaResource donde type='image' AND status='published'
      // Incluye: id, filename, path, url, alt, caption, etc.
    ],
    "videos": [
      // MediaResource donde type='video' AND status='published'
    ]
  },
  "relations": {
    "content_to_content": [
      // ContentRelation donde ambos contenidos están published
      // Incluye: source_content_id, target_content_id, relation_type, is_bidirectional
    ],
    "content_to_media": [
      // ContentResourceRelation donde ambos están published
      // Incluye: content_id, resource_id, context, order, is_primary
    ]
  }
}

Reglas del Content Pack:

  • Solo incluye contenido con status='published'
  • Solo incluye la última versión (is_latest=true)
  • Las relaciones están incluidas explícitamente
  • Los recursos multimedia tienen URLs relativas o absolutas
  • El hash se calcula sobre content + media + relations

🎯 PRINCIPIOS DE DISEÑO

1. Separación de Capas Funcionales

CRÍTICO: El campo functional_layer garantiza que:

  • Contenido operativo NO se mezcle con formativo
  • Contenido formativo NO se mezcle con referencia
  • Cada capa tiene su propia estructura de content
  • Las relaciones entre capas están explícitas

2. Versionado Semántico

  • Major (X.0.0): Cambios incompatibles (estructura diferente)
  • Minor (0.X.0): Nuevas funcionalidades compatibles
  • Patch (0.0.X): Correcciones compatibles

3. Estados y Workflow

draft → submitted → in_review → approved → published
  ↓         ↓           ↓
rejected  rejected   rejected

4. Trazabilidad Completa

  • Todo cambio queda registrado en AuditLog
  • Historial de versiones en ContentVersion
  • Workflow de validación en ValidationWorkflow

5. Relaciones Bidireccionales

  • ContentRelation permite relaciones bidireccionales
  • Campo is_bidirectional indica si la relación es simétrica
  • El Content Pack incluye todas las relaciones

6. Offline-First

  • El Content Pack es autocontenido (incluye todo lo necesario)
  • Las relaciones están incluidas en el pack
  • Los recursos multimedia tienen URLs relativas o absolutas
  • El sistema funciona sin conexión usando cache

7. SCORM-Ready

  • Solo guías formativas pueden tener SCORM
  • El paquete SCORM se genera automáticamente
  • Metadatos SCORM completos en SCORMPackage

VALIDACIONES Y CONSTRAINTS

Validaciones de Contenido

  1. Separación de Capas:

    • Un ContentItem SOLO puede tener functional_layer de UNA capa
    • El content JSON debe ser compatible con la capa
  2. Tipo y Capa:

    • type='protocol'functional_layer='operativa' (SIEMPRE)
    • type='guide'functional_layer='formativa' (SIEMPRE)
    • type='drug'functional_layer='referencia' (SIEMPRE)
    • type='manual'functional_layer='referencia' (SIEMPRE)
    • type='checklist'functional_layer='operativa' (SIEMPRE)
  3. Versionado:

    • version debe seguir formato semántico: ^\d+\.\d+\.\d+$
    • Solo una versión puede tener is_active=true por content_id
  4. SCORM:

    • Solo type='guide' y functional_layer='formativa' pueden tener SCORM
    • Si scorm_enabled=true, debe existir SCORMPackage asociado

Validaciones de Relaciones

  1. ContentRelation:

    • source_content_id != target_content_id (no auto-relaciones)
    • Si is_bidirectional=true, debe existir relación inversa
  2. ContentResourceRelation:

    • content_id y resource_id deben existir
    • context debe ser válido para el tipo de contenido

Validaciones de Workflow

  1. ValidationWorkflow:
    • current_status debe seguir el workflow definido
    • No se puede pasar de published a draft directamente
    • rejected requiere rejection_reason

📝 NOTAS TÉCNICAS

Campos JSON Flexibles

Los campos content y metadata son JSON para permitir:

  • Estructuras específicas por tipo de contenido
  • Extensibilidad sin cambios de esquema
  • Metadatos adicionales sin migraciones

UUIDs vs IDs Numéricos

  • UUIDs para IDs principales (mejor para distribución, sin colisiones)
  • Strings para slugs (legibles, SEO-friendly)

Timestamps

  • Todos los timestamps en formato ISO 8601
  • Timezone: UTC
  • Incluir created_at y updated_at en todas las entidades principales

Soft Deletes

  • No eliminar físicamente contenido publicado
  • Usar campo status='archived' para "eliminación"
  • Mantener historial completo

🚀 COMPATIBILIDAD

Panel de Administración

  • CRUD completo para todas las entidades
  • Editor visual para cada tipo de contenido
  • Gestor de recursos multimedia
  • Sistema de validación con workflow
  • Generación de SCORM
  • Exportación de Content Pack

Content Pack JSON

  • Estructura autocontenida
  • Incluye relaciones explícitas
  • URLs relativas/absolutas para recursos
  • Hash para verificación de integridad

Uso Offline

  • Content Pack descargable y cacheable
  • Funciona sin conexión
  • Fallback a datos locales garantizado

SCORM

  • Generación automática desde guías formativas
  • Metadatos SCORM 1.2 completos
  • Exportación como ZIP

Última actualización: 2025-01-06
Estado: MODELO CANÓNICO DEFINITIVO - FUENTE DE VERDAD