# Migración: Portal Docentes — Fase 2 (Evaluaciones en Línea)

Tercera fase de la migración de `uepca/docentes/` hacia `admin_docentes/`
(ver `migracion_de_modulo_docentes.md` para el plan completo). Cubre el
banco de preguntas, la creación/administración de evaluaciones en línea, la
corrección de respuestas de texto libre, los resultados en PDF y el
calendario de evaluaciones del docente. Cierra el pendiente que dejó
explícito `documentacion/evaluaciones-en-linea-migracion.md` (lado alumno,
ya migrado): *"Portal docente para crear/editar exámenes, preguntas, banco
de opciones y corregir preguntas de texto libre... queda fuera de este
trabajo"*.

## Alcance

Se apoya 100% en el esquema ya creado por `db/fase9-evaluaciones-online.sql`
(`examen_varios`, `examen_pregunta`, `examen_preguntas`, `examen_opciones`,
`examen_respuesta`, `examen_notas`, `examen_vio`) — no se tocó ninguna de
esas tablas.

| Origen (`uepca/docentes/`) | Destino (`admin_docentes/`) | Rol |
|---|---|---|
| `preguntas-list.php` + `preguntas-buscar-ajax.php` + `pregunta-ver-agrega.php` | `preguntas-list.php` | Banco de preguntas: listar, crear y editar (simple/múltiple/texto, hasta 10 opciones, imagen opcional) |
| `examen-list.php` + `examen-eliminar-ajax.php` + `materias-buscar.php` | `examenes-list.php` | Listado de evaluaciones del docente + crear nueva + eliminar (soft-delete) |
| `examen-perfil.php` + `examen-perfil-actual-ajax.php` + `examen-pregunta-ver-ajax.php` + `examen-pregunta-quitar-ajax.php` | `examen-perfil.php` | Editar datos del examen + agregar/quitar preguntas del banco |
| `examen-vistos.php` + `examen-vistos-buscar.php` | `examen-vistos.php` | Roster del grado/sección: visto/no visto, nota acumulada |
| `examen-corregir.php` + `examen-nota-actual.php` + `examen-nota-observacion.php` + `examen-respuesta-borrar.php` | `examen-corregir.php` | Ver preguntas/respuestas de un alumno, calificar (especialmente texto libre), borrar respuestas |
| `examen-resultados.php` | `procesos/examen-resultados.php` | PDF de notas consolidadas por alumno |
| `calendario.php` + `calendario-nuevo.php` + `calendario-borrar.php` + `calendario-get.php` | `calendario-evaluaciones.php` | Calendario de evaluaciones del grado/sección (crear/ver/borrar) |

**Excluido de esta fase**: `hist-alu.php`, `list-historial.php`,
`rep-cortes.php`, `revisionPdfListado.php`, `observ-guia.php` (reportes /
docente guía — fases 4 y 5).

## Decisiones de diseño

- **Slugs**: `doc-preguntas`, `doc-examenes`, `doc-calendario-evaluaciones`,
  grupo de menú "Evaluaciones" — seed en
  `db/fase12-portal-docentes-evaluaciones.sql`, ya aplicado contra
  `jesistem_siscev` local y habilitado para colegio 11. Sidebar condicionado
  también por `$_SESSION['docDa']=='S'` (todo este módulo depende de
  `trgsmp`, exclusivo de Bachillerato/Liceo — no aplica a Primaria).
- **Consolidación de AJAX a páginas normales**: el legacy resuelve casi todo
  con `$.post()` a ~15 archivos PHP diminutos que devuelven JSON para
  actualizar modales in-place (guardado campo-por-campo al cambiar un
  input, popups con `swal()`). Se migró a formularios servidos normalmente
  (submit + redirect), el mismo patrón ya usado en el resto de
  `admin_docentes/`. Reduce ~20 archivos legacy a 7 páginas + 1 procesador
  de PDF, sin perder funcionalidad — es la simplificación de UX más grande
  de esta fase.
- **Calendario simplificado**: el `calendario.php` original trae un widget
  de calendario JS custom (~500 líneas de `quicktmpl`/jQuery hecho a mano,
  sin librería). Se reemplazó por una tabla ordenable (mismo patrón que el
  resto del portal) en `calendario-evaluaciones.php` — misma funcionalidad
  (crear/ver/borrar eventos de `evalua_calendario` por grado/sección), sin
  reimplementar un calendario visual. Si se necesita la vista de calendario
  real más adelante, es una mejora de UI aislada, no de datos.
