# 19 — Mapa de Dependencias

> Qué depende de qué, verificado a partir de las referencias reales del código y de las relaciones del esquema.

---

## 1. Capas del sistema

```mermaid
graph TD
    subgraph "Entrada"
      IDX["public/index.php"]
      AL["core/AutoLoad.php"]
    end
    subgraph "Configuración"
      ENV[".env → Env"]
      CFG["Config → ConfigEnv"]
      MENU["Menu · QuickActionsConfig · Titles"]
    end
    subgraph "Framework"
      CB["Controller"]
      MB["Model + 26 Atributos"]
      VW["View"]
      RT["Router"]
      LST["Lista / ListaAjax"]
      DBL["Db → KleePDO → MysqlPDO"]
      UTL["Cache · Logger · UserFlash\nRateLimiter · PasswordPolicy\nQueueCss · QueueScripts · helpers"]
    end
    subgraph "Aplicación"
      CTRL["75 controladores"]
      MOD["127 modelos"]
      SRV["12 servicios"]
      VIEWS["291 vistas + 8 layouts"]
    end
    subgraph "Persistencia"
      MY[("MySQL")]
      FS["files/"]
      ST["storage/cache/"]
    end

    IDX --> AL
    ENV --> CFG --> AL
    AL --> CB
    CB -.hereda.-> CFG
    CTRL --> CB
    CTRL --> MOD
    CTRL --> SRV
    CTRL --> LST
    CTRL --> VW --> VIEWS
    MOD --> MB --> DBL --> MY
    SRV --> MOD
    LST --> MOD
    CB --> UTL
    MOD --> UTL
    RT --> MOD
    MENU --> RT
    CTRL --> FS
    UTL --> ST
```

### 🔴 Dependencias inversas del core (existentes y conocidas)

`core/` **debería** ser independiente de `app/`, pero no lo es:

| Fichero del core | Referencia de `app/` | Motivo |
|---|---|---|
| `core/Controller.php` | `PermisosModel`, `UsuariosModel`, `DemoController`, `Config`/`ConfigEnv` | Autorización y modo demo |
| `core/Model.php` | `UsuariosModel`, `LogModulesModel`, `Config`, `Controller`, `ROUTER` | Auditoría y filtros de sesión |
| `core/Router.php` | `PermisosModel` | Devuelve `'#'` si no hay permiso |
| `core/Lista.php` | `PermisosModel`, `UsuariosModel` | Filtra acciones por permiso |
| `core/ListaAjax.php` | `Controller` (CSRF) | Genera el formulario de `remove` |
| `core/View.php` | Instancia `{X}Controller` | Para resolver el layout |
| `app/config/Menu.php` | `ColaboradoresModel`, `Controller`, `ROUTER` | Condición `colaborador_lider_equipo` |

**No introduzcas dependencias inversas nuevas.** Las existentes son deuda técnica conocida.

---

## 2. Dependencia central: `colaboradores`

Es la entidad raíz. **20+ tablas y prácticamente todos los módulos dependen de ella.**

```mermaid
graph TD
    COL[("colaboradores")]

    COL --> M1["Metas"]
    COL --> M2["Evaluación 360"]
    COL --> M3["Planes de Desarrollo"]
    COL --> M4["Mapa de Talento"]
    COL --> M5["Planes de Carrera"]
    COL --> M6["Sucesión"]
    COL --> M7["Reconocimientos"]
    COL --> M8["Vacaciones"]
    COL --> M9["Asistencia"]
    COL --> M10["Nómina"]
    COL --> M11["Adelantos"]
    COL --> M12["Beneficios"]
    COL --> M13["Capacitación"]
    COL --> M14["Tickets"]
    COL --> M15["Comunicación Interna"]
    COL --> M16["Mi Equipo"]
    COL --> M17["Portal del Colaborador"]

    CAT["cargos · areas · sedes\ntipos_contrato · ceco"] --> COL
    REC["Reclutamiento"] -->|crea| COL
    COL -->|IdJefeInmediato| COL
```

