# Sesión de desarrollo — 2026-06-18

**Rama:** `features/MirkoALS2`
**Commits incluidos:** cambios posteriores al commit `4cfdab6` (fix estudiantes query)

---

## Resumen

Sesión de trabajo sobre el frontend y backend de SGETECBA. Cuatro áreas principales: módulo de Reportes, simplificación de navegación, Carreras como hub central de materias/pensum, y soporte de código de asignatura por carrera.

---

## 1. Módulo Reportes (`/admin/reportes`, `/direccion/reportes`)

**Archivo:** `frontend/src/pages/Reportes.tsx` — reescritura completa.

### Tabs implementadas

| Tab | Contenido |
|---|---|
| **Gerencial** | Dashboard ejecutivo con KPIs globales + tarjetas por modalidad con barra proporcional de matrícula + tabla por carrera con barras inline |
| **Asistencias** | Reporte de riesgo académico: filtro carrera+período, tabla con badge de alerta (NORMAL / OBSERVACIÓN / EMERGENCIA / CRÍTICO) según % de faltas |
| **Matriculaciones** | Filtros carrera+período+fechas, descarga PDF `reporte_matriculaciones.pdf` |
| **Padrón** | Filtro texto+activo/inactivo, descarga PDF `padron_estudiantes.pdf` |
| **Malla curricular** | Selector de carrera, descarga PDF `malla_{codigo}.pdf` |

### Endpoints consumidos (ya existían en backend)
- `GET /reportes/gerencial/carreras` — métricas por carrera
- `GET /reportes/gerencial/modalidades` — métricas por modalidad
- `GET /reportes/facultad` — reporte de riesgo de asistencias
- `GET /reportes/matriculaciones/pdf` — PDF (blob)
- `GET /reportes/estudiantes/padron` — PDF (blob)
- `GET /reportes/malla/{carreraId}` — PDF (blob)

### Colores gerencial
`MOD_COLORS = ["#dc661f", "#1e3a5f", "#7c3aed", "#059669", "#0284c7", "#b45309"]` — asignados por índice de modalidad para consistencia visual entre tarjetas y tabla.

---

## 2. Simplificación de navegación

**Archivo:** `frontend/src/components/Sidebar.tsx`

Se eliminaron dos ítems del menú lateral:
- `Pensum / Oferta` → absorbido por el drawer de Carreras
- `Niveles` → administrado desde la creación de carrera

El menú Admin pasó de 13 a 11 ítems.

---

## 3. Carreras como hub central de materias

**Archivo:** `frontend/src/pages/Carreras.tsx` — refactor del drawer lateral.

### Nuevas capacidades del drawer "Materias y oferta"

- **Selector de período** con indicador `✓ activo`. Filtra por `modalidad_academica_id` de la carrera; al abrir el drawer se preselecciona el período activo automáticamente.
- **Badge de período activo** en las tarjetas de la grilla.
- **Turno por oferta**: cada fila de materia muestra el turno como chip azul claro.
- **Grupos** en el formulario de agregar: selector turno + grupo en grid de 2 columnas.
- **Descarga PDF** de malla curricular desde el header del drawer.
- **Botón renombrado**: "Ver pensum" → "Materias y oferta".

---

## 4. Código de asignatura por carrera

Permite que la misma asignatura comparta nombre pero tenga un código distinto en cada carrera (ej: "Álgebra Lineal" = `INF-MAT-01` en Informática, `MKT-MAT-01` en Marketing).

### BD — migration_013.sql

```sql
ALTER TABLE sgetecba.pensum
    ADD COLUMN codigo_en_carrera VARCHAR(50) NULL;
```

### Backend

| Archivo | Cambio |
|---|---|
| `backend/app/api/v1/routes/pensum.py` | `PensumItemCreate` y `PensumItemRead` incluyen `codigo_en_carrera`. CREATE actualiza el código si el registro ya existe. Nuevo endpoint `PATCH /pensum/codigo-en-carrera` para actualizar el código por `(asignatura_id, carrera_id)`. |
| `backend/app/api/v1/routes/oferta_asignaturas.py` | `_SELECT_OFERTA` agrega LEFT JOIN con subquery `DISTINCT ON (asignatura_id, carrera_id)` sobre `pensum` para devolver `codigo_en_carrera` junto a cada oferta. |
| `backend/app/schemas/common.py` | `OfertaAsignaturaRead` añade campo `codigo_en_carrera: str \| None = None`. |

