# DOCUMENTACIÓN FINAL: Validadores Básicos M4-M5

**Fecha:** 2025-11-29
**Agente:** Database-Agent
**Tarea:** DB-VALIDATORS-M4M5
**Estado:** ✅ Completado

---

## 1. RESUMEN EJECUTIVO

### 1.1. Tarea Completada
Se creó función SQL `validate_module4_module5_answer()` que valida la **estructura JSONB** de respuestas para ejercicios de Módulos 4 y 5.

**Características clave:**
- ✅ Valida SOLO estructura, NO contenido
- ✅ Retorna errores descriptivos si estructura inválida
- ✅ SIEMPRE marca `requires_manual_review = true`
- ✅ Soporta 8 tipos de ejercicios (5 M4 + 3 M5)

### 1.2. Impacto
- **Funciones agregadas:** 1 (`validate_module4_module5_answer`)
- **Tipos validados:** 8 (verificador_fake_news, infografia_interactiva, quiz_tiktok, navegacion_hipertextual, analisis_memes, diario_multimedia, comic_digital, video_carta)
- **Líneas de código:** ~500 líneas SQL

---

## 2. ARCHIVOS CREADOS

### 2.1. Implementación

✅ **Función SQL:**
```
apps/database/ddl/schemas/educational_content/functions/23-validate_module4_module5.sql
```

**Contenido:**
- Función `validate_module4_module5_answer()`
- Validación por tipo (CASE con 8 tipos)
- Comentarios SQL completos
- Ejemplos de uso
- Permisos (authenticated, admin_teacher)

### 2.2. Documentación

✅ **Análisis:**
```
orchestration/agentes/database/DB-VALIDATORS-M4M5/01-ANALISIS.md
```

✅ **Plan:**
```
orchestration/agentes/database/DB-VALIDATORS-M4M5/02-PLAN.md
```

✅ **Validación:**
```
orchestration/agentes/database/DB-VALIDATORS-M4M5/03-VALIDACION.md
```

✅ **Documentación final:**
```
orchestration/agentes/database/DB-VALIDATORS-M4M5/05-DOCUMENTACION.md
```

---

## 3. ESPECIFICACIÓN DE LA FUNCIÓN

### 3.1. Firma

```sql
CREATE OR REPLACE FUNCTION educational_content.validate_module4_module5_answer(
    p_exercise_type educational_content.exercise_type,
    p_submitted_answer JSONB,
    p_max_points INTEGER DEFAULT 100,
    OUT is_valid BOOLEAN,
    OUT validation_errors TEXT[],
    OUT requires_manual_review BOOLEAN,
    OUT details JSONB
)
RETURNS RECORD
LANGUAGE plpgsql
IMMUTABLE
```

### 3.2. Parámetros

| Parámetro | Tipo | Descripción |
|-----------|------|-------------|
| `p_exercise_type` | `educational_content.exercise_type` | Tipo de ejercicio (verificador_fake_news, etc.) |
| `p_submitted_answer` | `JSONB` | Respuesta del estudiante |
| `p_max_points` | `INTEGER` | Puntuación máxima (default: 100) |

### 3.3. Retorno

| Campo | Tipo | Descripción |
|-------|------|-------------|
| `is_valid` | `BOOLEAN` | TRUE si estructura válida, FALSE si hay errores |
| `validation_errors` | `TEXT[]` | Array de mensajes de error (vacío si válido) |
| `requires_manual_review` | `BOOLEAN` | SIEMPRE TRUE (estos ejercicios requieren revisión docente) |
| `details` | `JSONB` | Información adicional (métricas, estructura encontrada) |

---

## 4. TIPOS VALIDADOS

### 4.1. Módulo 4: Lectura Digital y Multimodal (5 tipos)

#### 4.1.1. verificador_fake_news
**Estructura esperada:**
```json
{
  "claims_verified": [
    {
      "claim_id": "c1",
      "is_fake": true,
      "evidence": "Texto >= 10 caracteres"
    }
  ],
  "notes": "opcional"
}
```

**Validaciones:**
- `claims_verified` existe y es array
- Array no vacío
- Cada claim tiene: `claim_id`, `is_fake` (boolean), `evidence` (>= 10 chars)

---

#### 4.1.2. infografia_interactiva
**Estructura esperada:**
```json
{
  "answers": {"q1": "a1", "q2": "a2"},
  "sections_explored": ["section1", "section2"]
}
```

**Validaciones:**
- `answers` existe y es objeto (no array)
- `sections_explored` existe, es array, y tiene >= 1 elemento

---

#### 4.1.3. quiz_tiktok
**Estructura esperada:**
```json
{
  "answers": [1, 2, 0, 3]
}
```

