# 09 — Operación, configuración y deuda técnica

## 9.1 Configuración por capas

```
app/config/Config.php       ← valores por defecto, versionado
        ▲ extends
app/config/ConfigEnv.php    ← overrides por entorno, NO versionado (secretos)
        ▲ extends
core/Controller.php         ← abstract Controller extends ConfigEnv
```

Cualquier controlador puede leer la configuración como `Controller::$loQueSea` o
`static::$loQueSea`, porque toda la cadena hereda de `ConfigEnv`. Igual con
`app/config/GeneralDataArray.php` → `DataEnv.php`.

### Plantilla de `ConfigEnv.php`

```php
<?php
class ConfigEnv extends Config
{
    public static $appId = 'klee_evaluacion';          // prefijo de $_SESSION
    public static $LOGIN_AUTOMATICO = true;            // SSO Microsoft
    public static $LOGIN_MANUAL = true;                // formulario usuario/clave

    public static $DB_CONNECTIONS = array(
        'klee' => array(
            'name'     => 'klee',
            'driver'   => 'mysql',
            'dbname'   => 'evaluacion_docente',
            'host'     => 'localhost',
            'user'     => '***',
            'password' => '***',
            'instance' => null,
        ),
    );

    public static $config_metodologias = array(
        'estudiantes' => true,   // discriminar cuestionario por P/V
        'pares'       => false,
        'directores'  => false,
    );

    public static $API_CONFIG = array(
        'ollama' => array('url' => 'http://<host>:11434/api/', 'token' => '***'),
    );
}
```

Otras claves que conviene fijar por entorno: `$debug`, `$Publicado`, `$email_send`,
`$userMasterKey`, `$microsoft_login`, `$FILTERS_SESION['Periodo']['valueDefault']`.

### Banderas operativas más relevantes (`Config.php`)

| Bandera | Uso operativo |
|---|---|
| `$Publicado` | `false` → pantalla de mantenimiento en el portal |
| `$debug` | Solo en desarrollo: expone SQL y trazas |
| `$LOG_ACTIONS` / `$LOG_MODULES` / `$LOG_ACCESS` | Auditoría; `LOG_MODULES` puede crecer mucho |
| `$perfil` | `"universidad"` activa la lógica de líderes de proceso en la consolidación |
| `$config_reportes` | Qué agrupaciones se ofrecen (sedes/facultades/programas) |
| `$IP_BLOCKING` | Activa la lista blanca `ips_autorizadas` |

### Configuración en base de datos (`configuraciones`)

Clave-valor por `Grupo`. Las que afectan procesos:

| Grupo | Clave | Efecto |
|---|---|---|
| `Pesos` | `PesoEstudiantes`, `PesoAutoevaluaciones`, `PesoDirectores` | **Sin ellas la consolidación no corre** |
| `Notificaciones` | `NotificacionEstudiantesAsunto/Mensaje`, `NotificacionAutoevaluacionAsunto/Mensaje`, `NotificacionDirectoresAsunto/Mensaje` | Plantillas de correo |
| `General` | `DetenerEnvioNotificaciones` | Interruptor de emergencia del cron de correos |
| `General` | `EnvioMaximoNotificaciones` | Tamaño de lote del cron (2 o 4) |

## 9.2 Despliegue

Estructura mínima en el servidor:

```
<raíz>/
  app/  core/  vendor/  files/
  public/                       ← document root recomendado
    index.php  admin/index.php  metronic_v8.0.23_html_demo1/
  app/config/ConfigEnv.php      ← creado a mano en el servidor
```

- El `.htaccess` de la raíz solo hace `DirectoryIndex public/index.php?r=home/index`; lo habitual
  es apuntar el vhost directamente a `public/`.
- `core/.htaccess` desactiva el listado de directorios. **`app/`, `core/` y `files/` no deberían
  ser accesibles por HTTP**: verifícalo tras cada despliegue.
- `files/` necesita permisos de escritura del usuario del servidor web (subidas de fotos, firmas,
  adjuntos de postulaciones).
- No hay pipeline de build ni de assets: se copia el código y la carpeta Metronic.

### Cron recomendado

```cron
*/5 * * * *  curl -s "https://<host>/?c=alertasEmail&a=sendCron" > /dev/null
```

