workspace-v1/projects/gamilit/docs/90-transversal/arquitectura-database/ARCHITECTURE-DUAL-EXERCISES-2025-11-24.md
Adrian Flores Cortes 967ab360bb Initial commit: Workspace v1 with 3-layer architecture
Structure:
- control-plane/: Registries, SIMCO directives, CI/CD templates
- projects/: Gamilit, ERP-Suite, Trading-Platform, Betting-Analytics
- shared/: Libs catalog, knowledge-base

Key features:
- Centralized port, domain, database, and service registries
- 23 SIMCO directives + 6 fundamental principles
- NEXUS agent profiles with delegation rules
- Validation scripts for workspace integrity
- Dockerfiles for all services
- Path aliases for quick reference

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-23 00:35:19 -06:00

11 KiB

Arquitectura Dual: Sistema de Ejercicios

Fecha: 2025-11-24 Versión: 2.5.3 Tipo: Arquitectura + Bug Fix Crítico Prioridad: P0 - CRÍTICO


📋 Resumen Ejecutivo

Problema: Sistema bloqueaba reenvíos de ejercicios después del primer intento exitoso, impidiendo práctica ilimitada.

Solución: Arquitectura dual que separa ejercicios autocorregibles (práctica) de ejercicios de revisión manual (evaluación formal).

Resultado:

  • Reenvíos ilimitados permitidos
  • Anti-farming implementado (XP solo en primer acierto)
  • Sin duplicación de datos ni XP

🏗️ Arquitectura Implementada

┌─────────────────────────────────────────┐
│    EJERCICIO COMPLETADO POR ESTUDIANTE  │
└─────────────────┬───────────────────────┘
                  │
                  ▼
      ¿requires_manual_grading?
                  │
        ┌─────────┴─────────┐
        │                   │
    FALSE                 TRUE
   (práctica)          (evaluación)
        │                   │
        ▼                   ▼
┌─────────────────┐   ┌──────────────────┐
│exercise_attempts│   │exercise_         │
│                 │   │submissions       │
├─────────────────┤   ├──────────────────┤
│• Reintentos ∞   │   │• 1 entrega       │
│• XP 1ra vez     │   │• Espera revisión │
│• Trigger auto   │   │• XP al calificar │
└─────────────────┘   └──────────────────┘

📂 Archivos Modificados

Database

Migraciones:

  • migrations/2025-11-24-add-requires-manual-grading.sql

    • Agrega columna requires_manual_grading a educational_content.exercises
    • Clasifica 15 ejercicios existentes como autocorregibles
    • Crea índice de performance
  • migrations/2025-11-24-cleanup-incorrect-submissions.sql

    • Elimina 8 registros legacy incorrectos
    • Limpia exercise_submissions de ejercicios autocorregibles

Ubicación histórica:

  • docs/historical-migrations/2025-11-24-add-requires-manual-grading.sql
  • docs/historical-migrations/2025-11-24-cleanup-incorrect-submissions.sql

Backend

Entity:

  • apps/backend/src/modules/educational/entities/exercise.entity.ts
    • Line 202: Campo requires_manual_grading: boolean

Service:

  • apps/backend/src/modules/progress/services/exercise-submission.service.ts
    • Lines 199-236: Validación de tipo + single submission enforcement

Controller:

  • apps/backend/src/modules/educational/controllers/exercises.controller.ts
    • Lines 16-17: Imports (Connection, InjectConnection)
    • Lines 45-46: Constructor injection
    • Lines 840-938: Arquitectura dual completa con anti-farming

🔄 Flujo de Ejercicios Autocorregibles

1. Usuario envía respuesta

POST /api/v1/educational/exercises/:id/complete
Content-Type: application/json

{
  "answers": { ... },
  "startedAt": 1234567890,
  "hintsUsed": 0,
  "powerupsUsed": []
}

2. Backend valida tipo

const exercise = await this.exercisesService.findById(exerciseId);

if (exercise.requires_manual_grading) {
  // Ruta de revisión manual
  return await this.exerciseSubmissionService.submitExercise(...);
}

// Continúa con flujo autocorregible...