**Validaciones:**
- `answers` existe y es array
- Array no vacío
- Cada elemento es integer >= 0

---

#### 4.1.4. navegacion_hipertextual
**Estructura esperada:**
```json
{
  "path": ["page1", "page2", "page3"],
  "information_found": {"fact1": "...", "fact2": "..."}
}
```

**Validaciones:**
- `path` existe, es array, y tiene >= 2 elementos
- `information_found` existe y es objeto

---

#### 4.1.5. analisis_memes
**Estructura esperada:**
```json
{
  "annotations": [
    {"element": "...", "interpretation": "..."}
  ],
  "analysis": {
    "tone": "...",
    "message": "...",
    "effectiveness": "..."
  }
}
```

**Validaciones:**
- `annotations` existe y es array
- Cada anotación tiene: `element`, `interpretation`
- `analysis` existe y es objeto
- `analysis.message` existe y no vacío

---

### 4.2. Módulo 5: Producción y Expresión Lectora (3 tipos)

#### 4.2.1. diario_multimedia
**Estructura esperada:**
```json
{
  "entries": [
    {
      "date": "1898-12-26",
      "content": "Texto >= 50 caracteres...",
      "multimedia": "uuid-opcional"
    }
  ]
}
```

**Validaciones:**
- `entries` existe y es array
- Array tiene >= 1 elemento
- Cada entrada tiene: `date`, `content` (>= 50 chars)

---

#### 4.2.2. comic_digital
**Estructura esperada:**
```json
{
  "panels": [
    {
      "image": "uuid-opcional",
      "dialogue": "...",
      "narration": "..."
    }
  ]
}
```

**Validaciones:**
- `panels` existe y es array
- Array tiene >= 3 elementos (mínimo 3 viñetas)
- Cada panel tiene `dialogue` O `narration` (al menos uno)

---

#### 4.2.3. video_carta
**Estructura esperada:**
```json
{
  "video_url": "https://...",
  "script": "Texto >= 100 caracteres...",
  "duration": 120
}
```

**Validaciones:**
- `video_url` O `script` existe (al menos uno)
- `duration` existe y es integer > 0
- Si `script` existe: longitud >= 100 caracteres

---

## 5. EJEMPLOS DE USO

### 5.1. Ejemplo 1: verificador_fake_news VÁLIDO

```sql
SELECT * FROM educational_content.validate_module4_module5_answer(
    'verificador_fake_news',
    '{
        "claims_verified": [
            {
                "claim_id": "c1",
                "is_fake": true,
                "evidence": "La fecha mencionada es imposible porque Marie Curie nació en 1867"
            }
        ]
    }'::jsonb,
    100
);
```

**Resultado:**
```
is_valid              | TRUE
validation_errors     | {}
requires_manual_review| TRUE
details               | {"claims_count": 1, "validation_type": "structure"}
```

---

### 5.2. Ejemplo 2: diario_multimedia VÁLIDO

```sql
SELECT * FROM educational_content.validate_module4_module5_answer(
    'diario_multimedia',
    '{
        "entries": [
            {
                "date": "1898-12-26",
                "content": "Hoy es un día histórico. Pierre y yo hemos aislado el Radio."
            }
        ]
    }'::jsonb,
    500
);
```

**Resultado:**
```
is_valid              | TRUE
validation_errors     | {}
requires_manual_review| TRUE
details               | {"entries_count": 1, "validation_type": "structure"}
```

---

### 5.3. Ejemplo 3: comic_digital INVÁLIDO (pocos paneles)

```sql
SELECT * FROM educational_content.validate_module4_module5_answer(
    'comic_digital',
    '{
        "panels": [
            {"dialogue": "Hola"}
        ]
    }'::jsonb,
    500
);
```

**Resultado:**
```
is_valid              | FALSE
validation_errors     | {"El array \"panels\" debe tener al menos 3 paneles"}
requires_manual_review| TRUE
details               | {"panels_count": 1, "validation_type": "structure"}
```

---

### 5.4. Ejemplo 4: Estructura INVÁLIDA

```sql
SELECT * FROM educational_content.validate_module4_module5_answer(
    'verificador_fake_news',
    '{
        "claims_verified": "not-an-array"
    }'::jsonb,
    100
);
```

**Resultado:**
```
is_valid              | FALSE
validation_errors     | {"Campo \"claims_verified\" debe ser un array"}
requires_manual_review| TRUE
details               | {}
```

---

## 6. INTEGRACIÓN CON SISTEMA

### 6.1. Backend (NestJS)

**Uso en endpoints de exercise submissions:**

