# SGETECBA — Estado del proyecto 11/06/2026 (sesión tarde)

**Stack:** FastAPI + PostgreSQL 18 (schema: `sgetecba`) + React + TypeScript + Vite + TailwindCSS  
**Branch:** `features/MirkoALS`  
**Repo:** https://github.com/ZIS-TECBA/sgetecba

---

## Estado de bugs (imagen Pendientes — Junio 2026)

| Bug | Descripción | Severidad | Estado |
|-----|-------------|-----------|--------|
| BUG-06 | `createOferta` siempre pasa `nivel_academico_id: null` — no hay selector en el form de creación | ALTA | ✅ Resuelto — commit `c914ff9` |
| BUG-07 | `handleDelete` en Matriculaciones no tiene `catch` — errores silenciados | MEDIA | ✅ Resuelto — commit `ab34cb6` |
| BUG-09 | Doble `useEffect` en Asistencias → 4 requests HTTP al montar | ALTA | ✅ Resuelto — commit `7c84c8f` |
| BUG-10 | Paginación Asistencias usa closure con `page` potencialmente stale | MEDIA | ✅ Resuelto — commit `862a828` |
| BUG-12 | Nombre duplicado en accessibility tree de tabla Estudiantes | BAJA | ⚠️ No verificado — sin test de accesibilidad formal |

---

## Lo que se hizo en esta sesión

### 1. Rediseño conceptual Asignaturas → Pensum → Ofertas

**Problema:** El flujo anterior mezclaba dos conceptos distintos en la misma pantalla de Ofertas: a qué carrera pertenece una materia (dato permanente del plan de estudios) y en qué horario se dicta en un período (dato logístico).

**Solución implementada:**

| Pantalla | Para qué sirve ahora |
|----------|----------------------|
| **Asignaturas** | Crear la materia y asignarla a la carrera + semestre en el mismo paso |
| **Apertura de materias** (antes Ofertas) | Abrir la materia para un período: turno, grupo, nivel |
| **Niveles** | Catálogo de semestres/módulos/años |
| **Períodos** | Ciclos académicos con fechas |

**Tabla nueva en BD:** `sgetecba.pensum` — vincula asignatura ↔ carrera ↔ nivel de forma permanente.

**Archivos nuevos:**
- `backend/app/api/v1/routes/pensum.py` — CRUD pensum
- `backend/app/api/v1/routes/grupos.py` — CRUD grupos
- `backend/app/api/v1/routes/niveles_academicos.py` — CRUD niveles
- `frontend/src/pages/Grupos.tsx` — página admin Grupos
- `frontend/src/pages/NivelesAcademicos.tsx` — página admin Niveles

---

### 2. Flujo docente: self-assign (docente se asigna solo a materias)

**Concepto:** El admin crea las aperturas de materias. El docente entra a su interfaz, ve las materias disponibles sin docente asignado y se "une" a la que va a dictar.

#### Backend — nuevos endpoints en `/docente`

| Método | Ruta | Descripción |
|--------|------|-------------|
| GET | `/docente/ofertas-disponibles` | Lista aperturas sin docente, filtrando las que ya tiene el docente logueado |
| POST | `/docente/asignarse` | El docente se asigna a una apertura |
| DELETE | `/docente/asignaciones/{id}` | El docente se desvincula (solo si no tiene sesiones configuradas) |
| DELETE | `/docente/asignaciones/{id}/horario` | Elimina el horario y sesiones sin asistencia registrada |

**Archivos modificados:**
- `backend/app/services/docente_service.py` — funciones `get_ofertas_disponibles`, `asignarse_a_oferta`, `divorciarse_de_oferta`, `eliminar_horario_docente`
- `backend/app/api/v1/routes/docente.py` — 4 endpoints nuevos
- `backend/app/schemas/docente.py` — `OfertaDisponible`, campo `asignacion_id` en `AsignaturaDocente`

---

### 3. Rediseño UX — HorarioDocente.tsx

**Problema de UX anterior:** todo en una sola página larga, el docente tenía que scrollear hasta abajo para configurar horario, sin buscador.

**Nuevo diseño con tabs:**

- **Tab "Mis materias"** (por defecto): lista compacta de materias asignadas con acciones directas
  - Botón **"Configurar horario"** / **"Editar horario"** → abre **modal** (sin scroll)
  - Botón **"Eliminar horario"** → confirmación → borra sesiones sin asistencia
  - Botón **"Dejar materia"** → solo visible si no hay sesiones, con confirmación
  - Acordeón **"Sesiones"** → tabla de fechas generadas con estado