### Frontend

| Archivo | Cambio |
|---|---|
| `frontend/src/types/api.ts` | `OfertaAsignaturaResumen` añade `codigo_en_carrera?: string \| null`. |
| `frontend/src/api/client.ts` | Nueva función `updatePensumCodigo(asignatura_id, carrera_id, codigo_en_carrera)` — llama `PATCH /pensum/codigo-en-carrera`. |
| `frontend/src/pages/Carreras.tsx` | Formulario "Agregar materia": nuevo campo "Código en esta carrera (opcional)". Al guardar llama `updatePensumCodigo` si se ingresó un código. Filas de oferta: chip naranja con el código específico si está definido. |

---

## 5. Módulo DIRECCION

**Archivos nuevos/modificados:**
- `frontend/src/layouts/DireccionLayout.tsx` — layout con acento morado, 3 ítems: Dashboard, Carreras, Reportes en rutas `/direccion/*`
- `frontend/src/auth/roles.ts` — redirect automático a `/direccion/dashboard` para rol `DIRECCION`
- `frontend/src/routes/AppRouter.tsx` — grupo de rutas `/direccion/*` con `DireccionLayout`

---

## 6. Módulo MKT

**Archivos:** `frontend/src/layouts/MKTLayout.tsx`, `frontend/src/pages/mkt/InscripcionMKT.tsx`

Flujo completo de inscripción MKT:
- Búsqueda de alumno por cédula
- Inscripción nueva / reinscripción
- Subida de foto de perfil
- Navegación con tecla Enter entre campos del formulario

---

## 7. Asistencias (Secretaria / Asistente Académico)

**Archivo:** `frontend/src/pages/secretaria/AsistenciasSecretaria.tsx`

- Botón "Imprimir planilla" habilitado
- Navegación de teclado para carga de asistencia: teclas `1`–`4` mapean a estados, `↑↓` mueven fila, `Enter` avanza al siguiente alumno

---

## 8. Horario Docente

**Archivo:** `frontend/src/pages/docente/HorarioDocente.tsx`

- Badge "Próxima sesión" en la tarjeta del horario con la fecha de la siguiente clase futura
- Cálculo de `esPasada` corregido: usa medianoche del día actual para no ocultar la sesión del día corriente hasta que termine

---

## 9. Funciones agregadas a `api/client.ts`

| Función | Endpoint | Propósito |
|---|---|---|
| `fetchReporteFacultad(params?)` | `GET /reportes/facultad` | Reporte de riesgo de asistencias |
| `downloadReporteMatriculacionesPdf(params)` | `GET /reportes/matriculaciones/pdf` | PDF de matriculaciones (blob) |
| `downloadReportePadronPdf(params)` | `GET /reportes/estudiantes/padron` | PDF padrón de estudiantes (blob) |
| `downloadReporteMallaPdf(carreraId)` | `GET /reportes/malla/{id}` | PDF malla curricular (blob) |
| `fetchGerencialCarreras()` | `GET /reportes/gerencial/carreras` | Métricas gerenciales por carrera |
| `fetchGerencialModalidades()` | `GET /reportes/gerencial/modalidades` | Métricas gerenciales por modalidad |
| `updatePensumCodigo(asig_id, car_id, codigo)` | `PATCH /pensum/codigo-en-carrera` | Código de asignatura por carrera |
| `fetchOfertasPorCarrera(carreraId, periodoId?)` | `GET /oferta_asignaturas` | Filtro por período opcional |

---

## Restricciones de esta sesión

- **No se modificó el schema de BD** salvo `migration_013` (columna nullable, sin impacto en datos).
- **No se crearon nuevas tablas ni se alteraron relaciones**.
- Toda la lógica de negocio nueva es frontend + pequeños ajustes de backend para exponer datos ya existentes.
