EtlController es el puente HTTP entre Sevastopol y los loaders Python de Nostromo. Su única responsabilidad es disparar procesos Python desde Express con child_process.spawn, validar prerrequisitos antes del arranque y mantener el estado de las corridas en memoria.
No persiste resultados — el estado completo de una corrida vive en un Map<number, EtlExecutionStatus> indexado por PID, con LRU de 100 entradas. La trazabilidad persistente vive en los logs stdout/stderr que cada loader emite.
Nostromo es un módulo Python independiente; importar Python en Node implicaría empaquetar el venv. La frontera CLI mantiene la separación de tecnologías.
Registry in-memory con LRU 100
El estado de una corrida es efímero — el cliente la polea hasta completed/failed y la olvida. Persistir el registry no aporta valor (los logs ya están en stdout).
Watchdog ETL_TIMEOUT_MS=15min
Procesos colgados (sesión SII, scraping) deben morir solos. El timeout es configurable por env.
Validación de UTM antes del spawn
impuesto_2cat_loader falla si no hay UTM del mes en parametros.indicadores. El controller hace getIndicador(YYYY-MM-01, "UTM") antes de gastar un fork. Devuelve 409 con accionRecomendada si falta.
errorTail con clasificación de patrones
FUNCTIONAL_ERROR_PATTERNS (no encontró, no disponible, falló) prevalece sobre SECONDARY_LOGGING_PATTERNS (SSL, MongoDB). El tail prioriza el error funcional; el diagnóstico secundario va en “Secondary diagnostics”.
tailText(value, 1200)
Solo los últimos ~1200 chars del log se devuelven al cliente. Suficiente para diagnóstico; evita pasar megabytes por red.
resolvePythonExecutable con venv detection
Prefiere .venv/Scripts/python.exe (dev) y cae a python del PATH (prod). El path absoluto a Nostromo es c:\dev\Nostromo — MVP documentado.
authenticateToken middleware
Solo usuarios autenticados disparan ETL. La UI valida adicionalmente que el rol sea SUPER_ADMIN.
Sin streaming de stdout
La UI espera el endedAt para mostrar el errorTail. Streaming agregaría complejidad (SSE/WebSocket) sin caso de uso claro.