# Sesión de Trabajo — 20 de Junio 2026

**Rama:** `feature/santi`  
**Responsable:** Santiago Caballero  
**Asistido por:** Claude Sonnet 4.6  

---

## 1. Fix: Facultad de Tecnología no aparecía en Reportes

**Problema:** `GET /api/v1/reportes/gerencial/facultades` retornaba 0 carreras/estudiantes para todas las facultades.

**Causa raíz:** La carrera INFORMATICA tenía `facultad_id = NULL` en `sgetecba.carreras`. El query de reportes hace JOIN por ese campo, entonces la carrera quedaba fuera de cualquier facultad.

**Fix aplicado:**
```sql
UPDATE sgetecba.carreras SET facultad_id = 1 WHERE id = 1 AND eliminado_en IS NULL;
-- Facultad de Tecnología id=1
```

**Resultado:** Facultad de Tecnología muestra `total_carreras=1, total_estudiantes=1, total_ofertas=1, total_inscripciones=1`.

---

## 2. Backup de base de datos

Generado y guardado en `BD/backups/backup_2026-06-17.sql` (219 KB).

---

## 3. Merge de rama MirkoALS2 → feature/santi

Se integró `features/MirkoALS2` en `feature/santi` con **prioridad a MirkoALS2** en conflictos.

```bash
git merge origin/features/MirkoALS2 --strategy=recursive --strategy-option=theirs
```

**100 archivos modificados · +41,621 líneas integradas · 0 conflictos manuales.**

### Módulos nuevos integrados desde MirkoALS2:

| Área | Archivos nuevos |
|------|----------------|
| Backend routes | `calificaciones.py`, `convalidaciones.py`, `matriculas.py`, `periodos_clase.py`, `turnos.py`, `parametros_institucionales.py` |
| Frontend pages | `Calificaciones.tsx`, `CalificacionesAdmin.tsx`, `PanelAlumnos.tsx`, `AsignacionHorarios.tsx` |
| Módulo MKT | `DashboardMKT.tsx`, `InscripcionMKT.tsx`, `InscritosMKT.tsx` |
| Layouts | `DireccionLayout.tsx`, `MKTLayout.tsx` |
| BD | Backups, migrations 007–013, seeds de prueba, diagramas ER |

---

## 4. QA Intermedio — post-merge

### Resultado inicial (pre-migraciones):
- **16/22 endpoints OK**
- **6 endpoints con error 500** — todos por tablas/columnas faltantes en DB

### Causa raíz de los 500:

| Problema | Detalle |
|----------|---------|
| Tabla faltante | `sgetecba.calificaciones` |
| Tabla faltante | `sgetecba.periodos_clase` |
| Tabla faltante | `sgetecba.parametros_institucionales` |
| Columna faltante | `sgetecba.pensum.codigo_en_carrera` |
| Columna faltante | `sgetecba.pensum.anio_pensum` |
| Columna faltante | `sgetecba.periodos_academicos.anio_pensum` |

---

## 5. Aplicación de migraciones pendientes

### migration_013 — `pensum.codigo_en_carrera`
```sql
ALTER TABLE sgetecba.pensum ADD COLUMN IF NOT EXISTS codigo_en_carrera VARCHAR(50) NULL;
```

### migration_pensum_calificaciones (MirkoALS2)
```sql
ALTER TABLE sgetecba.periodos_academicos ADD COLUMN IF NOT EXISTS anio_pensum INTEGER;
ALTER TABLE sgetecba.estudiante_carreras ADD COLUMN IF NOT EXISTS anio_pensum INTEGER;

-- Duplicar pensum 2025 → versión 2023
INSERT INTO sgetecba.pensum (asignatura_id, carrera_id, nivel_academico_id, anio, ...)
SELECT ..., 2023, ... FROM sgetecba.pensum WHERE anio = 2025 AND eliminado_en IS NULL;

-- Asignar anio_pensum a períodos existentes
UPDATE sgetecba.periodos_academicos SET anio_pensum = 2025 WHERE nombre LIKE '2025%' OR nombre LIKE '2026%';
```

### Tablas creadas desde cero
```sql
CREATE TABLE sgetecba.periodos_clase (...);
CREATE TABLE sgetecba.calificaciones (...);
CREATE TABLE sgetecba.parametros_institucionales (...);
```

### Resultado post-migraciones: **23/23 endpoints OK ✅**

---

## 6. Backup post-migraciones

Generado: `BD/backups/backup_2026-06-20.sql` (229 KB).

---

## 7. QA por Roles — flujo completo

Usuarios probados: `admin`, `asistente_academico`, `docente`, `decano` — todos con contraseña `Admin123*`.

