# Pendientes — Migracion a Nube Talento Humano

## Objetivo

Mover los datos historicos y los cierres mensuales de Talento Humano a PostgreSQL en nube, para que el dashboard y los cierres no dependan de que la Mac este encendida.

## Estado certificado al 2026-07-23

- Local read-only audit OK: existen 10 tablas de Talento Humano en `Base de Datos Talento Humano`.
- Tablas principales con datos: `historico_empleados`, `historico_ir`, `historico_nomina_pyg`, `historico_nomina_pyg_control`, `hotel_unificacion`, `ceco_unificacion`, `socios`.
- Remoto comercial `Bases de Datos Historicos Comercial - rmartinez` contiene historicos comerciales en `public`.
- Talento Humano quedo migrado en la base remota separada `Base de Datos Historicos Talento Humano`, schema `public`.
- Estructura remota creada: 10 tablas, secuencias, PKs, indices y FK principal.
- Datos remotos cargados y certificados contra local por conteos y hashes agregados.
- Secretos retirados del codigo: PostgreSQL, NominaApp y P&G se leen desde `.env` local o Secrets de nube.
- `.env` local creado sin versionar y con permisos `600`.
- Endpoints admin protegidos por `X-Admin-Key` cuando `APP_REQUIRE_ADMIN_AUTH=true`.
- CORS restringido por `CORS_ALLOWED_ORIGINS`.
- Errores HTTP no exponen traceback salvo `APP_DEBUG_ERRORS=true`.
- SSL verifica certificados por defecto con `APP_VERIFY_SSL=true`.

## Controles contra fugas de datos

- No imprimir API keys, passwords, cedulas, nombres de empleados ni sueldos individuales en consola, logs o reportes.
- Usar auditorias con conteos, columnas, indices y hashes agregados, no muestras de datos personales.
- Mantener `.env` fuera de Git y con permisos privados.
- Configurar Secrets en el scheduler de nube, no variables pegadas en scripts.
- En PostgreSQL nube, usar usuario dedicado de aplicacion, no superusuario.
- Separar permisos:
  - Dashboard: solo lectura sobre tablas historicas y mapeos.
  - Cierres: escritura controlada sobre tablas historicas requeridas.
  - Admin sync: protegido por `ADMIN_API_KEY`.
- No exponer PostgreSQL abierto a internet sin allowlist/VPN/Tailscale/tunel privado.
- Rotar llaves que estuvieron historicamente en el repositorio antes de considerar el despliegue como seguro.

## Plan paso a paso

1. Crear destino de Talento Humano en nube. **Completado**
   - Opcion A: nueva base `Base de Datos Talento Humano`.
   - Opcion B: schema separado dentro de una base existente, por ejemplo `talento_humano`.
   - Ejecutado: base remota separada `Base de Datos Historicos Talento Humano`.

2. Crear usuarios y permisos. **Pendiente**
   - `th_dashboard_reader`: `SELECT`.
   - `th_cierre_writer`: `SELECT`, `INSERT`, `UPDATE`, `DELETE` solo en tablas TH.
   - Evitar superusuario y credenciales compartidas.

3. Migrar estructura primero. **Completado**
   - Exportar solo DDL desde local.
   - Revisar tablas, indices, secuencias y constraints.
   - Aplicar DDL en remoto en ventana controlada.

4. Migrar datos despues de aprobar estructura. **Completado**
   - Exportar datos con `pg_dump --data-only`.
   - Restaurar en remoto.
   - Verificar conteos por tabla y `MAX(fecha)` / `MAX(periodo)`.
   - Comparar hashes agregados por tabla cuando aplique, sin imprimir PII.

5. Apuntar scripts a nube. **Preparado**
   - Configurar `PG_HOST`, `PG_PORT`, `PG_DATABASE`, `PG_USER`, `PG_PASSWORD`.
   - Configurar `PG_DATABASE=Base de Datos Historicos Talento Humano`.
   - Configurar `PG_SCHEMA=public`.
   - Alternativa: configurar `DATABASE_URL` de la base remota de Talento Humano.
   - Configurar `NOMINA_API_KEY`, `PYG_API_KEY`, `ADMIN_API_KEY`.
   - Mantener `APP_VERIFY_SSL=true`, `APP_DEBUG_ERRORS=false`.

6. Configurar scheduler en nube.
   - Dia 1 5:00 AM: `cierre_mes.py --empleados-activos-detalle`.
   - Dias 5 y 7 5:00 AM: `cierre_mes.py --solo-empleados-si-vacio`.
   - Dias 1, 5 y 7 5:30 AM: `cargar_historico_nomina_pyg.py --mes-anterior --fuente ambas`.
   - Base de instalacion preparada en `deploy/README-cloud.md`, `deploy/install-cloud-cron.sh` y `deploy/crontab-talento-humano.example`.
   - Verificado localmente con `deploy/install-cloud-cron.sh --dry-run` contra la base remota correcta.

7. Probar sin escribir.
   - `cierre_mes.py --test --empleados-activos-detalle`.
   - `cierre_mes.py --test --solo-empleados-si-vacio`.
   - `cargar_historico_nomina_pyg.py --mes-anterior --fuente ambas --dry-run`.

8. Prueba controlada de escritura.
   - Ejecutar sobre un periodo de prueba o tabla clon si existe.
   - Validar conteos, periodos y logs sin PII.

9. Cambiar dashboard a lectura de nube.
   - Arrancar `servidor.py` con usuario reader.
   - Verificar `/proxy/historico/max-periodo`.
   - Verificar tabs principales del dashboard.

