- Configure workspace Git repository with comprehensive .gitignore - Add Odoo as submodule for ERP reference code - Include documentation: SETUP.md, GIT-STRUCTURE.md - Add gitignore templates for projects (backend, frontend, database) - Structure supports independent repos per project/subproject level Workspace includes: - core/ - Reusable patterns, modules, orchestration system - projects/ - Active projects (erp-suite, gamilit, trading-platform, etc.) - knowledge-base/ - Reference code and patterns (includes Odoo submodule) - devtools/ - Development tools and templates - customers/ - Client implementations template 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
17 KiB
17 KiB
PLAN DE IMPLEMENTACIÓN: Validadores Básicos M4-M5
Fecha: 2025-11-29 Agente: Database-Agent Tarea: DB-VALIDATORS-M4M5 Estado: Planeación
1. RESUMEN EJECUTIVO
1.1. Objetivo
Implementar función SQL validate_module4_module5_answer() que valide SOLO ESTRUCTURA de respuestas JSONB para ejercicios de Módulos 4 y 5.
1.2. Alcance
- ✅ Validación de estructura JSONB
- ✅ Detección de campos faltantes o mal formados
- ✅ Validación de tipos de datos
- ❌ NO evaluación de calidad de contenido
- ❌ NO autocorrección (siempre
requires_manual_review = true)
2. ARQUITECTURA DE LA SOLUCIÓN
2.1. Función Principal
Nombre: educational_content.validate_module4_module5_answer()
Firma:
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
Parámetros:
p_exercise_type: Tipo de ejercicio (verificador_fake_news, diario_multimedia, etc.)p_submitted_answer: Respuesta del estudiante en formato JSONBp_max_points: Puntuación máxima (para contexto, no se usa en scoring)
Retorno:
is_valid: TRUE si estructura es válida, FALSE si hay erroresvalidation_errors: Array de mensajes de error (vacío si válido)requires_manual_review: SIEMPRE TRUEdetails: Información adicional de validación (métricas, estructura encontrada)
2.2. Flujo de Validación
┌─────────────────────────────────────────┐
│ validate_module4_module5_answer() │
└─────────────────────────────────────────┘
↓
┌─────────────────────┐
│ Verificar JSONB │
│ no nulo │
└─────────────────────┘
↓
┌─────────────────────┐
│ CASE exercise_type │
└─────────────────────┘
↓
┌─────────────────────────────────────┐
│ M4: verificador_fake_news │
│ - claims_verified[] existe │
│ - Cada claim tiene estructura │
└─────────────────────────────────────┘
┌─────────────────────────────────────┐
│ M4: infografia_interactiva │
│ - answers{} existe │
│ - sections_explored[] existe │
└─────────────────────────────────────┘
┌─────────────────────────────────────┐
│ M4: quiz_tiktok │
│ - answers[] es array de integers │
└─────────────────────────────────────┘
┌─────────────────────────────────────┐
│ M4: navegacion_hipertextual │
│ - path[] existe │
│ - information_found{} existe │
└─────────────────────────────────────┘
┌─────────────────────────────────────┐
│ M4: analisis_memes │
│ - annotations[] existe │
│ - analysis{} existe │
└─────────────────────────────────────┘
┌─────────────────────────────────────┐
│ M5: diario_multimedia │
│ - entries[] existe │
│ - Cada entrada tiene date/content │
└─────────────────────────────────────┘
┌─────────────────────────────────────┐
│ M5: comic_digital │
│ - panels[] existe │
│ - Cada panel tiene dialogue/narr │
└─────────────────────────────────────┘
┌─────────────────────────────────────┐
│ M5: video_carta │
│ - video_url O script existe │
│ - duration > 0 │
└─────────────────────────────────────┘
↓
┌─────────────────────┐
│ Construir resultado │
│ - is_valid │
│ - validation_errors │
│ - details │
└─────────────────────┘
↓
┌─────────────────────────────┐
│ requires_manual_review=TRUE │
└─────────────────────────────┘
3. ESPECIFICACIÓN DETALLADA POR TIPO
3.1. Módulo 4
verificador_fake_news
-- Estructura esperada
{
"claims_verified": [
{"claim_id": "c1", "is_fake": true, "evidence": "..."}
],
"notes": "opcional"
}
-- Validaciones
✓ claims_verified existe y es array
✓ Array tiene >= 1 elemento
✓ Cada elemento tiene: claim_id (text), is_fake (boolean), evidence (text)
✓ claim_id no vacío
✓ evidence longitud >= 10
infografia_interactiva
-- Estructura esperada
{
"answers": {"q1": "a1", "q2": "a2"},
"sections_explored": ["intro", "timeline", "achievements"]
}
-- Validaciones
✓ answers existe y es objeto (no array)
✓ sections_explored existe y es array
✓ sections_explored tiene >= 1 elemento
quiz_tiktok
-- Estructura esperada
{
"answers": [1, 2, 0, 3]
}
-- Validaciones
✓ answers existe y es array
✓ Array tiene >= 1 elemento
✓ Cada elemento es integer >= 0
navegacion_hipertextual
-- Estructura esperada
{
"path": ["page1", "page2", "page3"],
"information_found": {"fact1": "...", "fact2": "..."}
}
-- Validaciones
✓ path existe y es array
✓ path tiene >= 2 elementos (inicio → destino mínimo)
✓ information_found existe y es objeto
analisis_memes
-- Estructura esperada
{
"annotations": [
{"element": "texto superior", "interpretation": "ironía"}
],
"analysis": {
"tone": "humorístico",
"message": "crítica social",
"effectiveness": "alta"
}
}
-- Validaciones
✓ annotations existe y es array
✓ Cada anotación tiene: element (text), interpretation (text)
✓ analysis existe y es objeto
✓ analysis.message existe y no vacío
3.2. Módulo 5
diario_multimedia
-- Estructura esperada
{
"entries": [
{
"date": "1898-12-26",
"content": "Hoy descubrimos el Radio...",
"multimedia": "uuid-opcional"
}
]
}
-- Validaciones
✓ entries existe y es array
✓ Array tiene >= 1 elemento
✓ Cada entrada tiene: date (text formato fecha), content (text >= 50 chars)
✓ content no vacío y longitud >= 50
comic_digital
-- Estructura esperada
{
"panels": [
{
"image": "uuid-opcional",
"dialogue": "¡Eureka!",
"narration": "Marie en el laboratorio"
}
]
}
-- Validaciones
✓ panels existe y es array
✓ Array tiene >= 3 elementos (mínimo 3 viñetas)
✓ Cada panel tiene: dialogue O narration (al menos uno)
video_carta
-- Estructura esperada
{
"video_url": "https://...", -- O
"script": "Texto del guión...",
"duration": 120 -- segundos
}
-- Validaciones
✓ video_url O script existe (al menos uno)
✓ duration existe y es integer > 0
✓ Si existe script: longitud >= 100 caracteres
4. IMPLEMENTACIÓN
4.1. Archivo a Crear
Ruta: apps/database/ddl/schemas/educational_content/functions/23-validate_module4_module5.sql
Secciones del archivo:
- Header con metadatos
- Función principal
- Helpers internos (validación JSONB)
- Comentarios SQL
- Permisos
- Ejemplos de uso
4.2. Pseudocódigo
CREATE OR REPLACE FUNCTION validate_module4_module5_answer(...)
RETURNS RECORD AS $$
DECLARE
v_errors TEXT[] := ARRAY[]::TEXT[];
v_details JSONB := '{}'::jsonb;
BEGIN
-- 1. Validación básica
IF p_submitted_answer IS NULL OR p_submitted_answer = 'null'::jsonb THEN
v_errors := array_append(v_errors, 'Respuesta vacía o nula');
is_valid := false;
RETURN;
END IF;
-- 2. CASE por exercise_type
CASE p_exercise_type
WHEN 'verificador_fake_news' THEN
-- Validar claims_verified[]
IF NOT (p_submitted_answer ? 'claims_verified') THEN
v_errors := array_append(v_errors, 'Falta campo claims_verified');
ELSIF jsonb_typeof(p_submitted_answer->'claims_verified') != 'array' THEN
v_errors := array_append(v_errors, 'claims_verified debe ser un array');
ELSIF jsonb_array_length(p_submitted_answer->'claims_verified') = 0 THEN
v_errors := array_append(v_errors, 'claims_verified no puede estar vacío');
ELSE
-- Validar estructura de cada claim
FOR i IN 0..jsonb_array_length(p_submitted_answer->'claims_verified')-1
LOOP
v_claim := p_submitted_answer->'claims_verified'->i;
IF NOT (v_claim ? 'claim_id' AND v_claim ? 'is_fake' AND v_claim ? 'evidence') THEN
v_errors := array_append(v_errors, format('Claim %s: faltan campos', i));
END IF;
-- Validar tipos...
END LOOP;
END IF;
WHEN 'diario_multimedia' THEN
-- Similar...
-- ... otros tipos
ELSE
v_errors := array_append(v_errors, format('Tipo de ejercicio no soportado: %s', p_exercise_type));
END CASE;
-- 3. Construir resultado
is_valid := (array_length(v_errors, 1) IS NULL OR array_length(v_errors, 1) = 0);
validation_errors := COALESCE(v_errors, ARRAY[]::TEXT[]);
requires_manual_review := TRUE; -- SIEMPRE
details := v_details;
END;
$$ LANGUAGE plpgsql IMMUTABLE;
4.3. Funciones Helper
Opcional: Crear funciones internas para validación común:
-- Helper: Validar que campo existe y es tipo específico
CREATE OR REPLACE FUNCTION _validate_field_type(
p_json JSONB,
p_field TEXT,
p_expected_type TEXT -- 'array', 'object', 'string', 'number', 'boolean'
)
RETURNS TEXT AS $$
BEGIN
IF NOT (p_json ? p_field) THEN
RETURN format('Campo "%s" faltante', p_field);
ELSIF jsonb_typeof(p_json->p_field) != p_expected_type THEN
RETURN format('Campo "%s" debe ser de tipo %s', p_field, p_expected_type);
END IF;
RETURN NULL; -- Sin error
END;
$$ LANGUAGE plpgsql IMMUTABLE;
DECISIÓN: Implementar helpers inline dentro de la función principal para simplicidad (no crear funciones separadas).
5. TESTING
5.1. Test Cases
Caso 1: verificador_fake_news - Válido
SELECT * FROM educational_content.validate_module4_module5_answer(
'verificador_fake_news',
'{
"claims_verified": [
{"claim_id": "c1", "is_fake": true, "evidence": "Evidencia aquí"}
]
}'::jsonb,
100
);
-- Esperado: is_valid=TRUE, validation_errors=[], requires_manual_review=TRUE
Caso 2: verificador_fake_news - Inválido
SELECT * FROM educational_content.validate_module4_module5_answer(
'verificador_fake_news',
'{
"claims_verified": "not-an-array"
}'::jsonb,
100
);
-- Esperado: is_valid=FALSE, validation_errors=['claims_verified debe ser un array']
Caso 3: diario_multimedia - Válido
SELECT * FROM educational_content.validate_module4_module5_answer(
'diario_multimedia',
'{
"entries": [
{
"date": "1898-12-26",
"content": "Lorem ipsum dolor sit amet consectetur adipiscing elit..."
}
]
}'::jsonb,
500
);
-- Esperado: is_valid=TRUE
Caso 4: comic_digital - Inválido (pocos paneles)
SELECT * FROM educational_content.validate_module4_module5_answer(
'comic_digital',
'{
"panels": [
{"dialogue": "Hola"}
]
}'::jsonb,
500
);
-- Esperado: is_valid=FALSE, validation_errors=['Mínimo 3 paneles requeridos']
5.2. Validación con create-database.sh
cd /home/isem/workspace/workspace-gamilit/gamilit/projects/gamilit/apps/database
./create-database.sh
Criterios de éxito:
- ✅ Script completa sin errores
- ✅ Función se crea correctamente
- ✅ Permisos asignados
- ✅ Comentarios visibles con
\df+
6. DOCUMENTACIÓN
6.1. Comentarios SQL
COMMENT ON FUNCTION educational_content.validate_module4_module5_answer IS
'Validador de estructura JSONB para ejercicios de Módulos 4 y 5.
NO evalúa calidad de contenido (eso es responsabilidad del docente).
SÍ valida que la estructura de respuesta sea correcta.
SIEMPRE retorna requires_manual_review=TRUE.
Tipos soportados:
- M4: verificador_fake_news, infografia_interactiva, quiz_tiktok, navegacion_hipertextual, analisis_memes
- M5: diario_multimedia, comic_digital, video_carta
Retorna:
- is_valid: TRUE si estructura válida
- validation_errors: Array de mensajes de error
- requires_manual_review: Siempre TRUE
- details: Información adicional de validación';
6.2. Actualización de Inventarios
Archivo: orchestration/inventarios/DATABASE_INVENTORY.yml
educational_content:
functions: 32 # Era 31
validators_by_module:
module_1: 7
module_2: 6
module_3: 5
module_4: 5 # ← NUEVO (1 función maneja 5 tipos)
module_5: 3 # ← NUEVO (1 función maneja 3 tipos)
generic: 4
notes: "2025-11-29: validate_module4_module5_answer agregada para validación de estructura de ejercicios creativos"
7. CRONOGRAMA
| Fase | Tarea | Tiempo Estimado | Estado |
|---|---|---|---|
| 1 | Análisis | 30 min | ✅ Completado |
| 2 | Planeación | 30 min | 🔄 En progreso |
| 3 | Implementación función | 60 min | ⏸️ Pendiente |
| 4 | Testing manual | 20 min | ⏸️ Pendiente |
| 5 | Validación carga limpia | 10 min | ⏸️ Pendiente |
| 6 | Documentación | 20 min | ⏸️ Pendiente |
| TOTAL | 2h 50min |
8. CRITERIOS DE ACEPTACIÓN
8.1. Funcionales
- ✅ Función
validate_module4_module5_answer()creada - ✅ Valida estructura para 8 tipos de ejercicios (5 M4 + 3 M5)
- ✅ Retorna errores descriptivos si estructura inválida
- ✅ SIEMPRE retorna
requires_manual_review = true - ✅ NO evalúa contenido (solo estructura)
8.2. Técnicos
- ✅ Función
IMMUTABLE(puede cachear resultados) - ✅ Comentarios SQL completos
- ✅ Permisos correctos (authenticated, admin_teacher)
- ✅ Ejemplos de uso documentados
8.3. Calidad
- ✅
create-database.shcompleta sin errores - ✅ Tests manuales pasan
- ✅ Inventarios actualizados
- ✅ Trazas documentadas
9. RIESGOS Y MITIGACIONES
| Riesgo | Probabilidad | Impacto | Mitigación |
|---|---|---|---|
| JSONB mal formado causa error | Media | Bajo | Validación NULL/tipo al inicio |
| Nuevos campos en futuro | Media | Bajo | Función IMMUTABLE permite recrear fácilmente |
| Backend no usa función | Baja | Alto | Documentar integración en handoff |
10. PRÓXIMOS PASOS
- ✅ Análisis completado (01-ANALISIS.md)
- ✅ Plan completado (02-PLAN.md)
- ⏭️ Implementar función SQL (23-validate_module4_module5.sql)
- ⏭️ Validar con carga limpia
- ⏭️ Documentar en 05-DOCUMENTACION.md
Fecha finalización plan: 2025-11-29 Próxima fase: Implementación SQL