**Consecuencia operativa:** cualquier cambio en `colaboradores` o en `vista_colaboradores` afecta a **todo** el sistema. Y eliminar un colaborador requiere `ColaboradoresModel::deleteCascade()`, porque la mayoría de esas tablas **no tienen clave foránea declarada**.

---

## 3. Dependencia temporal: `periodos`

```mermaid
graph LR
    P[("periodos")] --> MT["Metas\nIdPeriodo · ventanas · min/max"]
    P --> EV["Evaluación 360\nIdPeriodo · flags · pesos"]
    P --> RS["respuestas\nIdPeriodo"]
    P --> MC["metas_consolidado\nIdPeriodo"]
    P --> CC["competencias_colaboradores\nIdPeriodo"]
    P --> FS["Filtro global de sesión\nFIND_IN_SET"]
    P --> LG["Login del portal\ncampo periodo obligatorio"]
    P --> DB["Dashboard\ngetSesionId()"]
```

El periodo activo (`$_SESSION[APP_ID]['filtersSesion']['Periodo']`) se inyecta automáticamente en **toda** consulta de un modelo que tenga columna `Periodo` o `IdPeriodo`.

---

## 4. Cadena de cálculo de talento

La dependencia funcional más larga del sistema:

```mermaid
graph TD
    A["periodos<br/>configuración de ventanas y pesos"] --> B["metas<br/>peso · cumplido"]
    A --> C["evaluaciones + respuestas<br/>360 multi-fuente"]
    B --> D["metas_consolidado<br/>Preliminar · Total"]
    C --> E["Totales por fuente<br/>ponderados por los pesos del periodo"]
    F["potencial_criterios +<br/>potencial_evaluacion_detalle"] --> G

    D -->|calcularPuntajeMetas| G["TalentScoreService"]
    E -->|calcularPuntaje360| G
    G -->|"0.6 criterios + 0.4 360"| H["Potencial"]
    D -->|Desempeño| I["Consolidado<br/>0.5 × desempeño + 0.5 × potencial"]
    H --> I
    I --> J["categorizarTalento()<br/>← talento_categorias"]
    J --> K["potencial_evaluaciones"]
    K --> L1["Mapa 9-Box<br/>← talento_celdas_9box"]
    K --> L2["Altos Potenciales<br/>← getUmbralHipo()"]
    K --> L3["requierePlanDesarrollo()<br/>→ planes_desarrollo"]
    K --> L4["Mi Equipo<br/>obtenerResumenEquipo()"]
    K --> L5["Portal: Mi Desempeño"]
    K --> L6["Sucesión: PuntajeAjuste"]
```

**Si rompes un eslabón, todo lo que está aguas abajo devuelve cero o valores incorrectos.**

---

## 5. Dependencias por módulo

Leyenda: **→** depende de · **⇢** dependencia opcional o débil