10. Desactivar programacion local.
    - Solo despues de confirmar que nube escribe correctamente.
    - Mantener local como fallback manual documentado.

## Pendiente operativo principal — Opcion 1: servidor Faranda + cron

**Estado:** procedimiento completamente documentado; pendiente de asignar el
servidor/runner interno y ejecutar la instalacion.

La opcion recomendada es instalar el scheduler en un servidor Faranda que este siempre encendido y tenga acceso de red a PostgreSQL remoto `172.19.0.160:5432`. Esto evita abrir PostgreSQL a internet y elimina la dependencia de la Mac.

Documento maestro de instalacion:

```text
deploy/INSTALACION_JOB_SERVIDOR_API.md
```

La guia contiene los comandos y controles para:

- crear el usuario tecnico `rrhhjobs`;
- crear permisos minimos para `th_cierre_writer`;
- instalar el repositorio y el entorno virtual;
- configurar `.env` con permisos `600`;
- probar la API sin imprimir datos personales;
- ejecutar `--dry-run`;
- instalar el cron;
- verificar zona horaria;
- evitar ejecuciones simultaneas entre servidor y Mac;
- certificar PostgreSQL y el dashboard;
- actualizar, recuperar o retirar el job.

### Requisitos del servidor

- Linux o macOS con uptime permanente.
- Acceso de red a `172.19.0.160:5432`.
- Acceso a `https://git.faranda.online/faranda/rrhh-report.git`.
- `git`, `python3`, `pip` y `cron`.
- Permiso para crear un `.env` privado con permisos `600`.
- Permiso para instalar crontab del usuario de servicio.

### Variables/Secrets requeridos

Configurar en `.env` privado del servidor o como Secrets del runner:

```text
DATABASE_URL=postgresql://[USUARIO]:[PASSWORD]@172.19.0.160:5432/Base%20de%20Datos%20Historicos%20Talento%20Humano
PG_SCHEMA=public
NOMINA_API_KEY=...
PYG_API_KEY=...
APP_VERIFY_SSL=true
APP_DEBUG_ERRORS=false
```

No guardar estos valores en Git ni pegarlos en tickets/chats.

### Procedimiento de instalacion

```bash
git clone https://git.faranda.online/faranda/rrhh-report.git
cd rrhh-report
python3 -m pip install psycopg2-binary pandas openpyxl
chmod 600 .env
deploy/install-cloud-cron.sh --dry-run
deploy/install-cloud-cron.sh --install
```

### Programacion que instalara el cron

- Dia 1 5:00 AM: `cierre_mes.py --empleados-activos-detalle`.
- Dias 5 y 7 5:00 AM: `cierre_mes.py --solo-empleados-si-vacio`.
- Dias 1, 5 y 7 5:30 AM: `cargar_historico_nomina_pyg.py --mes-anterior --fuente ambas`.

### Criterios de certificacion

Antes de desactivar la Mac:

- `deploy/install-cloud-cron.sh --dry-run` debe terminar OK.
- `crontab -l` debe mostrar el bloque `BIA_TALENTO_HUMANO_CLOUD_CRON`.
- `/proxy/historico/max-periodo` debe seguir respondiendo desde la base remota correcta.
- Despues de la primera ejecucion real, validar:
  - `MAX(fecha)` en `historico_empleados`.
  - `MAX(periodo)` en `historico_ir`.
  - `MAX(periodo)` en `historico_nomina_pyg WHERE fuente='nomina'`.
- Revisar logs en `logs/cloud/` sin imprimir PII.

### Desactivacion local posterior

Solo despues de una ejecucion real exitosa en servidor:

- Desactivar LaunchAgents locales de `cierre_mes.py`.
- Desactivar LaunchAgents locales de `cargar_historico_nomina_pyg.py`.
- Mantener la Mac documentada como fallback manual, no como scheduler principal.

## Bloqueadores antes de escribir en remoto

- Crear usuarios dedicados reader/writer si el servidor permite gestion de roles.
- Confirmar si el scheduler final sera Git/Faranda runner, VPS, cron en servidor, VPN/Tailscale o runner dentro de red.
- Rotar `NOMINA_API_KEY` y `PYG_API_KEY` por haber existido en historial Git.
- Definir respaldo automatico de la base `Base de Datos Historicos Talento Humano`.

## Certificacion de datos migrados

| Tabla | Filas local | Filas remoto |
|---|---:|---:|
| `cargo_unificacion` | 572 | 572 |
| `ceco_unificacion` | 421 | 421 |
| `empresas` | 28 | 28 |
| `historico_empleados` | 41.958 | 41.958 |
| `historico_ir` | 5.149 | 5.149 |
| `historico_nomina_pyg` | 53.242 | 53.242 |
| `historico_nomina_pyg_control` | 1.170 | 1.170 |
| `hotel_unificacion` | 29 | 29 |
| `nomina_conceptos` | 494 | 494 |
| `socios` | 20 | 20 |

Hashes agregados principales:

- `historico_empleados`: `8030e83d5bf662051275549712312c12`
- `historico_ir`: `d38d085bc08f257ca1e2e3de43e928a3`
- `historico_nomina_pyg`: `58f4e4c09bfe0f07bf9e29fdf5340eda`

Pruebas contra remoto:

- `cierre_mes.py --test --solo-empleados-si-vacio`: OK, sin escritura.
- `cargar_historico_nomina_pyg.py --mes-anterior --fuente ambas --dry-run`: OK.
