Files
fn_monitoring/project.md
T
2026-06-05 17:29:42 +02:00

15 KiB

name, description, tags, repo_url
name description tags repo_url
fn_monitoring Monitoreo y visualizacion del estado del fn_registry. API HTTP read-only sobre las bases de datos SQLite y dashboard ImGui que consume la API.
monitoring
api
dashboard
sqlite
visualization
https://gitea-dgg044oo04woo4ggcsws4gk0.organic-machine.com/dataforge/fn_monitoring

Apps

App Lang Descripcion
sqlite_api Go API REST HTTP read-only sobre registry.db y todas las operations.db. Puerto 8484.
registry_dashboard C++ / ImGui Dashboard con KPIs, charts y tablas del registry. Consume sqlite_api (HTTP) con fallback a SQLite directo.

Cada app.md es la referencia canonica del binario — endpoints completos, flags, dependencias. Este documento cubre como operar el proyecto como un todo: arranque, service, flujo de datos, troubleshooting.


Arquitectura

                          registry.db  (raiz)
                          apps/*/operations.db
                          projects/*/apps/*/operations.db
                                 │  (read-only, mode=ro)
                                 ▼
          ┌──────────────────────────────────────────────┐
          │  sqlite_api  (Go net/http, :8484)            │
          │    /health                                   │
          │    /api/databases                            │
          │    /api/databases/:db/tables                 │
          │    /api/databases/:db/schema                 │
          │    /api/databases/:db/query   (POST, SELECT) │
          │    /api/databases/:db/fts                    │
          └──────────────────────────────────────────────┘
                                 ▲
                                 │  HTTP GET/POST
                                 │  (cpp-httplib + nlohmann/json)
                                 │
          ┌──────────────────────────────────────────────┐
          │  registry_dashboard  (C++ / ImGui + ImPlot)  │
          │    main.cpp  → reload_data()                 │
          │    data_http.cpp  (primario, HTTP)           │
          │    data.cpp       (fallback, SQLite C API)   │
          │    views.cpp  → KPI row, charts, tables      │
          └──────────────────────────────────────────────┘

Separacion de responsabilidades:

  • sqlite_api no conoce el dashboard. Es una API generica: expone cualquier DB SQLite de fn_registry/ read-only con FTS5.
  • registry_dashboard no conoce la estructura de registry.db directamente, solo a traves del JSON que devuelve la API. El modo SQLite directo es fallback para entornos sin red.

Puerto 8484 — elegido para no colisionar con Metabase (3000), Jupyter (8888) ni deploy_server (9090).


Servicio sqlite_api

Modos de arranque

Modo Comando Cuando usarlo
Dev (foreground, go run) cd projects/fn_monitoring/apps/sqlite_api && go run -tags fts5 . Iteracion rapida, ver logs en la terminal
Dev (background) ./start.sh (dentro de apps/sqlite_api/) Probar el dashboard rapido sin systemd. Escribe PID en sqlite_api.pid y log en sqlite_api.log
Production (systemd) sudo systemctl start sqlite_api Arranque en boot, restart on failure, logs en journal

Variables de entorno

Var Valor Proposito
FN_REGISTRY_ROOT ruta absoluta a la raiz del registry Evita que el binario busque registry.db subiendo por el cwd. Obligatoria bajo systemd.

Instalar como servicio systemd (local)

Usar el pipeline del registry install_systemd_service_bash_pipelines:

cd /home/lucas/fn_registry

# 1. Build del binario
CGO_ENABLED=1 go build -tags fts5 \
  -o projects/fn_monitoring/apps/sqlite_api/sqlite_api \
  ./projects/fn_monitoring/apps/sqlite_api/

# 2. Instalar unit + enable + start (requiere sudo sin password para systemctl)
source bash/functions/pipelines/install_systemd_service.sh
install_systemd_service \
  --name sqlite_api \
  --exec "$(pwd)/projects/fn_monitoring/apps/sqlite_api/sqlite_api" \
  --workdir "$(pwd)" \
  --env "FN_REGISTRY_ROOT=$(pwd)" \
  --description "fn_registry SQLite HTTP API" \
  --after network.target \
  --restart on-failure

Operacion

sudo systemctl status  sqlite_api     # estado + ultimas lineas del journal
sudo systemctl restart sqlite_api     # tras rebuild del binario
sudo systemctl stop    sqlite_api     # parar
journalctl -u sqlite_api -f           # logs en vivo
curl http://127.0.0.1:8484/health     # health check

Redeploy tras cambios en el codigo Go

cd /home/lucas/fn_registry
CGO_ENABLED=1 go build -tags fts5 \
  -o projects/fn_monitoring/apps/sqlite_api/sqlite_api \
  ./projects/fn_monitoring/apps/sqlite_api/
sudo systemctl restart sqlite_api

No hace falta reinstalar el unit — solo recompilar y reiniciar.


Dashboard registry_dashboard

Build

cd cpp
cmake -B build/linux -S .
cmake --build build/linux --target registry_dashboard -j$(nproc)

El binario queda en cpp/build/linux/registry_dashboard (o projects/fn_monitoring/apps/registry_dashboard/registry_dashboard.exe en Windows).

Ejecucion

# Modo API (por defecto, intenta localhost:8484)
./registry_dashboard

# API remoto
./registry_dashboard --api http://192.168.1.10:8484

# API + fallback SQLite
./registry_dashboard --api http://127.0.0.1:8484 /home/lucas/fn_registry/registry.db

# Solo SQLite (sin API)
./registry_dashboard /home/lucas/fn_registry/registry.db

La UI muestra en la cabecera de donde vienen los datos (HTTP vs SQLite). F5 recarga.

Flujo de datos

  1. main.cpp::reload_data() intenta HTTP primero via load_registry_data_http().
  2. Si la API responde 200 y el JSON parsea, los datos pueblan RegistryData.
  3. Si falla la API (timeout, 5xx, JSON invalido) y hay --db, cae a load_registry_data() (SQLite directo).
  4. Si ninguno funciona, la UI muestra un mensaje de error y no hay reintento automatico — hay que pulsar reload.

Vistas

Seccion Datos Query subyacente
KPI row (8 cards) totales y porcentajes SELECT COUNT(*) sobre functions, types, apps, analysis, unit_tests, proposals + agregados tested/pure
Charts (bar + pie) funciones por lang/domain, reparto pure/impure, kind GROUP BY lang, GROUP BY domain, GROUP BY purity, GROUP BY kind
Tablas ultimas 20 functions, apps, analysis, types ORDER BY updated_at DESC LIMIT 20

Detalle de composicion de componentes viz en apps/registry_dashboard/app.md.


Troubleshooting

Sintoma Causa probable Verificacion / Fix
Dashboard dice "HTTP API failed, falling back to SQLite" sqlite_api no esta corriendo curl http://127.0.0.1:8484/health — si falla, systemctl status sqlite_api o ./start.sh
sqlite_api arranca y muere inmediatamente No encuentra registry.db Exportar FN_REGISTRY_ROOT=/home/lucas/fn_registry o correr desde la raiz del registry
systemctl start sqlite_api pide password Falta sudoers para systemctl Ver .claude/rules/deploy.md — el usuario necesita NOPASSWD para systemctl, mv a /etc/systemd/system/
Dashboard abre pero todas las cifras son 0 API conecta pero devuelve DB vacia curl -X POST http://127.0.0.1:8484/api/databases/registry/query -d '{"sql":"SELECT COUNT(*) FROM functions"}'
API responde lento / timeout Query pesada sobre FTS5 Timeout hardcoded a 5s en handlers.go. Revisar la query en journal.
Bind rechazado (address already in use) Otro proceso en 8484 `ss -tlnp

Logs

# systemd
journalctl -u sqlite_api -n 100 --no-pager
journalctl -u sqlite_api -f

# start.sh
tail -f projects/fn_monitoring/apps/sqlite_api/sqlite_api.log

Como extender

Anadir un endpoint a sqlite_api

  1. Registrar la ruta en Server.Routes() (handlers.go).
  2. Handler lee r.URL.Path / r.Body, delega en DBPool para resolver la DB, ejecuta SQL read-only.
  3. Test en handlers_test.go (patron: tabla de casos HTTP).
  4. Rebuild + systemctl restart sqlite_api.
  5. Documentar en apps/sqlite_api/app.md (tabla de endpoints).

Anadir una vista al dashboard

  1. Nuevo campo en RegistryData (data.h) + su equivalente en la respuesta JSON.
  2. Parseo en data_http.cpp y carga SQL en data.cpp (ambos paths, para mantener el fallback).
  3. Renderizado en views.cpp usando componentes del dominio viz (kpi_card, bar_chart, etc.) — ver regla frontend_theming analoga para C++: usar primitivos del registry antes que ImGui crudo.
  4. Rebuild con CMake.

Anadir una DB nueva

La descubre automaticamente DiscoverDatabases() escaneando apps/*/operations.db y projects/*/apps/*/operations.db. No hay que registrar nada — al reiniciar sqlite_api aparecen con alias ops:{app_name}.