| Rol | Score | Estado |
|-----|-------|--------|
| ADMIN | 23/23 | ✅ Perfecto |
| ASISTENTE_ACADÉMICO | 9/10 | ✅ OK |
| DOCENTE | 5/8 | ⚠️ 2 obs. detectadas |
| DIRECCIÓN | 4/4 | ✅ Perfecto |

### Integridad de DB verificada:
- 0 estudiantes con carrera inválida
- 0 registros en pensum con asignatura/carrera inválida
- 0 ofertas con periodo inválido
- 0 sesiones con oferta inválida
- 0 carreras sin facultad
- TypeScript frontend: **0 errores**

---

## 8. Resolución de observaciones del QA

### OBS 1 — DOCENTE sin registro en tabla `docentes`

**Problema:** Usuario `docente` (id=3) existía en `sgetecba.usuarios` pero no tenía FK en `sgetecba.docentes`. Las rutas `/docente/mis-asignaturas`, `/docente/horario`, `/docente/mis-estudiantes` retornaban 404.

**Fix DB:**
```sql
INSERT INTO sgetecba.docentes (nombres, apellidos, cedula_identidad, correo, activo, usuario_id, creado_en, actualizado_en)
VALUES ('Docente', 'Demo', '99999999', 'docente@tecba.edu.bo', true, 3, NOW(), NOW());
-- → id=1 asignado
```

**Fix código** (`backend/app/api/v1/routes/docente.py:88`):
```python
# ANTES — inválido en PostgreSQL con SELECT DISTINCT
ORDER BY e.nombre_completo

# DESPUÉS
ORDER BY nombre_completo   # usa el alias del SELECT
```

**Resultado:** 3/3 endpoints docente self-service → **200 ✅**

---

### OBS 2 — ASISTENTE_ACADÉMICO sin acceso a `GET /grupos`

**Problema:** `grupos.py` tenía `require_roles(ROLE_ADMIN)` exclusivo. AA necesita leer grupos para el flujo de matriculación.

**Fix** (`backend/app/api/v1/routes/grupos.py`):
```python
# Antes
from app.core.roles import ROLE_ADMIN
_: dict = Depends(require_roles(ROLE_ADMIN)),          # GET

# Después
from app.core.roles import ROLE_ADMIN, ROLE_ASISTENTE_ACADEMICO
_: dict = Depends(require_roles(ROLE_ADMIN, ROLE_ASISTENTE_ACADEMICO)),  # GET solamente
# POST / PUT / DELETE → siguen siendo ROLE_ADMIN exclusivo
```

**Resultado:** AA puede leer grupos ✅ — escritura/borrado siguen bloqueados ✅

---

## 9. Resultado final de regresiones

| Check | Resultado |
|-------|-----------|
| AA POST /grupos bloqueado | ✅ 403 |
| AA DELETE /grupos bloqueado | ✅ 403 |
| ADMIN lee grupos | ✅ 200 |
| DOCENTE bloqueado en grupos | ✅ 403 |
| DIRECCION bloqueada en grupos | ✅ 403 |

---

## 10. Git — commits del día

| Hash | Mensaje |
|------|---------|
| `227db16` | db: backup 2026-06-20 post-migraciones |
| `39da89c` | merge: integra features/MirkoALS2 en feature/santi |
| `91e76be` | feat: fix inscripción estudiantes, roles AA, HorarioDocente readonly, backup 2026-06-17 |

Todos pusheados a `origin/feature/santi`.

---

## Archivos modificados hoy

| Archivo | Tipo | Cambio |
|---------|------|--------|
| `backend/app/api/v1/routes/grupos.py` | Código | Agrega AA al GET de grupos |
| `backend/app/api/v1/routes/docente.py` | Código | Fix SQL ORDER BY en SELECT DISTINCT |
| `sgetecba.carreras` | DB | `facultad_id = 1` asignado a INFORMATICA |
| `sgetecba.docentes` | DB | INSERT usuario docente (id=3 vinculado) |
| `sgetecba.pensum` | DB | Columna `codigo_en_carrera` + versión 2023 |
| `sgetecba.periodos_academicos` | DB | Columna `anio_pensum` |
| `sgetecba.estudiante_carreras` | DB | Columna `anio_pensum` |
| `sgetecba.calificaciones` | DB | Tabla creada |
| `sgetecba.periodos_clase` | DB | Tabla creada |
| `sgetecba.parametros_institucionales` | DB | Tabla creada |
| `BD/backups/backup_2026-06-17.sql` | Backup | 219 KB |
| `BD/backups/backup_2026-06-20.sql` | Backup | 229 KB |