| Módulo | Depende de | Es usado por |
|---|---|---|
| **Colaboradores** | cargos, areas, sedes, tipos_contrato, ceco | **Todos** |
| **Reclutamiento** | cargos, areas, sedes, tipos_contrato ⇢ colaboradores | Colaboradores (crea altas) |
| **Metas** | periodos, colaboradores, metas_categorias | Talento, Planes de Desarrollo, Dashboard |
| **Evaluación 360** | periodos, colaboradores, competencias, preguntas, escalas | Talento, Planes de Desarrollo |
| **Competencias/Preguntas/Escalas** | *(catálogos raíz)* | Evaluación 360, Planes de Desarrollo |
| **Planes de Desarrollo** | colaboradores, competencias ⇢ metas ⇢ evaluaciones ⇢ 9-Box | Portal, Mi Equipo |
| **Talento / 9-Box** | metas_consolidado, evaluaciones, potencial_criterios, talento_* | Sucesión, Planes de Desarrollo, Mi Equipo, Portal |
| **Planes de Carrera** | cargos, colaboradores | Portal |
| **Sucesión** | cargos, colaboradores ⇢ Talento | — |
| **Reconocimientos** | colaboradores, reconocimiento_tipos, reconocimiento_reglas | Portal |
| **Vacaciones** | colaboradores, politicas_vacaciones, festivos | **Asistencia** (bloquea marcación) |
| **Asistencia** | colaboradores, asistencia_turnos, **Vacaciones**, **Ausencias** | Nómina ⇢ (horas extra) |
| **Nómina** | colaboradores, nomina_conceptos, nomina_parametros | Adelantos (descuento por cuotas) |
| **Adelantos** | colaboradores, adelanto_politicas ⇢ Nómina | Portal |
| **Beneficios** | colaboradores, cargos, areas, sedes, tipos_contrato *(reglas)* | Portal |
| **Capacitación** | colaboradores | Portal ⇢ Planes de Desarrollo |
| **Tickets** | colaboradores, servicio_categorias, servicio_sla_politicas | Portal, Dashboard |
| **Línea de Ética** | linea_etica_tipos, linea_etica_categorias | *(nadie)* |
| **Comunicación Interna** | colaboradores, areas, sedes, cargos *(audiencias)* | Portal |
| **Mi Equipo** | colaboradores (`LiderEquipo`, `IdJefeInmediato`), Talento, Metas, Planes de Desarrollo | — |
| **Portal del Colaborador** | **Casi todos los módulos** | — |
| **Configuración** | *(raíz)* | **Todos** |
| **Asistente IA** | Toda la base de datos (lectura) | — |

### Módulo totalmente independiente

**Línea de Ética.** No requiere colaborador, no requiere sesión y nada depende de ella. Es el módulo más aislado y, por tanto, el más seguro de modificar.

### Módulos hoja (nada depende de ellos)

Línea de Ética, Sucesión, Reconocimientos, Mi Equipo, Comunicación Interna, Asistente IA.

### Módulos raíz (todo depende de ellos)

Configuración (roles, permisos, periodos, sedes, cargos, areas, tipos_contrato) y Colaboradores.

---

## 6. Acoplamientos fuertes (cuidado al modificar)

```mermaid
graph LR
    V["Vacaciones aprobadas"] -->|bloquea| A["Marcación de asistencia"]
    AU["Ausencias aprobadas"] -->|bloquea| A
    A -->|horas extra| N["Nómina ⇢"]
    N -->|cuotas de descuento| AD["Adelantos"]
    R["Reclutamiento: contratado"] -->|crea/activa| C["Colaborador"]
    M["Metas consolidadas"] -->|desempeño| T["Talento"]
    E["Evaluación 360"] -->|potencial| T
    T -->|requierePlanDesarrollo| PD["Planes de Desarrollo"]
    T -->|PuntajeAjuste| S["Sucesión"]
    L["LiderEquipo = 1"] -->|habilita| ME["Mi Equipo"]
    L -->|habilita| PDE["Planes del Equipo"]
```

| Acoplamiento | Fichero | Qué se rompe si lo tocas |
|---|---|---|
| Vacaciones/Ausencias → Asistencia | `AsistenciaRegistrosModel::validarBloqueoMarcacion()` | Se podría marcar asistencia estando de vacaciones |
| Reclutamiento → Colaborador | `RecruitmentApplicationsModel::moverEtapa()` | El contratado no quedaría activo |
| Metas + 360 → Talento | `TalentScoreService::calcularPuntajeMetas()` / `calcularPuntaje360()` | Todo el 9-Box a cero |
| Talento → Planes de Desarrollo | `TalentScoreService::requierePlanDesarrollo()` | No se dispararían los planes |
| `LiderEquipo` → Menú | `Menu::evaluarCondicionItem()` → `ColaboradoresModel::esLiderEquipo()` | "Mi Equipo" desaparecería o aparecería para todos |
| Periodo de sesión → Todo | `Model::addFiltersSesion()` | Listados vacíos en media aplicación |

---

## 7. Dependencias externas