- **Seguridad — verificación de propiedad reforzada**: cada página
  reverifica `id_docente = $_SESSION['idAlum']` contra `examen_varios`
  antes de mostrar o modificar un examen (no solo confía en la sesión
  genérica como el legacy). Igual para preguntas del banco
  (`id_docente` en `examen_pregunta`) y materias/grados
  (`trgsmp` en cada acción de creación).
- **Bug de seguridad del legacy corregido, no replicado**:
  `examen-perfil-actual-ajax.php` tomaba el **nombre de columna SQL**
  directo de `$_POST['campo']` sin whitelist (`UPDATE examen_varios SET
  $campo='$campoNue' WHERE id_examen='$id_examen'`) — inyección de columna
  arbitraria. `examen-perfil.php` migrado solo permite editar un conjunto
  fijo de columnas (`titulo_examen`, `fecha_ini`, `fecha_fin`,
  `publica_nota`, `valor`) vía un único formulario con `UPDATE` de columnas
  fijas, nunca dinámicas desde input.
- **Bloqueo tras iniciar la evaluación**: se preserva la regla del legacy —
  una vez que `fecha_ini` ya pasó, ni los datos del examen ni sus preguntas
  se pueden modificar (por integridad académica, evita alterar una prueba
  que estudiantes ya están respondiendo).
- **Auditoría de borrado de respuestas**: se crean las tablas
  `bitacora_examen` y `examen_borrado` (no existían en
  `jesistem_juanxxiii`) para registrar cuándo un docente borra las
  respuestas de un alumno — mismo criterio que ya usaba el legacy, ahora
  con estructura normalizada a utf8mb4 (ver
  `db/fase12-portal-docentes-evaluaciones.sql`).

## Bugs encontrados y corregidos durante la verificación end-to-end

1. **`bind_param()` con conteo de tipos incorrecto** (2 veces, en
   `preguntas-list.php`): un `INSERT` le faltaba un carácter de tipo para
   la imagen (`Fatal error: ArgumentCountError`), un `UPDATE` tenía uno de
   más. `mysqli::bind_param()` no tolera el desajuste — se corrigieron
   ambos conteos.
2. **Timezone por defecto del servidor rompía la ventana "evaluación ya
   iniciada"**: ninguna página nueva llamaba
   `date_default_timezone_set('America/Caracas')` antes de comparar fechas
   contra `date('Y-m-d H:i:s')`. En este entorno de desarrollo el timezone
   por defecto de PHP es UTC (4h adelante de Caracas), así que un examen
   programado para "dentro de 2 horas" en hora local aparecía como "ya
   comenzado". **Corrección centralizada**: se agregó
   `date_default_timezone_set('America/Caracas')` a `bootstrap.php`
   (compartido por `admin_alumnos` y `admin_docentes`) en vez de repetirlo
   en cada archivo — corrige esta clase de bug para todo el portal, no solo
   para Fase 2. Antes de este fix, `notas-bachillerato.php` (Fase 1) y
   `perfil.php` (Fase 0) tenían el mismo riesgo latente sin haberse
   manifestado en las pruebas de esas fases.
3. **`htmlspecialchars(null)` deprecado**: los eventos de calendario creados
   automáticamente al crear un examen no llevan `texto` (columna opcional,
   solo la usan los eventos creados manualmente desde
   `calendario-evaluaciones.php`) — al listarlos, `htmlspecialchars($e['texto'])`
   con `null` genera *deprecated notice* en PHP 8.1+. Corregido con
   `?? ''`.

## Verificación

Cuenta de docente sintética (`90000005`, cargo docente bachillerato,
autorizada por el usuario) asignada vía `trgsmp2526` a un grado/sección/
materia real (61/1/6111 "Fundamento Humano Cristiano"), y un alumno
sintético (`90000006`) en ese mismo grado/sección, **sin representante**
(mismo criterio que Fase 1, para no arriesgar disparar los triggers de
notificación Telegram con datos falsos).

Flujo probado de punta a punta vía HTTP (login real + cookies de sesión):

