---
id: "0095"
title: "Frontend C++ ImGui para `dag_engine`"
status: pendiente
type: feature
domain:
  - cpp-stack
  - frontend
scope: multi-app
priority: alta
depends: []
blocks: []
related: []
created: 2026-05-17
updated: 2026-05-17
tags: []
---
# 0095 — Frontend C++ ImGui para `dag_engine`

**Status:** pendiente
**Created:** 2026-05-15
**Type:** app
**Blocks:** 0096 (data_factory) — necesita frontend C++ unificado para scheduler
**Related:** `apps/dag_engine` (Go + Vite/React actual), `projects/fn_monitoring/apps/registry_dashboard` (referencia pubsub)

## Problema

`dag_engine` (alternativa propia a Dagu, ya existente) hoy sirve dos modos:
- CLI (`run/list/status/validate/server`).
- Web (Vite + React + Mantine en `apps/dag_engine/frontend/`).

El resto del ecosistema de monitorizacion del registry esta en C++ ImGui (`registry_dashboard`, `call_monitor`, futuro `data_factory`). Forzar al usuario a saltar al navegador para gestionar/observar DAGs rompe el flujo. Ademas la app `data_factory` (issue 0096) necesita embeber vista de scheduler para mostrar que DAG dispara cada extractor — si esa vista es web, no encaja en su UI ImGui.

## Objetivo

Anadir app C++ ImGui `dag_engine_ui` que cubre el caso "ver/lanzar/inspeccionar DAGs" con el **mismo backend** (`dag_engine server` HTTP+WS) y reusa el patron pubsub de `registry_dashboard` (HTTP REST + WebSocket live updates).

NO sustituye el frontend web — convive. El web sigue util para acceso remoto al VPS; el C++ es para uso local en escritorio.

## Piezas

### Backend (apps/dag_engine, cambios minimos)

1. **WS hub `DagRunHub`** en `apps/dag_engine/events.go` siguiendo el patron de `CallMonitorHub` (sqlite_api/events.go):
   - Hub global con N subscribers WS.
   - Ticker arranca solo con >=1 subscriber.
   - Polling watermark a tabla `dag_runs` + `dag_step_results` cada 500ms.
   - Snapshot inicial al conectar (lista DAGs + ultimos runs).
   - Broadcast de eventos: `run_started`, `step_completed`, `run_finished`, `schedule_updated`.
2. **Endpoint** `GET /api/ws/dagruns` (upgrade WebSocket).
3. **Endpoint** `POST /api/dags/:name/run` (Run Now) — ya existe; verificar que devuelve `run_id` inmediato y el hub broadcastea el progreso.
4. **CORS** ya abierto en `middleware.go`.

### App C++ ImGui (`apps/dag_engine_ui/`)

Scaffolding via `fn run init_cpp_app dag_engine_ui --desc "Frontend ImGui para dag_engine"`.

1. **Capa HTTP**: `data_http.{cpp,h}` clona patron de `registry_dashboard/data_http.{cpp,h}` (cpp-httplib + nlohmann/json). Endpoints:
   - `GET /api/dags` -> lista DAGs.
   - `GET /api/dags/:name` -> detalle.
   - `GET /api/dags/:name/runs` -> historial.
   - `GET /api/runs/:id` -> timeline pasos.
   - `POST /api/dags/:name/run` -> dispara.
   - `POST /api/dags/:name/validate` -> valida YAML.
2. **Capa WS**: `ws_client.{cpp,h}` reusado tal cual de `registry_dashboard`. Conecta a `ws://127.0.0.1:8090/api/ws/dagruns`.
3. **Tabs** (panels via `cfg.panels`):
   - **DAG List** — tabla: name, schedule (cron), last_status, last_run_at, next_run_at, tags. Reusa `table_view_cpp_viz`. Click fila -> DAG Detail.
   - **DAG Detail** — header + metadata + boton "Run Now" + historial ultimos N runs (`table_view_cpp_viz`). Reusa `page_header_cpp_core`, `button_cpp_core`, `badge_cpp_core`.
   - **Run Detail** — timeline de steps con stdout/stderr expandible. Reusa `tree_view_cpp_core` y un componente nuevo `timeline_cpp_viz` si no existe (delegar a fn-constructor).
   - **Schedule** — vista cron: para cada DAG con `schedule:` lo siguiente que va a disparar (`next_cron_time_go_core`). Mini-calendario opcional.
   - **Health** — kpis: runs_24h, success_rate, p95_duration, failed_runs. Reusa `kpi_card_cpp_viz`.
4. **Live updates**: WS recibe eventos -> push a ringbuffer en memoria -> tabs leen del ringbuffer en cada `render`. Run en curso se anima (spinner en columna status).
5. **Config**: `--api-url http://127.0.0.1:8090` (default localhost). Persistencia en `app_settings.ini` (gestionado por `app_settings_cpp_core`).

### Frontmatter `app.md`

