API Frontend – Cierre de Bloque¶
Esta guía explica cómo el frontend debe cerrar un bloque. El cierre requiere 2 pasos:
1) Preview: calcula la nota sugerida y habilita una ventana temporal para poder confirmar.
2) Confirmación: cierra el bloque (pasa el estado a pending para revisión).
El sistema obliga a realizar el preview inmediatamente antes de la confirmación. Si intentas confirmar sin un preview válido, fallará con PREVIEW_REQUIRED.
Endpoint¶
- Modo preview: usar query
preview=true - Modo confirmación: no enviar
previewopreview=false
Autenticación¶
Requiere token JWT. Enviar Authorization: Bearer <JWT>
Parámetros¶
| Parámetro | Ubicación | Requerido | Descripción |
|---|---|---|---|
blockId |
path | Sí | ID del bloque a cerrar |
preview |
query | No | true para preview; omitido/false para confirmar |
studentId |
query/body | Sí | ID del alumno con el que se evalúa el bloque |
schoolCourseId |
query/body | No | Curso escolar. Si no se envía, usa el último curso |
grade |
body | Solo en confirmación | Nota final del bloque. DECIMAL(4,2) |
Flujo Recomendado (Frontend)¶
┌──────────────────┐
│ 1. Llamar PREVIEW │
└────────┬─────────┘
│
▼
┌──────────────────────────────────────┐
│ 2. Mostrar resumen y nota sugerida │
│ - suggestedGrade │
│ - counts (contenidos evaluados) │
└────────┬─────────────────────────────┘
│
▼
┌──────────────────────────────────────┐
│ 3. Profesor acepta o modifica nota │
└────────┬─────────────────────────────┘
│
▼
┌──────────────────────────────────────┐
│ 4. Llamar CONFIRMACIÓN (antes TTL) │
│ - Enviar grade en body │
│ - Estado cambia a "pending" │
└──────────────────────────────────────┘
Importante: La confirmación valida que existe un preview vigente para el mismo employeeId y blockId. Si el TTL expiró o no hiciste preview, devuelve error PREVIEW_REQUIRED.
Ejemplos¶
Preview (curl)¶
curl -X POST \
"https://<host>/api/v2/blocks/123/close?preview=true&studentId=456&schoolCourseId=2025" \
-H "Authorization: Bearer <token>"
Respuesta:
{
"ok": true,
"mode": "preview",
"expiresInSeconds": 600,
"counts": {
"contentScores": 5,
"personalizedScores": 2,
"total": 7
},
"suggestedGrade": 7.85
}
Confirmación (curl)¶
curl -X POST \
"https://<host>/api/v2/blocks/123/close?studentId=456" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"grade": 7.5}'
Respuesta:
{
"ok": true,
"message": "Block closed successfully. Status set to pending.",
"block": { /* entidad actualizada */ },
"status": "pending",
"grade": 7.5
}
Preview (TypeScript/fetch)¶
const response = await fetch(
`/api/v2/blocks/${blockId}/close?preview=true&studentId=${studentId}&schoolCourseId=${courseId ?? ''}`,
{
method: 'POST',
headers: { Authorization: `Bearer ${token}` },
}
);
const data = await response.json();
// data.suggestedGrade, data.counts, data.expiresInSeconds
Confirmación (TypeScript/fetch)¶
const response = await fetch(
`/api/v2/blocks/${blockId}/close?studentId=${studentId}&schoolCourseId=${courseId ?? ''}`,
{
method: 'POST',
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ grade: finalGrade }),
}
);
Respuestas¶
Preview exitoso¶
{
"ok": true,
"mode": "preview",
"expiresInSeconds": 600,
"counts": {
"contentScores": 5,
"personalizedScores": 2,
"total": 7
},
"suggestedGrade": 7.85
}
Confirmación exitosa¶
{
"ok": true,
"message": "Block closed successfully. Status set to pending.",
"status": "pending",
"grade": 7.5,
"studentBlockId": 42
}
Nota: El
studentBlockIdes el ID del registro en la tablastudent_blocksque almacena el estado del bloque para este estudiante específico.
Errores Comunes¶
| Código | Error | Descripción |
|---|---|---|
| 400 | PREVIEW_REQUIRED |
Intentaste confirmar sin preview vigente (o expirado) |
| 400 | INVALID_STATUS |
El bloque no está en estado open |
| 400 | STUDENT_ID_REQUIRED |
Falta studentId o no es numérico |
| 400 | BLOCK_ID_REQUIRED |
blockId inválido |
| 400 | GRADE_REQUIRED |
Falta grade en confirmación |
| 404 | BLOCK_NOT_FOUND |
blockId no existe |
| 401 | UNAUTHORIZED |
Falta/expiró token |
Notificación a Administradores¶
Al confirmar el cierre de un bloque, se envía automáticamente un email a los administradores configurados en ADMIN_EMAILS con:
- Nombre del bloque (ej: "Bloque 1")
- Asignatura
- Nombre completo del estudiante
- Nombre completo del profesor
- Nota asignada
- Fecha de cierre
Notas Técnicas¶
- El preview marca una llave temporal en Redis
blockClosePreview:{blockId}:{employeeId}con TTL configurable (BLOCK_CLOSE_PREVIEW_TTL, default 600s = 10 min). - La confirmación exige que exista esa marca (mismo usuario) y la consume al cerrar.
- Si no envías
schoolCourseId, el backend usa el último curso automáticamente. - Al confirmar, el bloque pasa a
pendingpara revisión administrativa.