⚠️ Ese endpoint es público (ver [06.6](06-seguridad-permisos.md#66-endpoints-públicos-que-ejecutan-trabajo)).
Mientras no se proteja, conviene restringirlo por IP en el servidor web.

### Checklist de inicio de periodo

1. Crear el `periodo` con sus fechas por actor y las banderas `Aplicar*`.
2. Revisar el banco de `preguntas` (tipos 1–6, metodologías, áreas, orden).
3. Ejecutar la sincronización en orden: estudiantes → materias de estudiantes → materias de
   docentes → docentes → `actualizarJefes` → `agregarLabores` (para pregrado y para escuela).
4. Verificar `vista_docentes_sin_jefe` y los programas creados con `IdFacultad = -1`.
5. Asignar pares (`docentesPares`) e instrumentos a los líderes (`directores.Instrumento`).
6. Comprobar los pesos en `configuraciones` (`Grupo = 'Pesos'`).

### Checklist de cierre de periodo

1. Cerrar ventanas de fechas.
2. `sincronizacion/openIAClasificacion` → clasificar comentarios.
3. `sincronizacion/openIAResumen` → generar resúmenes (requiere que no haya docentes faltantes).
4. `consolidados/evaluaciones` → **Consolidar** (destruye y recalcula el consolidado del periodo).
5. Regenerar gráficas (`consolidados/grafica*`) y validar reportes.
6. Registrar planes de mejora derivados.

## 9.3 Deuda técnica priorizada

### Crítico (seguridad / integridad)

1. **SQL sin sentencias preparadas** en toda la capa de lectura (`MysqlPDO`). Entrada de usuario
   llega al `WHERE` desde `AjaxController` y desde `criteriaExt`. → [06.1](06-seguridad-permisos.md#61-inyección-sql)
2. **Contraseñas en MD5** sin sal, con comparación `==`. → [06.2](06-seguridad-permisos.md#62-hash-de-contraseñas-md5)
3. **Contraseña maestra global** válida para cualquier usuario. → [06.3](06-seguridad-permisos.md#63-contraseña-maestra-global)
4. **Secretos en el repositorio y en el historial de git** (Microsoft client secret, API key de
   OpenAI, credenciales del integrador Academusoft). Rotar. → [06.5](06-seguridad-permisos.md#65-secretos-en-código-versionado)
5. **Endpoints públicos que ejecutan trabajo** (`sendCron`, `grafica*`, `importLabores`).
6. **Sin transacciones**: consolidación y sincronización pueden dejar datos a medias.

### Alto (mantenibilidad)

7. **Sin migraciones de esquema.** Tablas y vistas se editan a mano; no hay forma de reproducir la
   base desde el repositorio. Mínimo viable: versionar un `schema.sql` y un changelog de DDL.
8. **Sin pruebas automatizadas.** Ni unitarias ni de integración. La lógica de consolidación
   (fórmula ponderada con reescalado) es el primer candidato obvio a tests.
9. **Controladores muy largos**: `SincronizacionController` (1.259 líneas),
   `PublicController` (1.088), `OdsController` (870), `ReportesController` (805). Contienen lógica
   de negocio que debería vivir en modelos/servicios.
10. **Duplicación estructural**: `verificarGestion()` repite el mismo bloque cuatro veces (una por
    rol); las cuatro parejas Selección/Evaluación comparten el 90 % del código; `core/CheckSession.php`
    y `public/check_session.php` son byte a byte idénticos; `Model::existsFiel()` (con typo) convive
    con `Model::existsField()`, que la reemplaza.
11. **Vistas con HTML masivo repetido** (los paneles de filtro/exportar de cada `list.php` son
    copias literales). Extraer a parciales.

### Medio

12. **`Controller::changeFiltersSesionAction()` itera una clave inexistente.** Recorre
    `$filtersSesion[$key]['subFilters']`, pero `Config::$FILTERS_SESION` no define `subFilters`
    en ningún filtro. El cambio de periodo funciona porque el valor ya se guardó antes del bucle,
    pero cada cambio emite `Warning: Undefined array key "subFilters"` y
    `foreach() argument must be of type array|object`. Eliminar el bucle o declarar `subFilters => array()`.
13. **Código muerto**: `LaborDocenteModel::importLabores()` inexistente e `IdImportado` no
    declarado; integración OpenAI (`sgraaf/chatgpt-php`, `OPENIA_API_KEY`) sustituida por Ollama;
    `Instalador.php` marcado `TODO`; `TestController`; layouts `developr*` de una plantilla anterior.
14. **`$_REQUEST['criteriaExt']`** presente en varios `loadCriteria()`: superficie de ataque y
    acoplamiento fuerte cliente-BD.
15. **Salida directa (`echo`) desde el core** en rutas de validación y error.
16. **`ObservacionesClasificacion`** se compara con literales en español (`"OPORTUNIDAD DE MEJORA"`)
    esparcidos por el código; debería ser un catálogo en `GeneralDataArray`.
17. **Mezcla de relaciones por Id y por código** (`docentes.Programa` = código, `programas.IdFacultad` = Id).
    Genera joins frágiles en las vistas SQL.
18. **Sin manejo de errores del API externo** en varias rutas de sincronización: se asume que la
    respuesta es una lista.

### Bajo

19. `composer.json` sin `name`, sin `autoload` propio ni `require-dev`.
20. Sin `README.md` en la raíz (esta carpeta `docs/` lo suple parcialmente).
21. Mezcla de estilos de array (`array()` vs `[]`) y de comillas.
22. `VERSION = '3.0'` / `FECHA_VERSION = '2020-05'` desactualizadas en `core/AutoLoad.php`.

## 9.4 Datos de contexto del repositorio

- ~836 commits desde 2023-03; autores principales: Yeison Palomá (548), YesidG (236), Yeison Ortiz (42).
- Ramas activas: `master`, `yeison`, `test`, `developer`, más ramas por cliente (`EAN`, `EanDEmo`) y por persona.
- ~26.700 líneas de PHP en `app/` + `core/`, más 281 vistas.