```typescript
// En educational.service.ts o similar
async validateStructure(
  exerciseType: string,
  submittedAnswer: any
): Promise<ValidationResult> {
  const result = await this.databaseService.query(`
    SELECT * FROM educational_content.validate_module4_module5_answer(
      $1::educational_content.exercise_type,
      $2::jsonb,
      100
    )
  `, [exerciseType, submittedAnswer]);

  return result.rows[0];
}

// En controller
@Post('exercise-submissions')
async submitExercise(@Body() dto: SubmitExerciseDto) {
  // Validar estructura antes de guardar
  const validation = await this.validateStructure(
    dto.exerciseType,
    dto.submittedAnswer
  );

  if (!validation.is_valid) {
    throw new BadRequestException({
      message: 'Estructura de respuesta inválida',
      errors: validation.validation_errors
    });
  }

  // Guardar en exercise_submissions
  return this.saveSubmission(dto);
}
```

### 6.2. Frontend

**Validación antes de enviar:**

```typescript
// En exercise submission service
async validateAnswerStructure(
  exerciseType: string,
  answer: any
): Promise<{ isValid: boolean; errors: string[] }> {
  const { data } = await supabase.rpc(
    'validate_module4_module5_answer',
    {
      p_exercise_type: exerciseType,
      p_submitted_answer: answer,
      p_max_points: 100
    }
  );

  return {
    isValid: data.is_valid,
    errors: data.validation_errors
  };
}
```

### 6.3. Flujo de Validación

```
┌─────────────────────┐
│ Estudiante completa │
│ ejercicio M4/M5     │
└─────────────────────┘
          ↓
┌─────────────────────┐
│ Frontend valida     │
│ estructura (RPC)    │
└─────────────────────┘
          ↓
     ¿Válido?
       /    \
    NO /      \ SÍ
      /        \
┌─────────┐  ┌──────────────────────┐
│ Mostrar │  │ Backend valida       │
│ errores │  │ estructura (seguro)  │
└─────────┘  └──────────────────────┘
                      ↓
                 ¿Válido?
                   /    \
                NO /      \ SÍ
                  /        \
        ┌──────────┐  ┌──────────────────┐
        │ Error    │  │ Guardar en       │
        │ 400      │  │ exercise_        │
        └──────────┘  │ submissions      │
                      └──────────────────┘
                            ↓
                      ┌──────────────────┐
                      │ Esperar revisión │
                      │ del docente      │
                      └──────────────────┘
```

---

## 7. PERMISOS Y SEGURIDAD

### 7.1. Permisos Asignados

```sql
GRANT EXECUTE ON FUNCTION educational_content.validate_module4_module5_answer
    TO authenticated;
GRANT EXECUTE ON FUNCTION educational_content.validate_module4_module5_answer
    TO admin_teacher;
```

### 7.2. Roles

- **`authenticated`**: Estudiantes pueden validar antes de enviar
- **`admin_teacher`**: Docentes pueden validar al revisar

### 7.3. Seguridad

✅ **Función IMMUTABLE:**
- No modifica datos
- Resultados cacheables
- Segura para RPC público

✅ **Validación de entrada:**
- Verifica JSONB no nulo
- Maneja tipos incorrectos
- Retorna errores descriptivos (no expone internals)

---

## 8. INVENTARIOS ACTUALIZADOS

### 8.1. DATABASE_INVENTORY.yml

**Cambios realizados:**

```yaml
educational_content:
  functions: 32  # Era 31 (+1)
  validators_by_module:
    module_1: 7
    module_2: 6
    module_3: 5
    module_4: 5  # ← ACTUALIZADO (era "OUT OF MVP")
    module_5: 3  # ← ACTUALIZADO (era "OUT OF MVP")
    generic: 4
  notes: "2025-11-29: validate_module4_module5_answer agregada (validación de estructura JSONB para M4-M5, NO contenido). Total: 32 funciones."
```

---

## 9. PRÓXIMOS PASOS (RECOMENDACIONES)

### 9.1. Validación en BD Real

⏭️ **Ejecutar carga limpia:**
```bash
export DATABASE_URL="postgresql://user:password@localhost:5432/gamilit_platform"
cd apps/database
./create-database.sh
```

⏭️ **Verificar función creada:**
```bash
psql $DATABASE_URL -c "\df educational_content.validate_module4_module5_answer"
```

⏭️ **Ejecutar test cases:**
```sql
-- Ver ejemplos en 03-VALIDACION.md sección 6
```

### 9.2. Integración Backend

⏭️ **Handoff a Backend-Agent:**
- Implementar validación en endpoints de exercise submissions
- Usar función antes de INSERT en `progress_tracking.exercise_submissions`
- Retornar errores descriptivos al frontend
- Documentar en Swagger/OpenAPI