- `preguntas-list.php` → creó una pregunta de selección simple (3 opciones,
  1 correcta) y una de texto libre; verificado por `SELECT` directo que
  `examen_pregunta`/`examen_opciones` quedaron correctas. Vista de edición
  (`?editar=`) también probada sin errores.
- `examenes-list.php` → creó una evaluación nueva; verificado que
  `examen_varios` y el evento correspondiente en `evalua_calendario`
  quedaron correctos. Eliminar (`eliminar_examen`) probado al final:
  soft-delete (`status='2'`) + borrado del evento de calendario asociado,
  confirmado por conteo en BD.
- `examen-perfil.php` → agregó ambas preguntas del banco a la evaluación
  (5 ptos. cada una, exactamente el valor total de 10); confirmado en
  `examen_preguntas`. Aquí se encontró y corrigió el bug de timezone.
- Se simuló la respuesta del alumno sintético insertando directamente en
  `examen_vio`/`examen_respuesta`/`examen_notas` (la pregunta de selección
  simple autocalificada en 5 ptos., la de texto con nota en 0 pendiente de
  corrección — replicando exactamente lo que hace
  `admin_alumnos/examen-guarda.php` al momento en que el alumno entrega el
  examen, que ya crea una fila en `examen_notas` por cada pregunta,
  incluidas las de texto).
- `examen-vistos.php` → mostró correctamente "visto el ..." en hora local y
  la nota acumulada (5.00 Ptos., la del auto-calificado) para el alumno
  sintético; el resto del listado (alumnos reales del curso, en modo solo
  lectura) se mostró sin alterarse.
- `examen-corregir.php` → mostró ambas preguntas con su respuesta correcta,
  la respuesta del alumno y las opciones (marcando la correcta). Se guardó
  una calificación manual (4.50 ptos. + observación) para la pregunta de
  texto pendiente — confirmado por `SELECT` directo.
- `procesos/examen-resultados.php` → `Content-Type: application/pdf`, PDF
  válido.
- `calendario-evaluaciones.php` → creó un evento manual, lo listó junto al
  evento automático del examen (sin error tras el fix de `texto` nulo), y
  lo eliminó (soft-delete, verificado que el creado automáticamente por
  `examenes-list.php` no se vio afectado).
- Los 8 archivos nuevos/modificados de esta fase (incluido `bootstrap.php`)
  pasan `php -l` sin errores.

**No verificado en este ambiente**: el flujo real de un alumno respondiendo
el examen a través de `admin_alumnos/examen-hacer.php`/`examen-guarda.php`
(ya se probó en la migración de esa fase, según
`evaluaciones-en-linea-migracion.md`) — aquí se simuló directamente en BD
para no depender de ese flujo completo otra vez. Tampoco se probó con más
de un docente compartiendo el mismo grado/sección (para confirmar que el
aislamiento por `id_docente` no deja ver/editar preguntas o exámenes de
otro docente) — se revisó por código (todas las queries filtran por
`id_docente = $_SESSION['idAlum']`) pero no se ejercitó con una segunda
cuenta.

## Activar el módulo para un colegio

1. Aplicar `db/fase12-portal-docentes-evaluaciones.sql` contra `siscev` (ya
   aplicado en local; falta en producción) y contra la BD del colegio (crea
   `bitacora_examen`/`examen_borrado` si no existen).
2. Confirmar que `db/fase9-evaluaciones-online.sql` (Parte B) ya está
   aplicado contra la BD de ese colegio — sin las tablas `examen_*`, este
   módulo no funciona.
3. En `panel_admin` → colegio → módulos → habilitar **Banco de Preguntas**,
   **Evaluaciones en Línea**, **Calendario de Evaluaciones**.

## Pendiente / fuera de este alcance

- Resto de fases (Aula Virtual, Comunicación, Reportes) — ver
  `migracion_de_modulo_docentes.md`.
- Imágenes de preguntas (`imagen_question/`): se sirven/guardan igual que
  el legacy (carpeta en la raíz del repo, servidas vía
  `https://DOMINIO/imagen_question/...`) — mismo patrón y mismo gap ya
  documentado para `fotoalu/`/`fotodoc/` en `CLAUDE.md`.
- Vista de calendario visual (widget tipo mes/semana/día) si se decide que
  la tabla no es suficiente — ver "Calendario simplificado" arriba.
- Probar aislamiento entre dos docentes que comparten grado/sección/materia
  (ver "No verificado" arriba).
