--- name: registry_dashboard lang: cpp domain: tui description: "Dashboard ImGui para visualizar el estado del fn_registry. Consume datos via sqlite_api HTTP (fallback a SQLite directo). KPIs, charts, tablas, desglose por lenguaje/dominio/pureza." tags: [dashboard, imgui, visualization, registry, http] uses_functions: # viz - kpi_card_cpp_viz - bar_chart_cpp_viz - pie_chart_cpp_viz - table_view_cpp_viz - sparkline_cpp_viz # core (dashboard primitives) - dashboard_panel_cpp_core - dashboard_grid_cpp_core - fullscreen_window_cpp_core - page_header_cpp_core - badge_cpp_core - empty_state_cpp_core # core (UI primitives — projects/reindex/add modals) - button_cpp_core - icon_button_cpp_core - toolbar_cpp_core - modal_dialog_cpp_core - text_input_cpp_core - select_cpp_core - toast_cpp_core - tree_view_cpp_core # core (process orchestration — reindex) - process_runner_cpp_core - process_state_machine_cpp_core uses_types: [] framework: "imgui" entry_point: "main.cpp" dir_path: "projects/fn_monitoring/apps/registry_dashboard" repo_url: "https://gitea-dgg044oo04woo4ggcsws4gk0.organic-machine.com/dataforge/registry_dashboard" --- ## Arquitectura Dashboard C++ con dos modos de acceso a datos: 1. **HTTP API** (primario): Conecta a `sqlite_api` via HTTP para obtener datos de registry.db. No requiere acceso al filesystem. 2. **SQLite directo** (fallback): Lee registry.db directamente si la API no esta disponible. **Data layers:** - `data_http.cpp`: Carga datos via HTTP POST a sqlite_api (cpp-httplib + nlohmann/json) - `data.cpp`: Carga directa desde SQLite C API **Views** (`views.cpp`): Compone funciones del registry C++ para renderizar: - 8 KPI cards: functions, types, apps, analysis, unit tests, proposals, tested%, pure% - Bar charts: funciones por lenguaje, por dominio - Pie charts: pureza (pure/impure), kind (function/pipeline/component) - Tablas: ultimas 20 funciones, apps, analysis, tipos ## Build ```bash # Linux cd cpp && cmake -B build/linux -S . && cmake --build build/linux --target registry_dashboard -j$(nproc) # Windows (cross-compile) cd cpp && cmake -B build/windows -S . -DCMAKE_TOOLCHAIN_FILE=toolchains/mingw-w64.cmake && cmake --build build/windows --target registry_dashboard -j$(nproc) ``` ## Ejecucion ```bash # Via API (default, intenta conectar a localhost:8484) ./registry_dashboard # API explicita ./registry_dashboard --api http://192.168.1.10:8484 # Con SQLite fallback ./registry_dashboard --api http://127.0.0.1:8484 /path/to/registry.db # Solo SQLite (sin API) ./registry_dashboard /path/to/registry.db # Windows (PowerShell) .\registry_dashboard.ps1 ``` ## Dependencias vendored | Libreria | Version | Archivo | |----------|---------|---------| | cpp-httplib | v0.18.3 | vendor/httplib.h | | nlohmann/json | v3.11.3 | vendor/nlohmann/json.hpp | ## Roadmap - [ ] Filtros interactivos por lenguaje/dominio en sidebar - [ ] Busqueda FTS5 integrada via API - [ ] Detalles de funcion al hacer click en tabla - [ ] Extraer ws_client a `cpp/functions/network/` cuando un segundo app C++ necesite WS - [ ] SHA1 + Sec-WebSocket-Accept verification (hoy se confia en el handshake 101) - [ ] Migrar `nhooyr.io/websocket` → `github.com/coder/websocket` (mismo paquete, deprecation upstream) ## Notas - Por defecto intenta conectar a sqlite_api en `http://127.0.0.1:8484`. Si falla, usa SQLite directo. - SQLite compilado estaticamente en Windows via amalgamation vendoreada. En Linux usa libsqlite3 del sistema. - cpp-httplib usa sockets nativos (no OpenSSL) — solo HTTP, no HTTPS. ## Estado actual ### Fase — actions bar + projects tab + Add modal `[done 2026-04-25]` Cambios estructurales (requieren `sqlite_api` v0.2 con endpoints de mutacion): - **Actions bar** en el page header (`fn_ui::toolbar`): `Reindex` (Primary) → `http_post_reindex` via `process_runner`; `+ Add` (Secondary) → abre modal; `Reload` (Subtle) → re-fetch via `UserData` flag; `toast_inbox_button` con badge. - **Modal Add** (`modal_dialog`): `select` para Kind (App/Analysis/Vault), `select` de proyecto (obligatorio para Vault), `text_input` Name + Description + campos especificos. `process_runner` para el POST. Toast de exito/error + reload al completar. - **Tab Projects** (`tree_view` + tabs): columna izquierda con proyectos + entrada "(orphans)"; columna derecha con detalle nested (Apps/Analysis/Vaults). Click dispara `load_project_detail_http`. `RegistryData` gana `projects[]`, `orphan_apps`, `orphan_analyses`, `orphan_vaults`. Tipos nuevos `ProjectRow`, `VaultRow`, `ProjectDetail`. Layer `data_http.cpp` gana `load_projects_http`, `load_project_detail_http`, `http_post_{reindex,add_app,add_analysis,add_vault}`. `AnalysisRow` gana campo `lang` para coherencia con la tabla `analysis` (la query SQL pasa de `SELECT id,name,domain,description` a `SELECT id,name,lang,domain,description`). `views_set_api_url(url)` invocado desde `main.cpp` para que las vistas puedan disparar mutaciones. ### Bug fixes operativos `[done 2026-04-25]` - **Vibracion al redimensionar**: `fullscreen_window` v0.2 (NoScrollbar), altura de charts fija 260 px, `kpi_card` v1.2 (78 px + scale 1.4 + NoScrollbar). Ver `project.md` para detalle. - **HTTP POST timeout 5 ms en Windows**: `http_client.cpp::request()` usaba `struct timeval` en `setsockopt(SO_RCVTIMEO)`, que Windows interpreta como `DWORD` ms → 5 ms efectivos. Fix: rama `_WIN32` con `DWORD timeout_ms = timeout_sec * 1000`. `wsa_init` envuelto en `std::call_once`. - **Mensajes de toast vacios**: `post_json` ahora siempre escribe en `out_body` (extrae `output` del JSON en exito; sintetiza `"connect() failed to host:port (err=N)"` con codigo Winsock en error de conexion). Em dash sustituido por ASCII `:` para evitar render como `?` en fuentes sin ese codepoint. - **Inbox popup en otra pantalla**: `toast_inbox_button` antes usaba posicion calculada con `btn_pos.x - 332` que podia caer fuera del `WorkRect` del viewport principal; con `viewports = true` ImGui lo movia a otra ventana del OS. Fix: clamp al `WorkRect`, anclar con `ImGuiCond_Appearing` (no `Always`), `SetNextWindowViewport(vp->ID)`. ### Toolchain MinGW para Windows `[importante]` El cross-compile pasa de thread model `win32` a `posix` (`x86_64-w64-mingw32-g++-posix`) para que `std::mutex`/`std::thread` funcionen — necesario para `process_runner` y `toast`. Linker: `-static-libgcc -static-libstdc++ -static -lwinpthread`. Configurado en `cpp/toolchains/mingw-w64.cmake`. ### Lo siguiente que pega - Filtros del Roadmap: el `select` de proyecto del modal Add ya prueba que filtrar por proyecto es trivial; aplicar mismo patron a las tablas Apps/Analysis/Types. - Detalles al click: cuando un row de la tabla Apps (o Functions) se selecciona, abrir un panel lateral con metadata + boton "Open in editor" (segun OS, `xdg-open`/`explorer`). - Integracion FTS5: el endpoint `/api/databases/registry/fts` ya existe; falta cablearlo desde la actions bar como `text_input` con resultados live. ## Notas — Settings menubar (sesion 2026-04-25) - `render()` ahora llama `fn_ui::app_menubar(nullptr, 0, nullptr)` al inicio para exponer el item `Settings...` en la MainMenuBar. La app no tiene paneles toggleables ni layouts propios, asi que solo aparece Settings. - El usuario puede cambiar fuente (DroidSans/Karla/Roboto/Cousine) y tamaño (10..32 px) en runtime, y togglear el FPS overlay. Persistencia en `app_settings.ini` junto al `registry_dashboard.exe`. - `CMakeLists.txt` limpiado: `fps_overlay.cpp` y `tokens.cpp` ya viven en `fn_framework` — no listarlos explicitamente o el linker da multiple-definition. - 5 TTFs (Karla/Roboto/DroidSans/Cousine/Tabler) copiadas junto al exe via `add_imgui_app` post-build. ## Fase — Monitor tab + WebSocket live stream `[done 2026-05-14, issue 0086]` Rebranding "Claude Usage" → **Monitor**, ahora primera y por defecto en el TabBar. Es el landing del bucke reactivo (construir → ejecutar → recopilar → analizar → mejorar). Nuevos elementos UI: - **Toolbar interna** del Monitor con preset de ventana temporal (1h / 24h / 7d / 30d / All), boton Refresh manual, LED `live`/`offline` con timestamp del ultimo evento WS. - **5 KPI cards** (era 4): añadido "Errors" derivado de `COUNT(*) FROM calls WHERE success = 0` filtrado por la ventana activa. - **Sub-tab "Recent Executions"** (la primera) con columnas: When, Function, Tool, ms, OK, Error. Backed by `calls` table, sorted by ts DESC, limit 100, filtrada por ventana. - Violations sub-tab gana columna "When" con ts formateado. Pipeline en vivo (low-latency, push-based): ``` Hook PostToolUse ──► call_monitor CLI ──► INSERT calls (siempre, sincrono) │ ▼ ops:call_monitor.db ▲ │ (ticker 250ms cuando subs>0) sqlite_api /api/events/call_monitor ──► WS hub ──► subscribers (dashboards) ``` - **sqlite_api**: nuevo endpoint `GET /api/events/call_monitor`. Hub gestiona subscribers, ticker arranca solo con >=1 sub (cero overhead si no hay dashboards). Cliente recibe snapshot inicial (KPIs + 100 ultimas) y luego deltas (`id > watermark`). Intervalo adaptativo: 250ms activo → 2s idle (tras 30s sin eventos). - **registry_dashboard**: cliente WS minimal RFC6455 en `ws_client.{h,cpp}` (no TLS, thread propio, reconnect exponencial 0.5s → 8s). `main.cpp` consume deltas y los aplica a `g_data.claude` (incrementa KPIs, anade filas, dedup por id). - **Fallback**: si WS cae, los datos siguen registrandose en SQLite via call_monitor CLI. Al reconectar, el cliente puede mandar `{"watermark": N}` para reanudar sin perder eventos. Cambios en `data.{h,cpp}` y `data_http.{h,cpp}`: - `RecentExecutionRow`, `window_secs`, `ws_connected`, `last_event_ts`, `last_seen_call_id` en `ClaudeUsageData`. - `load_claude_usage_http(api, out, window_secs)` filtra `calls` y `violations` por ventana. - `load_recent_executions_http()` standalone para refetch parcial (preparado para WS, no esta cableado todavia — actualmente las deltas WS bastan). Decisiones de scope: - Sec-WebSocket-Accept verification se omite (server controlado, localhost only). - TLS fuera (ws://, no wss://). - WS client no extraido al registry todavia: hasta que un segundo app C++ lo necesite. ## Notas — Settings submenu + Git column (sesion 2026-04-28) - `fn_ui::app_menubar` reemplaza el item plano `Settings...` por un `BeginMenu("Settings")` con dos subitems: `Settings...` (existente) y `About...` (nuevo modulo `app_about_cpp_core`). El registry_dashboard cablea la info via `fn_ui::about_window_set_info("fn_registry Dashboard", "0.2.0", "Dashboard ImGui...")` antes de `fn::run_app`. - Tabla `Apps` gana columna **Git**: `remote` si `repo_url` esta poblado en `apps.repo_url`, `local` si existe `/.git/`, `-` si nada. `AppRow` extendido con `repo_url` y `dir_path`; SELECT en `data.cpp` y `data_http.cpp` ampliado a 8 columnas. - Build OK: `cmake --build build --target registry_dashboard` (Linux). La columna "Git" se ve sin reindexar.