# GAP CRITICO: Responses Page No Muestra Datos Reales **Fecha**: 18 Diciembre 2025 **Analista**: Requirements-Analyst **Prioridad**: P0 - CRITICO (Bloquea funcionalidad core) **Estado**: ✅ CORREGIDO - Implementación completada --- ## CORRECCION APLICADA **Fecha de corrección**: 19 Diciembre 2025 ### Archivos Modificados | Archivo | Cambio | |---------|--------| | `apps/backend/src/modules/teacher/dto/exercise-responses.dto.ts` | Agregados enums `ResponseSource`, `SubmissionStatus` y campos `source`, `status`, `feedback`, `requires_manual_grading` | | `apps/backend/src/modules/teacher/services/exercise-responses.service.ts` | Método `getAttempts()` ahora usa UNION de ambas tablas; `getAttemptDetail()` busca en ambas tablas | ### Cambios Clave 1. **UNION Query**: El método `getAttempts()` ahora consulta: - `progress_tracking.exercise_attempts` (ejercicios autocorregibles) - `progress_tracking.exercise_submissions` (ejercicios de revisión manual) 2. **Nuevo campo `source`**: Indica de qué tabla proviene cada registro (`attempt` o `submission`) 3. **Filtro por status**: Excluye automáticamente submissions con status `draft` 4. **getAttemptDetail mejorado**: Busca primero en `exercise_attempts`, si no encuentra busca en `exercise_submissions` --- ## RESUMEN EJECUTIVO El Teacher Portal tiene un gap critico: la pagina de Responses (`/teacher/responses`) **NO muestra las respuestas de los estudiantes** porque consulta la tabla incorrecta. | Aspecto | Estado Actual | Estado Esperado | |---------|---------------|-----------------| | Tabla consultada | `exercise_attempts` | `exercise_submissions` + `exercise_attempts` | | Datos visibles | 0 o datos antiguos | Todas las respuestas | | Funcionalidad | ROTA | FUNCIONAL | --- ## ANALISIS DEL PROBLEMA ### Arquitectura Dual de Tablas El sistema GAMILIT tiene **dos tablas** para almacenar respuestas de ejercicios: ``` ┌─────────────────────────────────────────────────────────────────────┐ │ FLUJO ACTUAL (ROTO) │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ ESTUDIANTE TEACHER PORTAL │ │ ┌─────────────────┐ ┌─────────────────┐ │ │ │ Completa │ │ Responses Page │ │ │ │ Ejercicio │ │ /teacher/ │ │ │ │ │ │ responses │ │ │ └────────┬────────┘ └────────┬────────┘ │ │ │ │ │ │ ▼ ▼ │ │ ┌─────────────────┐ ┌─────────────────┐ │ │ │ POST /progress/ │ │ GET /teacher/ │ │ │ │ submissions/ │ │ attempts │ │ │ │ submit │ │ │ │ │ └────────┬────────┘ └────────┬────────┘ │ │ │ │ │ │ ▼ ▼ │ │ ┌─────────────────┐ ┌─────────────────┐ │ │ │ exercise_ │ ╳ │ exercise_ │ │ │ │ submissions │─────╳─────────│ attempts │ │ │ │ (AQUI ESTAN │ ╳ │ (AQUI BUSCA) │ │ │ │ LOS DATOS!) │ │ │ │ │ └─────────────────┘ └─────────────────┘ │ │ │ │ ❌ NO HAY CONEXION - EL TEACHER NO VE LAS RESPUESTAS │ │ │ └─────────────────────────────────────────────────────────────────────┘ ``` ### Tabla 1: `exercise_submissions` **Proposito**: Ejercicios que requieren revision manual (Modulos 4 y 5) - Archivo DDL: `apps/database/ddl/schemas/progress_tracking/tables/04-exercise_submissions.sql` - Campo de respuestas: `answer_data` (JSONB) - Estados: draft, submitted, graded, reviewed - Tiene: `feedback`, `graded_at`, columnas de revision manual **Servicio que escribe**: `ExerciseSubmissionService.submitExercise()` - Endpoint: `POST /progress/submissions/submit` - Usado por: Frontend de estudiantes (`progressAPI.ts`) ### Tabla 2: `exercise_attempts` **Proposito**: Ejercicios autocorregibles (multiples intentos) - Archivo DDL: `apps/database/ddl/schemas/progress_tracking/tables/03-exercise_attempts.sql` - Campo de respuestas: `submitted_answers` (JSONB) - Sin estados de workflow - solo registro de intentos **Servicio que lee**: `ExerciseResponsesService.getAttempts()` - Endpoint: `GET /teacher/attempts` - Usado por: Teacher Portal Responses Page --- ## EVIDENCIA DEL GAP ### 1. Frontend de Estudiantes (progressAPI.ts:384-385) ```typescript // Backend endpoint: POST /api/progress/submissions/submit const backendPayload = { userId, exerciseId, answers, }; const { data } = await apiClient.post>( '/progress/submissions/submit', // <-- ESCRIBE EN exercise_submissions backendPayload, ); ``` ### 2. Backend de Teacher Portal (exercise-responses.service.ts:186) ```sql FROM progress_tracking.exercise_attempts attempt -- <-- LEE DE exercise_attempts LEFT JOIN auth_management.profiles profile ON profile.user_id = attempt.user_id ... ``` ### 3. Validacion en ExerciseSubmissionService (linea 227) ```typescript // Este servicio es SOLO para ejercicios que requieren revisión manual // Los ejercicios autocorregibles deben usar ExerciseAttemptService if (!exercise.requires_manual_grading) { throw new BadRequestException( 'This exercise is auto-graded and allows multiple attempts...' ); } ``` Esto confirma la arquitectura dual, pero el Teacher Portal solo lee de una tabla. --- ## IMPACTO | Impacto | Descripcion | |---------|-------------| | **Funcionalidad** | Teacher no puede ver respuestas de estudiantes | | **Calificacion** | No puede calificar ejercicios de Modulos 4-5 | | **Monitoreo** | No puede monitorear progreso real de estudiantes | | **Datos** | Los datos existen en BD pero son invisibles al teacher | --- ## SOLUCION PROPUESTA ### Opcion A: Modificar ExerciseResponsesService para consultar AMBAS tablas (RECOMENDADO) **Complejidad**: Media **Riesgo**: Bajo **Tiempo estimado**: 4-6 horas ```typescript // exercise-responses.service.ts async getAttempts(userId: string, query: GetAttemptsQueryDto): Promise { // Query UNION de ambas tablas const sql = ` -- Ejercicios autocorregibles (exercise_attempts) SELECT 'attempt' as source, attempt.id AS id, attempt.user_id AS student_id, attempt.submitted_answers AS answers, attempt.score, attempt.is_correct, attempt.submitted_at, ... FROM progress_tracking.exercise_attempts attempt ... UNION ALL -- Ejercicios de revision manual (exercise_submissions) SELECT 'submission' as source, sub.id AS id, sub.user_id AS student_id, sub.answer_data AS answers, sub.score, sub.is_correct, sub.submitted_at, ... FROM progress_tracking.exercise_submissions sub ... WHERE sub.status != 'draft' ORDER BY submitted_at DESC LIMIT $X OFFSET $Y `; } ``` ### Opcion B: Crear endpoint separado para submissions **Complejidad**: Baja **Riesgo**: Bajo **Tiempo estimado**: 2-3 horas Crear un nuevo endpoint `/teacher/submissions` que consulte `exercise_submissions` y agregar una tab en el frontend para mostrar ambos tipos. ### Opcion C: Migrar datos a una sola tabla (NO RECOMENDADO) **Complejidad**: Alta **Riesgo**: Alto (podria romper otras partes del sistema) **Tiempo estimado**: 2-3 dias --- ## ARCHIVOS A MODIFICAR ### Opcion A (Recomendada) | Archivo | Cambio | |---------|--------| | `apps/backend/src/modules/teacher/services/exercise-responses.service.ts` | Modificar query para UNION de ambas tablas | | `apps/backend/src/modules/teacher/dto/exercise-responses.dto.ts` | Agregar campo `source: 'attempt' \| 'submission'` | | `apps/frontend/src/apps/teacher/components/responses/ResponsesTable.tsx` | (Opcional) Mostrar indicador de tipo | --- ## VALIDACION POST-IMPLEMENTACION ### Pasos de Verificación 1. **Compilar backend**: ```bash cd apps/backend && npm run build ``` 2. **Test manual**: Como estudiante, completar un ejercicio de Modulo 4 o 5 3. **Verificar BD**: ```sql SELECT * FROM progress_tracking.exercise_submissions WHERE status != 'draft' ORDER BY submitted_at DESC LIMIT 5; ``` 4. **Verificar Teacher Portal**: Navegar a `/teacher/responses` y confirmar que aparece el ejercicio 5. **Test de detalle**: Click en "Ver" y confirmar que muestra las respuestas correctamente 6. **Test de filtros**: - Filtrar por `source=submission` para ver solo ejercicios de revisión manual - Filtrar por `status=submitted` para ver ejercicios pendientes de calificación ### Nuevo Flujo Corregido ``` ┌─────────────────────────────────────────────────────────────┐ │ FLUJO CORREGIDO ✅ │ ├─────────────────────────────────────────────────────────────┤ │ │ │ ESTUDIANTE TEACHER PORTAL │ │ ┌────────────┐ ┌────────────┐ │ │ │ Submit │ │ Responses │ │ │ │ Ejercicio │ │ Page │ │ │ └─────┬──────┘ └──────┬─────┘ │ │ │ │ │ │ ▼ ▼ │ │ ┌────────────────┐ ┌────────────────┐ │ │ │ exercise_ │ │ UNION QUERY │ │ │ │ SUBMISSIONS │◄─────────│ attempts + │ │ │ │ (M4-M5) │ │ submissions │ │ │ └────────────────┘ └────────────────┘ │ │ │ ▲ │ │ │ │ │ │ ┌────────────────┐ │ │ │ │ exercise_ │─────────────────────┘ │ │ │ ATTEMPTS │ │ │ │ (M1-M3) │ │ │ └────────────────┘ │ │ │ │ ✅ CONEXION COMPLETA - Teacher VE todas las respuestas │ │ │ └─────────────────────────────────────────────────────────────┘ ``` --- ## DEPENDENCIAS - RLS policies ya existen para `exercise_submissions` (linea 168 del DDL) - El frontend ya maneja el formato de respuesta (no requiere cambios mayores) --- ## SIGUIENTE PASO **ACCION INMEDIATA**: Implementar Opcion A - Modificar `ExerciseResponsesService` para consultar ambas tablas con UNION. --- *Analisis realizado: 2025-12-18* *Proyecto: GAMILIT - Portal Teacher* *Gap ID: G-RESPONSES-001*