```mermaid
graph LR
    K["Kuorum"] --> MY[("MySQL 8")]
    K --> SMTP["SMTP<br/>PHPMailer"]
    K -.si IA_ENABLED.-> OL["Ollama<br/>LLM local"]
    K -.si configurado.-> MS["Microsoft Entra ID<br/>OAuth 2.0"]
    K -.código muerto.-> OAI["OpenAI"]
    K --> CDN1["fonts.googleapis.com<br/>Poppins"]
    K --> CDN2["cdn.datatables.net<br/>idioma es-mx"]
    K --> FS2["files/"]
    K --> CR["Planificador cron<br/>externo"]
```

| Dependencia | Criticidad | Si falla |
|---|---|---|
| MySQL | 🔴 **Total** | `"Opps tuvimos un problema, conectandonos a la base de datos"` + `exit()` |
| `files/` escribible | 🟠 Alta | Fallan subidas, fotos y logotipos |
| `storage/cache/` escribible | 🟡 Media | Degrada en silencio; el autoload sigue funcionando |
| SMTP | 🟡 Media | No sale el correo; el resto funciona |
| `cdn.datatables.net` | 🔵 Baja | Los listados salen en inglés |
| `fonts.googleapis.com` | 🔵 Baja | Se usa la fuente de respaldo |
| Ollama | 🔵 Baja | Solo afecta al Asistente IA |
| Microsoft Entra ID | 🔵 Baja | Solo afecta al login institucional |
| Cron externo | 🟡 Media | No se envían las alertas por correo |

### Dependencias Composer

| Paquete | Usado por | Si falta |
|---|---|---|
| `phpmailer/phpmailer` | `AlertasEmailController`, `PlanesCarreraController` | Error fatal al enviar correo |
| `mpdf/mpdf` | `CapacitacionPortalController` | El certificado sale en HTML (degradación silenciosa) |
| `studio-42/elfinder` | `ElFinderController` | 503 con mensaje claro |
| `sgraaf/chatgpt-php` | `SincronizacionController` | Sin impacto: código muerto |
| `symfony/http-foundation` | **Nadie** | Sin impacto |
| `phpunit/phpunit` (dev) | `tests/` | No se pueden ejecutar las pruebas |
| `fakerphp/faker` (dev) | **Nadie** | Sin impacto |

---

## 8. Dependencias de configuración

```mermaid
graph TD
    ENV[".env"] --> SYNC["Config::syncConfigFromEnv()"]
    SYNC --> DB["DB_CONNECTIONS['klee']"]
    SYNC --> MAIL["email_send"]
    SYNC --> IA["ASISTENTE_IA"]
    SYNC --> MSF["microsoft_login"]
    SYNC --> FLAGS["Banderas: debug, LOG_*, VACACIONES_*, …"]
    DB --> ALL["TODA la aplicación"]

    CONF[("tabla configuraciones")] --> C1["metas.max_por_colaborador"]
    CONF --> C2["DetenerEnvioNotificaciones"]
    CONF --> C3["EnvioMaximoNotificaciones"]
    CONF --> C4["ReclutamientoContratoExigeFirma"]
    CONF --> C5["Umbrales del dashboard"]

    PER[("periodos")] --> P1["Ventanas de metas"]
    PER --> P2["Pesos de evaluación 360"]
    PER --> P3["Min/max de metas"]

    TC[("talento_config")] --> T1["Pesos de talento"]
    TC --> T2["Umbral HiPo"]
```

**El punto único de fallo de la configuración es `Config::syncConfigFromEnv()`.** Una variable que no se lea ahí, no existe para la aplicación.

---

## 9. Orden de carga en el arranque

Dependencias estrictas que **no se pueden reordenar**:

```
1. session_start()                    ← antes de cualquier acceso a $_SESSION
2. Url.php                            ← URL::base_url() la usan layouts y ROUTER
3. Env.php + Env::load('.env')        ← ANTES que Config
4. Config.php                          ← define la clase base
5. ConfigEnv[.local].php               ← extiende Config
6. Config::syncConfigFromEnv()         ← DESPUÉS de ConfigEnv, ANTES de Controller
7. Controller.php                      ← lee Controller::$debug inmediatamente
8. ErrorHandler.php (si $debug)
9. Router · Html · Db · Cache · KleePDO
10. Menu.php                           ← necesita ROUTER
11. Atributo · Model · ModelArray · View
12. LogsConsole · UserFlash · Lista · ListaAjax
13. QueueCss · QueueScripts · RateLimiter · PasswordPolicy
14. Logger · LoggerConfig · LoggerManager
15. helpers/DebugHelper.php
16. vendor/autoload.php                ← Composer
17. classmap + spl_autoload_register
18. Resolución y despacho del controlador
```