- **Tab "Disponibles para unirme"**: grid de cards con buscador en tiempo real
  - Filtra por nombre de materia, carrera, período o turno
  - Botón "Unirme" por card → al unirse, redirige al tab "Mis materias"

**Botón "Actualizar"** eliminado del header (innecesario).

---

### 4. Docentes — columna "Ver materias"

En la tabla de docentes del admin se agregó el botón **"Ver materias"** por fila.  
Abre un modal que muestra todas las asignaciones activas e inactivas del docente: materia, carrera, período.

**Endpoint usado:** `GET /docentes/{docente_id}/asignaciones` (ya existía).

---

### 5. Renombrar "Planilla del período" → "Imprimir horario"

Cambio de etiqueta en los botones de exportación PDF en:
- `frontend/src/pages/Asistencias.tsx`
- `frontend/src/pages/secretaria/AsistenciasSecretaria.tsx` (2 ocurrencias)

---

### 6. Dump de base de datos

Generado con `pg_dump` (PostgreSQL 18) y guardado en `BD/sgetecba_dump.sql`.  
Incluye schema completo + datos actuales de prueba.

**Para replicar en otra máquina:**
```bash
psql -U postgres -c "CREATE DATABASE sgetecba;"
psql -U postgres -d sgetecba -f BD/sgetecba_dump.sql
```

---

## Tareas pendientes

### Críticas
- [ ] BUG-12: verificar accessibility tree en tabla Estudiantes (baja prioridad pero sin confirmar)
- [ ] Matriculaciones: `fecha_inscripcion` sin valor por defecto → inicializar con hoy
- [ ] Matriculaciones: estado sin pre-selección → pre-seleccionar ACTIVA
- [ ] Selectores grandes → reemplazar `<select>` por combobox con búsqueda (períodos, asignaturas, carreras)

### Funcionalidad pendiente
- [ ] Pasar lista desde la interfaz docente (seleccionar sesión → marcar asistencia)
- [ ] Vista Pensum por Carrera en admin
- [ ] Importación Excel de estudiantes
- [ ] Editar materias de estudiante ya inscrito
- [ ] Faltas y Abandonos (páginas Secretaría)

### Técnicas
- [ ] Normalizar respuestas API: reemplazar `200 { ok: false }` por `400/404/409/422`
- [ ] Responsividad global en móvil/tablet
- [ ] Tests mínimos: auth por roles, importación con duplicados, asistencia duplicada → 409

---

## Archivos tocados esta sesión

```
backend/
  app/api/v1/api.py                          Registro routers pensum, grupos, niveles
  app/api/v1/routes/docente.py               4 endpoints nuevos (ofertas-disponibles, asignarse, divorciarse, eliminar-horario)
  app/api/v1/routes/grupos.py                NUEVO — CRUD grupos
  app/api/v1/routes/niveles_academicos.py    NUEVO — CRUD niveles
  app/api/v1/routes/pensum.py                NUEVO — CRUD pensum
  app/schemas/docente.py                     OfertaDisponible, asignacion_id
  app/services/docente_service.py            4 funciones nuevas

frontend/src/
  api/client.ts                              fetchOfertasDisponibles, asignarseAOferta, divorciarseDeOferta,
                                             eliminarHorarioDocente, fetchGruposAdmin, CRUD grupos,
                                             fetchAsignacionesDocente, tipos Grupo / OfertaDisponible
  types/api.ts                               AsignaturaDocente.asignacion_id, OfertaDisponible, Grupo
  components/Sidebar.tsx                     Links Grupos y Niveles
  routes/AppRouter.tsx                       Rutas /admin/grupos y /admin/niveles
  pages/Grupos.tsx                           NUEVO — CRUD grupos
  pages/NivelesAcademicos.tsx                NUEVO — CRUD niveles
  pages/Docentes.tsx                         Botón Ver materias + modal asignaciones
  pages/Asignaturas.tsx                      Asignación a carrera al crear
  pages/Ofertas.tsx                          Carga desde pensum
  pages/Asistencias.tsx                      Renombrar botón Imprimir horario
  pages/docente/HorarioDocente.tsx           Rediseño completo (tabs + modal + buscador + eliminar horario)
  pages/secretaria/AsistenciasSecretaria.tsx Renombrar botón Imprimir horario (x2)

BD/
  sgetecba_dump.sql                          NUEVO — dump completo schema + datos (491 KB)
```

---

*SGETECBA — Documento interno de desarrollo — 11/06/2026 — Mirko Lazarte*
