codigo0/docs/API_ENDPOINTS_ESPECIFICACION.md

680 lines
11 KiB
Markdown
Raw Normal View History

2026-01-19 08:10:16 +00:00
# 🔌 ESPECIFICACIÓN API REST - SERVIDOR DE CONTENIDO TES
**Versión:** 1.0.0
**Fecha:** 2025-01-06
**Base URL:** `https://servidor-tes.com/api` (ejemplo)
---
## 📋 ÍNDICE
1. [API Pública (App PWA)](#api-pública-app-pwa)
2. [API Admin (Panel Admin)](#api-admin-panel-admin)
3. [Códigos de Estado](#códigos-de-estado)
4. [Formato de Respuestas](#formato-de-respuestas)
5. [Rate Limiting](#rate-limiting)
---
# API PÚBLICA (APP PWA)
## Endpoints de Solo Lectura
### 1. Health Check
```
GET /api/health
```
**Descripción:** Verifica estado del servidor y base de datos.
**Autenticación:** No requerida
**Respuesta 200:**
```json
{
"status": "ok",
"timestamp": "2025-01-06T12:00:00Z",
"database": "connected",
"latest_pack_version": "1.0.0",
"latest_pack_hash": "sha256:abc123...",
"server_version": "1.0.0"
}
```
**Respuesta 503 (si BD desconectada):**
```json
{
"status": "error",
"timestamp": "2025-01-06T12:00:00Z",
"database": "disconnected",
"message": "Base de datos no disponible"
}
```
---
### 2. Content Pack Latest
```
GET /api/content/pack/latest
```
**Descripción:** Obtiene el Content Pack más reciente (solo contenido publicado).
**Autenticación:** No requerida
**Headers:**
- `If-None-Match: <hash>` - Si el hash coincide, retorna 304 Not Modified
**Respuesta 200:**
```json
{
"metadata": {
"version": "1.0.0",
"generated_at": "2025-01-06T12:00:00Z",
"hash": "sha256:abc123...",
"total_items": 45,
"total_resources": 120
},
"content": { ... },
"media": { ... },
"links": { ... }
}
```
**Headers de Respuesta:**
- `ETag: <hash>` - Hash del pack
- `Content-Type: application/json`
- `Cache-Control: public, max-age=3600` - Cache 1 hora
**Respuesta 304:** Not Modified (si `If-None-Match` coincide)
**Respuesta 404:** No hay pack disponible
---
### 3. Content Pack por Versión
```
GET /api/content/pack/:version
```
**Descripción:** Obtiene un Content Pack específico por versión.
**Parámetros:**
- `version` (path) - Versión semántica (ej: "1.0.0")
**Ejemplo:**
```
GET /api/content/pack/1.0.0
```
**Respuesta 200:** Igual que `/pack/latest`
**Respuesta 404:** Versión no encontrada
---
### 4. Protocolo Individual
```
GET /api/content/protocol/:slug
```
**Descripción:** Obtiene un protocolo específico con sus recursos asociados.
**Parámetros:**
- `slug` (path) - Slug del protocolo (ej: "rcp-adulto-svb")
**Ejemplo:**
```
GET /api/content/protocol/rcp-adulto-svb
```
**Respuesta 200:**
```json
{
"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",
"level": "operativo",
"priority": "critica",
"status": "published",
"version": "1.0.0",
"content": {
"steps": [...],
"checklist": {...},
"warnings": [...],
"key_points": [...]
},
"resources": {
"images": [
{
"id": "...",
"title": "Posición de Manos - RCP Adulto",
"url": "https://servidor-tes.com/media/images/rcp/...",
"alt_text": "...",
"section": "pasos",
"position": 7
}
],
"videos": [
{
"id": "...",
"title": "RCP Adulto SVB - Técnica Completa",
"url": "https://servidor-tes.com/media/videos/rcp/...",
"duration_seconds": 45,
"section": "pasos",
"position": 0
}
]
},
"related": {
"guide_id": "550e8400-...",
"guide_slug": "rcp-adulto-svb-formativo",
"manual_ids": ["..."],
"related_protocol_ids": ["..."]
}
}
```
**Respuesta 404:** Protocolo no encontrado o no publicado
---
### 5. Guía Individual
```
GET /api/content/guide/:slug
```
**Descripción:** Obtiene una guía formativa completa con sus 8 secciones.
**Parámetros:**
- `slug` (path) - Slug de la guía (ej: "abcde-operativo")
**Respuesta 200:**
```json
{
"id": "...",
"type": "guide",
"slug": "abcde-operativo",
"title": "ABCDE Operativo",
"level": "formativo",
"content": {
"sections": [
{
"numero": 1,
"titulo": "Introducción y Contexto",
"markdown": "# Introducción...",
"resources": {
"images": [...],
"videos": [...]
}
},
// ... 7 secciones más
],
"related_protocol_id": "...",
"related_manual_ids": [...]
},
"resources": {
"images": [...],
"videos": [...]
}
}
```
---
### 6. Recurso Multimedia
```
GET /api/content/media/:id
```
**Descripción:** Obtiene información de un recurso multimedia o redirige al archivo.
**Parámetros:**
- `id` (path) - UUID del recurso
**Query Params:**
- `download` (boolean) - Si true, fuerza descarga
**Respuesta 200 (JSON si no download):**
```json
{
"id": "...",
"type": "image",
"title": "Posición de Manos - RCP Adulto",
"url": "https://servidor-tes.com/media/images/rcp/rcp_posicion_manos_adulto.png",
"alt_text": "...",
"width": 1200,
"height": 800,
"file_size": 245678
}
```
**Respuesta 302 (Redirect si download):**
- Redirige a URL del archivo
**Respuesta 404:** Recurso no encontrado
---
# API ADMIN (PANEL ADMIN)
## Autenticación
### Login
```
POST /api/admin/auth/login
```
**Body:**
```json
{
"email": "admin@emerges-tes.local",
"password": "Admin123!"
}
```
**Respuesta 200:**
```json
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": {
"id": "...",
"email": "admin@emerges-tes.local",
"username": "admin",
"role": "super_admin"
},
"expiresIn": 86400
}
```
**Respuesta 401:** Credenciales inválidas
---
### Me (Usuario Actual)
```
GET /api/admin/auth/me
```
**Autenticación:** Requerida (Bearer Token)
**Respuesta 200:**
```json
{
"user": {
"id": "...",
"email": "...",
"username": "...",
"role": "...",
"is_active": true
}
}
```
---
## Contenido
### Listar Contenido
```
GET /api/admin/content
```
**Query Params:**
- `type` - Filtrar por tipo (protocol, guide, manual, drug, checklist)
- `status` - Filtrar por estado (draft, in_review, approved, published)
- `priority` - Filtrar por prioridad (critica, alta, media, baja)
- `search` - Búsqueda de texto
- `page` - Número de página (default: 1)
- `limit` - Items por página (default: 20)
**Respuesta 200:**
```json
{
"items": [...],
"total": 45,
"page": 1,
"limit": 20,
"totalPages": 3
}
```
---
### Obtener Contenido
```
GET /api/admin/content/:id
```
**Respuesta 200:** ContentItem completo
---
### Crear Contenido
```
POST /api/admin/content
```
**Body:**
```json
{
"type": "protocol",
"slug": "rcp-adulto-svb",
"title": "RCP Adulto - Soporte Vital Básico",
"clinical_context": "RCP",
"level": "operativo",
"priority": "critica",
"source_guideline": "ERC",
"content": {
"steps": [...],
"checklist": {...}
},
"tags": ["rcp", "svb", "adulto"]
}
```
**Respuesta 201:**
```json
{
"id": "...",
"message": "Contenido creado correctamente"
}
```
---
### Actualizar Contenido
```
PUT /api/admin/content/:id
```
**Body:** Mismo formato que crear
**Respuesta 200:**
```json
{
"id": "...",
"message": "Contenido actualizado correctamente",
"version": "1.1.0"
}
```
---
### Publicar Contenido
```
POST /api/admin/content/:id/publish
```
**Descripción:** Cambia status a 'published' y genera nueva versión.
**Respuesta 200:**
```json
{
"id": "...",
"status": "published",
"version": "1.0.0",
"message": "Contenido publicado correctamente"
}
```
---
### Solicitar Validación
```
POST /api/admin/content/:id/validate
```
**Body:**
```json
{
"comments": "Revisado y aprobado",
"validator_role": "tes"
}
```
**Respuesta 200:**
```json
{
"id": "...",
"status": "approved",
"validated_by": "...",
"validated_at": "2025-01-06T12:00:00Z"
}
```
---
## Recursos Multimedia
### Listar Recursos
```
GET /api/admin/media
```
**Query Params:**
- `type` - image | video
- `status` - draft | approved | published
- `block` - Filtrar por bloque
- `search` - Búsqueda
---
### Upload Recurso
```
POST /api/admin/media/upload
```
**Content-Type:** `multipart/form-data`
**Body:**
- `file` - Archivo (imagen o vídeo)
- `title` - Título
- `alt_text` - Texto alternativo
- `description` - Descripción
- `tags` - Tags (JSON array)
- `block` - Bloque temático
- `priority` - critica | alta | media | baja
- `usage_type` - operativo | formativo | referencia (puede ser array)
**Respuesta 201:**
```json
{
"id": "...",
"filename": "rcp_posicion_manos_adulto.png",
"path": "/media/images/rcp/rcp_posicion_manos_adulto.png",
"url": "https://servidor-tes.com/media/images/rcp/...",
"file_size": 245678,
"message": "Recurso subido correctamente"
}
```
---
### Asociar Recurso a Contenido
```
POST /api/admin/media/:id/associate
```
**Body:**
```json
{
"content_item_id": "...",
"section": "pasos",
"position": 7,
"placement": "inline",
"caption": "Posición correcta de manos",
"is_critical": true,
"priority": "critica"
}
```
---
## Content Pack
### Generar Pack
```
POST /api/admin/pack/generate
```
**Body:**
```json
{
"version": "1.0.0",
"include_draft": false,
"notes": "Primera versión del pack"
}
```
**Respuesta 200:**
```json
{
"version": "1.0.0",
"file_path": "/storage/packs/pack-v1.0.0.json",
"file_url": "https://servidor-tes.com/api/content/pack/1.0.0",
"hash": "sha256:abc123...",
"size_bytes": 5242880,
"total_items": 45,
"total_resources": 120,
"generated_at": "2025-01-06T12:00:00Z"
}
```
---
### Listar Versiones
```
GET /api/admin/pack/versions
```
**Respuesta 200:**
```json
{
"versions": [
{
"version": "1.0.0",
"generated_at": "2025-01-06T12:00:00Z",
"size_bytes": 5242880,
"total_items": 45,
"is_latest": true
},
{
"version": "0.9.0",
"generated_at": "2025-01-05T10:00:00Z",
"size_bytes": 4890123,
"total_items": 42,
"is_latest": false
}
]
}
```
---
# CÓDIGOS DE ESTADO
| Código | Significado | Uso |
|--------|-------------|-----|
| 200 | OK | Operación exitosa |
| 201 | Created | Recurso creado |
| 304 | Not Modified | Pack sin cambios (If-None-Match) |
| 400 | Bad Request | Datos inválidos |
| 401 | Unauthorized | No autenticado o token inválido |
| 403 | Forbidden | Sin permisos |
| 404 | Not Found | Recurso no encontrado |
| 409 | Conflict | Conflicto (ej: slug duplicado) |
| 422 | Unprocessable Entity | Validación fallida |
| 429 | Too Many Requests | Rate limit excedido |
| 500 | Internal Server Error | Error del servidor |
| 503 | Service Unavailable | Servicio no disponible (BD desconectada) |
---
# FORMATO DE RESPUESTAS
## Respuesta Exitosa
```json
{
"data": { ... },
"meta": {
"timestamp": "2025-01-06T12:00:00Z"
}
}
```
## Respuesta de Error
```json
{
"error": {
"code": "CONTENT_NOT_FOUND",
"message": "Contenido no encontrado",
"details": {
"id": "...",
"slug": "rcp-adulto-svb"
}
},
"meta": {
"timestamp": "2025-01-06T12:00:00Z"
}
}
```
---
# RATE LIMITING
## API Pública (App)
- **Límite:** 100 requests/minuto por IP
- **Headers:**
- `X-RateLimit-Limit: 100`
- `X-RateLimit-Remaining: 95`
- `X-RateLimit-Reset: 1641475200`
## API Admin
- **Límite:** 50 requests/minuto por usuario
- **Headers:** Mismo formato
**Respuesta 429:**
```json
{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Demasiadas solicitudes. Intenta de nuevo en 60 segundos."
},
"retryAfter": 60
}
```
---
**Fin de la Especificación**