Ver `core/AutoLoad.php`.

---

## 10. Grafo de dependencias entre módulos (texto)

```
Configuración (roles · permisos · periodos · sedes · cargos · areas · tipos_contrato)
    │
    ├──> Colaboradores  ◄──── Reclutamiento (crea altas)
    │        │
    │        ├──> Metas ────────────┐
    │        ├──> Evaluación 360 ───┤
    │        │      ▲               │
    │        │   Competencias       │
    │        │   Preguntas          ▼
    │        │   Escalas      TalentScoreService
    │        │                      │
    │        │                      ├──> Mapa de Talento 9-Box
    │        │                      ├──> Altos Potenciales
    │        │                      ├──> Planes de Desarrollo
    │        │                      ├──> Sucesión
    │        │                      └──> Mi Equipo
    │        │
    │        ├──> Vacaciones ──┐
    │        ├──> Ausencias ───┤
    │        │                 ▼
    │        ├──> Asistencia (bloqueo de marcación)
    │        │        │
    │        │        └──> horas extra ⇢ Nómina
    │        │                              │
    │        ├──> Nómina ◄───────────────────┘
    │        │        └──> cuotas ⇢ Adelantos
    │        │
    │        ├──> Adelantos de Nómina
    │        ├──> Beneficios
    │        ├──> Capacitación (LMS)
    │        ├──> Tickets / Centro de Ayuda
    │        ├──> Comunicación Interna
    │        ├──> Reconocimientos
    │        ├──> Planes de Carrera
    │        └──> Portal del Colaborador (agrega casi todo)
    │
    └──> Línea de Ética   ← independiente, no requiere colaborador ni sesión

Transversales: Asistente IA (lee toda la BD) · Auditoría (log_*) · Modo Demo
```

---

## 11. Qué revisar antes de modificar cada elemento

| Si modificas… | Revisa… |
|---|---|
| `colaboradores` o `vista_colaboradores` | **Todo el sistema.** Especialmente `deleteCascade()` y las 15 pestañas de `ColaboradoresController` |
| `periodos` | Metas, Evaluación 360, filtros de sesión, login del portal, dashboard |
| `metas` / `metas_consolidado` | `TalentScoreService`, Planes de Desarrollo, dashboard |
| `evaluaciones` / `respuestas` | `TalentScoreService`, consolidado 360 |
| `TalentScoreService` | 9-Box, HiPo, Sucesión, Mi Equipo, Portal, Planes de Desarrollo |
| `core/Controller.php` | Los 75 controladores |
| `core/Model.php` | Los 127 modelos |
| `core/db/MysqlPDO.php` | **Todo el acceso a datos** |
| `core/ListaAjax.php` | Todos los listados |
| `Config::$FILTERS_SESION` | Todas las consultas de modelos con `Estado` o `IdPeriodo` |
| `Menu.php` | La navegación de ambos portales. Requiere volver a iniciar sesión |
| `permisos` | La autorización. Requiere volver a iniciar sesión |
| `Controller::$PUBLIC_COLLABORATOR_ROUTES` | El acceso del portal del colaborador |
| Una vista `vista_*` | El modelo que la usa como `$VIEW_NAME` y su `ListaAjax` |
| `roles` | `usuarios.Tipo`, `permisos.IdRol`, el rol 5 forzado en el login del portal |
| `cargos` | Colaboradores, Carrera, Sucesión, reglas de Beneficios |
| `.env` | `Config::syncConfigFromEnv()` |

---

## Documentos relacionados
- [04_MODULES.md](04_MODULES.md)
- [05_DATABASE.md](05_DATABASE.md)
- [21_TRACEABILITY.md](21_TRACEABILITY.md)