```yaml
---
name: dag_engine_ui
lang: cpp
domain: tui
description: "Frontend ImGui para dag_engine. Lista, lanza e inspecciona DAGs con live updates via WS. Equivalente local al frontend web."
tags: [imgui, dashboard, dag, scheduler, http, websocket]
uses_functions:
  - kpi_card_cpp_viz
  - bar_chart_cpp_viz
  - table_view_cpp_viz
  - dashboard_panel_cpp_core
  - dashboard_grid_cpp_core
  - page_header_cpp_core
  - badge_cpp_core
  - button_cpp_core
  - icon_button_cpp_core
  - toolbar_cpp_core
  - text_input_cpp_core
  - select_cpp_core
  - tree_view_cpp_core
  - empty_state_cpp_core
  - modal_dialog_cpp_core
  - toast_cpp_core
uses_types: []
framework: "imgui"
entry_point: "main.cpp"
dir_path: "apps/dag_engine_ui"
repo_url: "https://gitea-dgg044oo04woo4ggcsws4gk0.organic-machine.com/dataforge/dag_engine_ui"
---
```

Tag de grupo: anadir `scheduler` (grupo nuevo si >=3 funciones lo respaldan; revisar antes — si no, dejar plano).

### Funciones nuevas a delegar (estimacion)

- `timeline_cpp_viz` — componente ImGui que pinta pasos de un run con duracion + status + expand stdout/stderr. Reusable por `data_factory` v2.
- `cron_explain_go_core` (puro) — dado `"0 */15 * * *"` devuelve string humano "every 15 min". Usado en DAG List.
- `http_poll_json_cpp_core` (impuro) — wrapper sobre cpp-httplib que hace GET periodico con backoff y publica deltas via callback. Reusable.

Si patrones se repiten en `registry_dashboard` (cabecera HTTP+WS hibrido) -> proposal de extraer un mini-cliente comun `cpp/functions/core/http_ws_client.{cpp,h}`. NO crear inline.

## Aceptacion

- `fn run init_cpp_app dag_engine_ui` ejecutado, scaffolding limpio.
- `dag_engine server` expone `/api/ws/dagruns` (hub con register/unregister/snapshot/delta).
- App C++ compila en Linux y Windows (`build_cpp_windows_bash_infra dag_engine_ui`).
- Smoke: con `dag_engine server` corriendo y un DAG ejemplo, abrir app -> ve DAG en lista, click "Run Now" -> timeline aparece en vivo sin refresh.
- `e2e_checks` en `app.md`:
  - `build_cmake` — `cmake --build cpp/build -j --target dag_engine_ui`.
  - `self_test` — `./dag_engine_ui --self-test` arranca, valida conexion HTTP a `dag_engine`, sale 0/1.
  - `pytest` opcional — script que arranca `dag_engine server` con DAG dummy, lanza UI headless (xvfb), spera evento WS, sale 0/1.
- `fn doctor cpp-apps` no reporta drift sobre `dag_engine_ui`.
- `uses_functions` declarado en `app.md` y los `.cpp` del registry listados en `CMakeLists.txt` coinciden (`fn doctor uses-functions`).

## No-objetivos

- Editar YAML de DAGs desde la UI (v2 — por ahora solo lectura + Run Now + Validate).
- Generar nuevos DAGs visualmente tipo drag&drop (v2).
- Sustituir el frontend web — convive.
- Soporte multi-engine (varios `dag_engine` remotos). Asume 1 backend local.

## Riesgos

| Riesgo | Mitigacion |
|---|---|
| WS hub anade peso al binario `dag_engine` | Mismo patron que `sqlite_api` (~150 LOC); negligible. |
| `cpp-httplib` no soporta WS upgrade limpio | `registry_dashboard/ws_client.cpp` ya implementa RFC 6455 manual sobre TCP. Reusar tal cual. |
| Doble UI (web + C++) -> deriva | Un solo backend, mismos endpoints. Si web cambia, C++ se entera por contrato HTTP. |
| Cron parser duplica logica si se anade `cron_explain` | Funcion pura nueva, atomica, justificada (UX). |

## Dependencias

- `apps/dag_engine` corriendo y aceptando conexiones.
- `cpp/functions/viz/*` y `cpp/functions/core/*` ya existentes (ver `uses_functions`).
- `cpp-httplib` y `nlohmann/json` vendored (igual que `registry_dashboard`).

## Plan de ejecucion (sub-tareas)

1. **Backend**: anadir `events.go` con `DagRunHub` + handler WS en `dag_engine`. Commit.
2. **Scaffolding**: `fn run init_cpp_app dag_engine_ui`. Commit.
3. **Capa HTTP**: copiar y adaptar `data_http.{cpp,h}` desde `registry_dashboard`. Endpoints DAG. Commit.
4. **Capa WS**: copiar `ws_client.{cpp,h}` tal cual. Conectar a `/api/ws/dagruns`. Commit.
5. **Tabs DAG List + Detail + Run Detail**. Commit por tab.
6. **Schedule + Health tabs**. Commit.
7. **Funciones nuevas** (`timeline_cpp_viz`, `cron_explain_go_core`, `http_poll_json_cpp_core`) — delegar a fn-constructor en paralelo en mismo turno. Commit por funcion.
8. **e2e_checks + redeploy_cpp_app_windows**. Commit final.

Cada paso: rama TBD propia (`issue/0095-<slug>`), merge `--no-ff` a master.

## Telemetria objetivo

Tras este issue:
- `dag_engine_ui` aparece en `function_stats` con `calls > 0` (lanzamientos via `is_cpp_app_running_windows_bash_infra`).
- `cron_explain_go_core` con `consumer_apps_count >= 1`.
- `timeline_cpp_viz` con consumidor declarado en `uses_functions` de `dag_engine_ui` + candidato a reuso en `data_factory` (issue 0096).
