--- 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-`), 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).