Deploy en otros PCs

Este proyecto se instala identico en cualquier maquina con el registry clonado:

  1. fn sync para traer los metadatos del proyecto.
  2. Build + systemd install (seccion "Instalar como servicio systemd" arriba).
  3. Build del dashboard.

Los datos son los .db locales — cada PC ve su propio estado del registry y sus propias operations.db. No hay sincronizacion remota de datos en este servicio: para eso existe fn sync contra registry_api (proyecto diferente, ver memoria project_registry_api).


Estado actual

Fase — projects view + mutaciones desde el dashboard [done 2026-04-25]

El dashboard pasa de read-only a manipular el registry via la API. Ampliacion en tres patas:

Backend (sqlite_api) — endpoints nuevos en handlers_projects.go y handlers_mutations.go:

Metodo Path Que hace
GET /api/projects Lista con conteos apps_count / analyses_count / vaults_count por proyecto + bloque orphans (entidades con project_id vacio).
GET /api/projects/{id} Detalle: apps[], analyses[], vaults[]. Acepta id="orphans" para devolver las huerfanas.
POST /api/reindex Ejecuta fn index desde registryRoot, devuelve {ok, output}.
POST /api/add/app Body {name, lang, domain, project, description} → crea apps/{name}/ o projects/{p}/apps/{name}/ con app.md minimo + fn index.
POST /api/add/analysis Body {name, project, packages[], description} → invoca fn run init_jupyter_analysis [--project p] name pkg1 pkg2 ....
POST /api/add/vault Body {name, project, path, description} → crea dir o symlink en projects/{p}/vaults/ + entry append en vault.yaml.