3. Validación con PostgreSQL

const validationResult = await this.connection.query(`
  SELECT * FROM educational_content.validate_and_audit(
    $1::UUID, $2::UUID, $3::JSONB
  )
`, [exerciseId, profileId, JSON.stringify(submittedAnswers)]);

const { score, is_correct, feedback } = validationResult[0];

4. Anti-Farming: Verificar primer acierto

const previousAttempts = await this.exerciseAttemptService
  .findByUserAndExercise(profileId, exerciseId);

const hasCorrectAttemptBefore = previousAttempts
  .some((attempt: any) => attempt.is_correct);

const isFirstCorrectAttempt = !hasCorrectAttemptBefore && isCorrect;

// XP solo en primer acierto
let xpEarned = isFirstCorrectAttempt ? exercise.xp_reward : 0;
let mlCoinsEarned = isFirstCorrectAttempt ? exercise.ml_coins_reward : 0;

5. Crear attempt

await this.exerciseAttemptService.create({
  user_id: profileId,
  exercise_id: exerciseId,
  submitted_answers: submittedAnswers,
  is_correct: isCorrect,
  score: score,
  xp_earned: xpEarned,
  ml_coins_earned: mlCoinsEarned,
  time_spent_seconds: timeSpent,
  hints_used: hintsUsed,
  comodines_used: powerupsUsed,
});

// Trigger automático: trg_update_user_stats_on_exercise
// Actualiza: gamification_system.user_stats

6. Respuesta al Frontend

{
  "score": 100,
  "isPerfect": true,
  "rewards": {
    "xp": 100,
    "mlCoins": 20,
    "bonuses": []
  },
  "feedback": "Excelente trabajo...",
  "isFirstCorrectAttempt": true,
  "rankUp": null
}

📊 Datos Actuales

Ejercicios por Módulo

Módulo Ejercicios XP Total Tipo
Módulo 1 5 500 XP Autocorregible
Módulo 2 5 500 XP Autocorregible
Módulo 3 5 500 XP Autocorregible
Total 15 1,500 XP 100% autocorregibles

Estado de Tablas

-- exercise_attempts (práctica)
SELECT COUNT(*) FROM progress_tracking.exercise_attempts;
-- Result: 7 registros (usuarios reales practicando)

-- exercise_submissions (evaluación formal)
SELECT COUNT(*) FROM progress_tracking.exercise_submissions;
-- Result: 0 registros (ningún ejercicio de revisión manual aún)

-- Validación: NO debe haber autocorregibles en submissions
SELECT COUNT(*)
FROM progress_tracking.exercise_submissions es
JOIN educational_content.exercises e ON e.id = es.exercise_id
WHERE e.requires_manual_grading = false;
-- Result: 0 ✅ (Limpieza exitosa)

🧪 Testing

Script de Validación

cd /home/isem/workspace/workspace-gamilit/gamilit/projects/gamilit/apps/database
./test-exercise-resubmission.sh

Tests Automatizados

# Test Estado
1 Columna requires_manual_grading existe
2 15 ejercicios clasificados correctamente
3 Usuario de prueba configurado
4 10 ejercicios disponibles (M2 y M3)
5 Historial limpio
6 0 registros incorrectos en submissions

Testing Manual Pendiente

Usuario de prueba:

  • ID: bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb
  • Email: teacher@gamilit.com
  • Estado: Level 1, Rank Ajaw, 0 XP, 100 ML Coins

Ejercicio sugerido:

  • Módulo 2, Ejercicio 1: "Detective Textual: El Misterio de la Radiación"
  • ID: b842db8f-08c5-4413-8920-6a8b5f61fc22
  • Recompensas: 100 XP, 20 ML Coins

Pasos:

  1. Completar ejercicio → Verificar +100 XP
  2. Reintentar mismo ejercicio → Verificar reenvío permitido
  3. Segunda respuesta correcta → Verificar +0 XP (anti-farming)
  4. Verificar en DB: solo tabla exercise_attempts usada

Validación SQL:

-- Ver intentos del estudiante
SELECT
  e.title,
  ea.is_correct,
  ea.score,
  ea.xp_earned,
  ea.submitted_at
