codigo0/docs/CONTENT_MODEL.md

537 lines
15 KiB
Markdown

# 📐 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**