Server.registryRoot se inyecta en NewServer(pool, root) (rebajado de findRegistryRoot() en main.go). Helpers runFN() y runShell() ejecutan con cmd.Dir = registryRoot y FN_REGISTRY_ROOT en el env.

Dashboard (registry_dashboard) — actions bar + tab Projects + modal Add:

  • Toolbar nueva en el header (fn_ui::toolbar): boton Reindex (Primary) → dispara http_post_reindex via process_runner; boton + Add → abre modal_dialog; boton Reload; toast_inbox_button con badge.
  • Modal Add con select para kind (App / Analysis / Vault), select de proyecto (obligatorio para Vault, opcional para resto), text_input Name + Description y campos especificos por kind (lang/domain para App, packages CSV para Analysis, abs path para Vault). Submit dispara el endpoint correspondiente via process_runner. Toast al completar + reload automatico.
  • Tab Projects con dos columnas: tree_view izquierda (proyectos + entrada "(orphans)" cuando hay entidades huerfanas), detalle derecha con tabs internas Apps / Analysis / Vaults. Click en un proyecto dispara load_project_detail_http.

Datos en RegistryData: nuevos projects[], orphan_apps, orphan_analyses, orphan_vaults. Tipos nuevos ProjectRow, VaultRow, ProjectDetail. load_registry_data_http llama a load_projects_http al final como best-effort (no fatal si falla).

Bug fix — vibracion al redimensionar [done 2026-04-25]

Dos fuentes de "vibracion" durante drag-resize de la ventana:

  • fullscreen_window_cpp_core v0.2: anadido NoScrollbar | NoScrollWithMouse. Sin esto, si el contenido excedia por 1-2px aparecia un scrollbar fugaz que reducia el ancho ~14px y reflowaba todo.
  • views.cpp::draw_dashboard: altura de charts pasa de GetContentRegionAvail().y * 0.35 a constante 260 px. La proporcion relativa propagaba el resize a todos los plots.
  • kpi_card_cpp_viz v1.2: altura fija 78 px (antes 108) + scale 1.4x (antes 1.8) + padding sm + NoScrollbar. El AutoResizeY con 8 cards generaba lag perceptible al redimensionar.

Bug fix — HTTP POST timeout en thread de background [done 2026-04-25]

http_client.cpp::request() pasaba struct timeval a setsockopt(SO_RCVTIMEO) en Windows, donde MSDN especifica DWORD ms. Resultado: timeout efectivo de 5 ms en lugar de 5 s. Se nota especialmente en POST desde threads (background runners) porque la latencia de scheduling puede pasar de 5 ms. Fix: rama _WIN32 con DWORD timeout_ms. Tambien wsa_init envuelto en std::call_once para evitar race entre main thread + runners. Mensajes de error formateados con ASCII (em dash U+2014 falla render con la fuente default).

Nueva app dev en cpp/apps/primitives_gallery/ (no es app del registry, vive en el source tree). Catalogo visual interactivo de los 19 primitivos UI de cpp/functions/{core,viz} con sidebar + panel + snippet por demo. Doble rol: smoke test visual al modificar tokens/componentes y build gate (esta en el CMake principal — si un primitivo rompe API la gallery no compila).

Demo destacada: graph_viewport con sliders de Nodes (100-20 000), Clusters (2-16) y los tres parametros de ForceLayoutConfig (Repulsion / Attraction / Gravity) aplicados en vivo. Util tambien como benchmark de rendimiento del stack graph_renderer + graph_force_layout + graph_spatial_hash.

README.md propio en cpp/apps/primitives_gallery/README.md.

Lo siguiente que pega

  • Tests unitarios de logica pura (Phase A del plan de tests): vendoreado de doctest, ~6 tests para label_stride, slice_at, process_runner transitions, toast queue, tokens sanity, parse_url. Cierra el ciclo gallery (visual) + ctest (logica).
  • Para que algunos tests sean posibles hace falta exponer funciones internas de bar_chart.cpp y pie_chart.cpp (actualmente en namespace anonimo).
  • loginctl enable-linger lucas para que el sqlite_api.service (user-level systemd) sobreviva al logout. Requiere sudo una vez. Decision pendiente del usuario.