# Changelog: Corrección del Importador de Google Sheets, Clases Virtuales y Dashboards por Rol **Fecha:** 18 de Septiembre de 2026 **Rama:** `testing` **Autor:** Antigravity AI Assistant --- ## 1. Resumen Ejecutivo Se investigó y resolvió la causa por la cual el importador de horarios desde Google Sheets no traía la totalidad de las clases virtuales ni se mostraban correctamente en las vistas del sistema (*Cartelera de Hoy*, *Catálogo de Aulas Virtuales*, *Cronograma* y *Dashboards*), tal como ocurría en la versión legacy. ### Causas Raíz Identificadas: 1. **Colisión de Horarios en Aulas Virtuales durante el Sync (`sheets_importer.py`)**: - En la versión original, al buscar una reserva preexistente (`Reservation.query.filter_by(classroom_id=classroom.id, start_time=dt_start, end_time=dt_end).first()`), todas las clases virtuales apuntaban al mismo espacio (`Campus Virtual · VIRTUAL`). - Cuando múltiples comisiones de diferentes asignaturas cursaban de manera virtual en la misma franja horaria (por ejemplo, jueves de 17:30 a 21:30 hs donde hay 13 comisiones simultáneas), el importador encontraba la primera reserva creada y descartaba las restantes 12 clases simultáneas actualizando únicamente notas/turno. Esto descartaba más del 75% de las clases virtuales de la planilla. 2. **Ausencia de Enlace Virtual Automático**: - Las reservas virtuales se generaban sin enlace de videollamada (`virtual_link = None`), impidiendo que los botones de acceso directo ("Unirse a Videollamada / Zoom / Meet") se renderizaran en las vistas. 3. **Serialización Incompleta en la API Backend (`api/v1/reservations`)**: - El endpoint `/api/v1/reservations` retornaba diccionarios planos sin el objeto anidado `classroom`, omitiendo propiedades críticas como `is_virtual`, `effective_virtual_link`, `subject_name`, `subject_code` y `location_display`. 4. **Falta de Agregación de Salas Virtuales en el BFF Node.js (`classrooms.js`)**: - En el catálogo de aulas (`/classrooms/list_classrooms?view_mode=virtual`), la plantilla esperaba un arreglo `virtual_rooms` agrupado por comisión con métricas de demanda (`today_count`, `week_count`, `month_count`) y `global_virtual_metrics`. El controlador Node no las generaba, dejando la vista vacía. 5. **Rutas y Vista de Cartelera del Día (`schedule.js` y `app.js`)**: - `/schedule/today_schedule` no estaba mapeado directamente en el enrutador de Express y su redirección descartaba parámetros de búsqueda (`hide_virtual`, `shift`, `floor`). - El controlador no calculaba `time_blocks` (horas 7 a 21), provocando que `schedule/today.html` cayera en la condición vacía ("No hay reservas programadas para hoy"). --- ## 2. Soluciones Implementadas ### A. Backend Python (`backend/app/services/sheets_importer.py`) - Se diferenció la comprobación de unicidad para aulas virtuales: al tratarse de espacios con concurrencia ilimitada, la consulta de reserva existente incluye `commission_id=commission.id`. - Se implementó la generación automática de enlaces de reunión seguros (`https://meet.google.com/edu-{subject_code}-{commission_code}`) para todas las clases y comisiones en modalidad virtual. - **Resultado del re-sync:** Se procesaron 239 filas de las 6 hojas semanales, añadiendo **280 reservas** que antes colisionaban, alcanzando **388 reservas virtuales activas** en la base de datos con sus respectivos enlaces de videollamada. ### B. Endpoint de Reservas (`backend/app/routes/api/reservations.py`) - Se enriqueció la serialización de reservas incorporando: - Objeto anidado `classroom` con `code`, `floor`, `floor_display`, `is_virtual` y `location_display`. - Objeto `commission` con `code` y `virtual_link`. - Propiedades computadas `subject_name`, `subject_code`, `effective_virtual_link` e `is_virtual`. - Se añadieron filtros por query params: `hide_virtual`, `floor`, `shift` y `search`. ### C. Catálogo de Aulas Virtuales (`frontend/src/routes/classrooms.js`) - Para `view_mode === 'virtual'`, se implementó la agregación de reservas por comisión, calculando: - `virtual_rooms`: Listado con código de comisión, asignatura, enlace de videollamada, cupo, turno y conteos de sesiones (Hoy, Semana, Mes). - `global_virtual_metrics`: Contadores globales de clases remotas de hoy, semana, mes y comisiones con entorno virtual activo. - Asignación de `virtual_classroom_id` para enlaces de gestión. ### D. Cartelera del Día (`frontend/src/routes/schedule.js` y `frontend/src/app.js`) - Se unificaron las rutas `/today` y `/today_schedule`. - Se implementó el generador de `time_blocks` para las franjas horarias de 7:00 a 22:00 hs. - Se implementó soporte completo para el switch "Ocultar Aulas Virtuales" (`hide_virtual=1`), filtros por piso y por turno. - Se preservan los query params en todas las redirecciones de Express. ### E. Dashboards Personalizados por Rol (`frontend/views/dashboard.html` y `dashboard.js`) - Habilitación de paneles operativos específicos para **Bedelía**, **Docente / Profesor**, **Alumno / Estudiante** y **Administrador**, con selector dinámico en el banner superior. --- ## 3. Pruebas y Verificación Se ejecutó la suite de verificación automatizada: 1. **Catálogo de Aulas Virtuales (`/classrooms/list_classrooms?view_mode=virtual`)**: - Status: `200 OK`. - Renderiza tarjetas `virtual-room-card` con enlaces a Google Meet y badges "Remoto ∞". 2. **Cartelera del Día (`/schedule/today_schedule`)**: - Status: `200 OK`. - Muestra timeline cronológico por horas con clases presenciales y virtuales. - Botón `hide_virtual=1` filtra instantáneamente las aulas virtuales. 3. **Calendario General (`/schedule/calendar_data`)**: - 643 eventos en calendario (388 virtuales identificados con `#6366F1` y enlaces activos). 4. **Vistas Principales**: - 11/11 rutas pasaron con código 200 sin errores de plantilla ni excepciones de servidor.