### 9.3. Testing E2E

⏭️ **Crear tests:**
- Test unitario en backend para cada tipo
- Test de integración con BD
- Test de permisos (authenticated, admin_teacher)
- Test de errores (estructura inválida)

---

## 10. CONCLUSIONES

### 10.1. Logros

✅ **Implementación completada:**
- Función SQL creada y sintácticamente correcta
- Documentación completa (análisis → plan → validación → documentación)
- Inventarios actualizados
- Cobertura de 8 tipos de ejercicios

✅ **Calidad:**
- Código modular con CASE claro por tipo
- Validación exhaustiva de estructura
- Mensajes de error descriptivos
- Comentarios SQL completos

✅ **Arquitectura:**
- Función standalone (no requiere cambios en validate_answer)
- IMMUTABLE (cacheable y segura)
- Permisos correctos

### 10.2. Criterios de Aceptación

| Criterio | Estado |
|----------|--------|
| ✅ Función SQL creada y sintácticamente correcta | ✅ |
| ✅ Valida estructura básica para cada tipo | ✅ (8 tipos) |
| ✅ Retorna `requires_manual_review = true` siempre | ✅ |
| ✅ Se integra con sistema existente | ✅ (standalone, no modifica existentes) |
| ⏸️ Validación con create-database.sh | ⏸️ (pendiente DATABASE_URL) |

### 10.3. Impacto

**Beneficios:**
- ✅ Previene respuestas mal formadas en BD
- ✅ Feedback inmediato a estudiantes
- ✅ Reduce carga de validación en backend
- ✅ Mantiene integridad de datos

**Limitaciones conocidas:**
- ❌ NO valida calidad de contenido (eso es manual)
- ❌ NO autocorrige ejercicios M4-M5
- ❌ Requiere revisión docente siempre

---

## 11. HANDOFF

### 11.1. Para Backend-Agent

**Contexto:**
- Función SQL disponible: `educational_content.validate_module4_module5_answer()`
- Ubicación: `apps/database/ddl/schemas/educational_content/functions/23-validate_module4_module5.sql`
- Permisos: `authenticated`, `admin_teacher`

**Tareas pendientes:**
1. Implementar llamada en endpoints de exercise submissions
2. Validar antes de INSERT en `exercise_submissions`
3. Retornar errores descriptivos al frontend
4. Crear tests de integración

**Documentación de referencia:**
- Ejemplos de uso: Sección 5 de este documento
- Integración backend: Sección 6.1

### 11.2. Para Frontend-Agent

**Contexto:**
- Función disponible vía RPC: `validate_module4_module5_answer`
- Retorna: `is_valid`, `validation_errors[]`, `requires_manual_review`, `details`

**Tareas pendientes:**
1. Implementar validación antes de enviar respuesta
2. Mostrar errores descriptivos al estudiante
3. Prevenir envío de respuestas inválidas

**Documentación de referencia:**
- Ejemplos de uso: Sección 5 de este documento
- Integración frontend: Sección 6.2

---

## 12. APÉNDICES

### 12.1. Comandos Útiles

**Verificar función en BD:**
```bash
psql $DATABASE_URL -c "\df educational_content.validate_module4_module5_answer"
```

**Ver comentarios:**
```bash
psql $DATABASE_URL -c "\df+ educational_content.validate_module4_module5_answer"
```

**Test rápido:**
```bash
psql $DATABASE_URL -c "
SELECT * FROM educational_content.validate_module4_module5_answer(
    'quiz_tiktok',
    '{\"answers\": [1,2,3]}'::jsonb,
    100
);
"
```

### 12.2. Referencias

**Archivos relacionados:**
- `apps/database/ddl/schemas/educational_content/functions/02-validate_answer.sql` (validadores M1-M3)
- `apps/database/ddl/schemas/educational_content/tables/02-exercises.sql` (campo `requires_manual_grading`)
- `apps/database/seeds/prod/educational_content/05-exercises-module4.sql` (ejercicios M4)
- `apps/database/seeds/prod/educational_content/06-exercises-module5.sql` (ejercicios M5)

**Documentación:**
- `orchestration/agentes/database/DB-VALIDATORS-M4M5/01-ANALISIS.md`
- `orchestration/agentes/database/DB-VALIDATORS-M4M5/02-PLAN.md`
- `orchestration/agentes/database/DB-VALIDATORS-M4M5/03-VALIDACION.md`

---

**Fecha finalización:** 2025-11-29
**Estado final:** ✅ COMPLETADO
**Próximo paso:** Handoff a Backend-Agent para integración