FROM progress_tracking.exercise_attempts ea
JOIN educational_content.exercises e ON e.id = ea.exercise_id
WHERE ea.user_id = 'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb'
ORDER BY ea.submitted_at DESC;

-- Ver XP total del estudiante
SELECT total_xp, level, current_rank, ml_coins
FROM gamification_system.user_stats
WHERE user_id = 'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb';

📈 Métricas de Impacto

Antes del Fix

Métrica Valor Estado
Reenvíos permitidos No Bloqueante
Duplicación de registros Bug crítico
XP duplicado Bug crítico
XP farming Posible Explotable

Después del Fix

Métrica Valor Estado
Reenvíos permitidos Ilimitados Funcional
Duplicación de registros No Corregido
XP duplicado No Corregido
XP farming Bloqueado Corregido

🔗 Referencias

Documentación Completa

Ubicación: /orchestration/agentes/architecture-analyst/analisis-sistema-xp-rangos-2025-11-24/

Documentos (27,000+ palabras):

  1. MATRIZ-IMPACTO-Y-DEPENDENCIAS.md (9,000+ palabras)

    • Análisis de dependencias backend/frontend
    • 5 conflictos críticos identificados
    • Planes de mitigación por conflicto
  2. SOLUCION-DEFINITIVA-EJERCICIOS-REENVIOS.md (13,000+ palabras)

    • Especificación técnica completa
    • Diagramas de flujo detallados
    • Casos de uso exhaustivos
  3. RESUMEN-IMPLEMENTACION-2025-11-24.md

    • Comparación código antes/después
    • Scripts de testing documentados
    • Métricas de validación
  4. STATUS-FINAL-2025-11-24.md

    • Estado post-implementación
    • Checklist completo (15 items)
    • Plan de testing manual paso a paso

Código Relacionado

Database:

  • DDL: apps/database/ddl/schemas/educational_content/tables/02-exercises.sql
  • Función: apps/database/ddl/schemas/educational_content/functions/validate_and_audit.sql
  • Trigger: apps/database/ddl/schemas/gamification_system/triggers/trg_update_user_stats_on_exercise.sql

Backend:

  • Entity: apps/backend/src/modules/educational/entities/exercise.entity.ts:202
  • Service Submission: apps/backend/src/modules/progress/services/exercise-submission.service.ts:199-236
  • Service Attempt: apps/backend/src/modules/progress/services/exercise-attempt.service.ts
  • Controller: apps/backend/src/modules/educational/controllers/exercises.controller.ts:840-938

🚀 Próximos Pasos

Fase 1: Testing Manual (CRÍTICO)

  • Validar reenvíos ilimitados en frontend
  • Validar anti-farming (XP solo en primer acierto)
  • Validar integridad de datos en DB

Fase 2: Completar Módulos 2 y 3

  • Avanzar 500 XP adicionales (Módulo 2 completo)
  • Verificar ascenso a rango Nacom (500 XP)
  • Avanzar 500 XP adicionales (Módulo 3 completo)
  • Verificar permanencia en Nacom hasta 1,500 XP

Fase 3: Deployment

  • Commit de cambios a Git
  • Push a staging
  • Testing en staging
  • Deployment a producción

🔄 Rollback Plan

Revertir Database

BEGIN;
DROP INDEX IF EXISTS educational_content.idx_exercises_requires_manual_grading;
ALTER TABLE educational_content.exercises
  DROP COLUMN IF EXISTS requires_manual_grading;
COMMIT;

Revertir Backend

git revert <commit-hash>
git push
npm run build
pm2 restart gamilit-backend

📞 Soporte

Implementado por: Architecture-Analyst Agent Fecha: 2025-11-24 Duración: 4 horas (análisis + implementación + testing)

Para issues:

  • Logs backend: tail -f /tmp/backend-test-fix.log
  • Testing script: apps/database/test-exercise-resubmission.sh
  • CHANGELOG completo: apps/database/docs/database/CHANGELOG.md

Última actualización: 2025-11-24 10:30 AM Versión documento: 1.0