fad4006f60
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
11 KiB
11 KiB
id, title, status, type, domain, scope, priority, depends, blocks, related, created, updated, tags
| id | title | status | type | domain | scope | priority | depends | blocks | related | created | updated | tags |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0049k | App `graph_explorer` (proyecto `osint_graph`) | completado | feature | app-scoped | alta | 2026-05-17 | 2026-05-17 |
0049k — App graph_explorer (proyecto osint_graph)
Metadata
| Campo | Valor |
|---|---|
| ID | 0049k |
| Estado | pendiente |
| Prioridad | alta |
| Tipo | feature — parte de #0049 — integracion final + activacion del feature flag |
Dependencias
Bloqueada por:
- 0049a — proyecto + sub-repo
- 0049f — renderer completo
- 0049g — source operations.db
- 0049h — layout GPU
- 0049i — layouts estaticos + viewport
- 0049j — labels
Desbloquea: activacion del feature flag osint_graph_v1.
Objetivo
Construir la app C++ graph_explorer en projects/osint_graph/apps/graph_explorer/, agnostica del backend, capaz de abrir cualquier operations.db del registry y visualizarlo con shapes/iconos/layouts/filtros/labels. Cumplir la regla cpp_apps.md y apps_tbd.md.
Contexto
Toda la libreria de visualizacion ya existe en cpp/functions/viz/ tras 0049b–j. Esta app es el consumer final que orquesta:
graph_load_from_operationspara cargar datos.types_registry(modulo local) para mergeartypes.yamlopcional con tipos descubiertos.graph_force_layout_gpu(o CPU) corriendo segun toggle.graph_renderer+graph_viewport+graph_labelspara visualizacion.fn_ui::*(toolbar, modal, select, etc.) para chrome.
Arquitectura
projects/osint_graph/apps/graph_explorer/
├── .git/ # sub-repo dataforge/graph_explorer (creado en 0049a)
├── app.md # NEW
├── CMakeLists.txt # NEW
├── main.cpp # NEW
├── data.{h,cpp} # NEW: dispatcher GraphLoadFn
├── views.{h,cpp} # NEW: Toolbar, Legend, Inspector, Stats
├── types_registry.{h,cpp} # NEW: lee types.yaml y mergea
└── examples/
└── types.yaml # NEW: ejemplo OSINT con Person/Email/Domain/...
app.md frontmatter
---
name: graph_explorer
lang: cpp
domain: viz
description: "Visor de grafos GPU-accelerated agnostico del backend. Lee operations.db de cualquier app del registry y permite explorar entidades/relaciones con shapes/iconos/layouts/filtros."
tags: [imgui, graph, osint, visualization, gpu]
uses_functions:
- graph_renderer_cpp_viz
- graph_force_layout_cpp_viz
- graph_force_layout_gpu_cpp_viz
- graph_layouts_cpp_viz
- graph_viewport_cpp_viz
- graph_labels_cpp_viz
- graph_icons_cpp_viz
- graph_sources_cpp_viz
- toolbar_cpp_core
- modal_dialog_cpp_core
- select_cpp_core
- text_input_cpp_core
- tree_view_cpp_core
- page_header_cpp_core
- fullscreen_window_cpp_core
uses_types: []
framework: "imgui"
entry_point: "main.cpp"
dir_path: "projects/osint_graph/apps/graph_explorer"
repo_url: "https://gitea-.../dataforge/graph_explorer"
---
CLI
graph_explorer [--input operations <path>] [--types <yaml>] [--layout force|grid|...]
graph_explorer apps/registry_dashboard/operations.db
graph_explorer --types projects/osint_graph/apps/graph_explorer/examples/types.yaml \
apps/element_agents/operations.db
Layout de ventanas
┌──────────────────────────────────────────────────────────┐
│ MainMenuBar (View | Settings | About) │
├─[Toolbar: Open | Layout: [force▼] | Filters | Fit | …]──┤
├─Legend──┬───────────────────────────────────────┬─Inspector─┤
│ Type │ │ id: ... │
│ ☑ Person│ │ type: ... │
│ ☑ Email │ Viewport (FBO) │ metadata… │
│ ☐ Domain│ │ │
│ Rels: │ │ Neighbors:│
│ ☑ owns │ │ • node A │
│ ... │ │ • node B │
├─────────┴───────────────────────────────────────┴────────────┤
│ Stats: nodes=12345 edges=54321 fps=60 energy=0.04 sel=2 │
└──────────────────────────────────────────────────────────┘
Tareas
Fase 1 — Esqueleto
- 1.1 Crear
app.mdcon frontmatter completo. - 1.2 Crear
CMakeLists.txtsiguiendocpp_apps.md. Listar todas las funciones del registry usadas explicitamente. - 1.3
main.cppminimo confn::run_app(cfg, render)+ parseo de--input/--types/--layout. - 1.4 Registrar la app en
cpp/CMakeLists.txtcon el patron deregistry_dashboard:set(_GE_DIR ${CMAKE_SOURCE_DIR}/../projects/osint_graph/apps/graph_explorer) if(EXISTS ${_GE_DIR}/CMakeLists.txt) add_subdirectory(${_GE_DIR} ${CMAKE_BINARY_DIR}/apps/graph_explorer) endif()
Fase 2 — data.{h,cpp} (dispatcher de sources)
- 2.1 Implementar dispatcher segun
--input:bool load_graph(const InputArgs& args, GraphData* out, GraphLoadStats* stats) { if (args.kind == INPUT_OPERATIONS) return graph_load_from_operations(args.uri, out, stats); // futuro: json/jsonl/graphml stats->errors++; return false; } - 2.2 Helper para reload (re-llamar la misma
GraphLoadFncon la misma URI).
Fase 3 — types_registry.{h,cpp}
- 3.1 Parser de
types.yaml:entities: - name: Person color: "#5B8DEF" shape: circle icon: ti-user - name: Email color: "#58CA8C" shape: square icon: ti-mail relations: - name: owns color: "#888888" style: solid - 3.2 Helper
apply_types_yaml(GraphData&, const ParsedTypes&): para cadaEntityType/RelationTypedel grafo cuyonamematchee en el yaml, sobrescribircolor/shape/icon_id/style. Tipos no encontrados se quedan con default (color por hash). - 3.3 Iconos: mapear nombre
ti-user→ codepoint Tabler usando una tabla en el headericons_tabler.h(helpers ya existentes o anadir uno nuevotabler_codepoint_by_name(const char*)). - 3.4 Construccion del
IconAtlas: collect codepoints distintos del yaml + fallback (icono "?" para no encontrados), llamargraph_icons_build(...).
Fase 4 — views.{h,cpp} (paneles)
- 4.1 Toolbar:
Open file…,Layout selector(select),Filters…(modal con checkboxes por tipo),Fit view,Save layout,Export PNG. - 4.2 Legend: lista de tipos con color swatch, icono y toggle de visibilidad. Toggle aplica a todos los nodos del tipo:
for each node where type_id == t: flags ^= NF_VISIBLE. Igual para relaciones. - 4.3 Inspector: cuando hay seleccion de un solo nodo, mostrar
id,type,metadata(raw JSON formateado), lista de vecinos directos clickables (click cambia seleccion). - 4.4 Stats: linea fija con counts + fps + energia.
- 4.5 Paneles toggleables via
AppConfig::panels.
Fase 5 — Persistencia
- 5.1
graph_explorer.dbSQLite junto al exe con tablalayouts(graph_hash TEXT, node_id TEXT, x REAL, y REAL, pinned INT, updated_at). - 5.2
graph_hash= hash del path del input (operations.db) para diferenciar entre grafos. - 5.3
Save layoutboton en la toolbar: snapshot de posiciones + flags. - 5.4 Al cargar un grafo conocido (mismo hash), pre-aplicar las posiciones guardadas.
- 5.5 Layout de paneles ImGui via
layout_storage(ya existe como funcion publica desde 0042).
Fase 6 — types.yaml ejemplo
- 6.1 Crear
examples/types.yamlcon ~10 tipos OSINT comunes (Person, Email, Domain, Phone, Org, IBAN, Account, Document, Address, Url) y 5 relaciones (owns, knows, located_in, transfers_to, member_of).
Fase 7 — TBD trabajo
- 7.1 Trabajar en rama
quick/graph-exploreroissue/0049k-graph-explorer-appsegun preferencia. - 7.2 Commits atomicos por panel/feature.
- 7.3 Merge
--no-ffa master del sub-repodataforge/graph_explorer. - 7.4 Push del sub-repo + push de fn_registry con la nueva ubicacion +
app.md.
Fase 8 — Indexado + flag
- 8.1
./fn indexdesde la raiz. - 8.2 Verificar:
SELECT id, name, project_id FROM apps WHERE id='graph_explorer_cpp_viz'; - 8.3 Activar feature flag en
dev/feature_flags.json:"osint_graph_v1": { "enabled": true, "issue": "0049", ... } - 8.4 Mover el issue principal 0049 + todos los sub-issues 0049a–k a
dev/issues/completed/y actualizar README.
Fase 9 — Verificacion end-to-end
- 9.1 Abrir
apps/registry_dashboard/operations.dby verificar que se ven entidades. - 9.2 Abrir un dataset OSINT real (cuando exista) o un fixture en
~/vaults/osint_graph/raw/. - 9.3 Verificar todas las features: filtrado por tipo, drag, multi-select, lasso, layouts, labels, save/load layout.
Criterio de done
graph_explorer apps/registry_dashboard/operations.dbarranca y muestra el grafo de entidades.- Con
--types examples/types.yaml, los tipos se ven con shapes/iconos/colores correctos. - 50k nodos cargan y se navegan a 60fps con layout GPU.
- Layouts intercambiables en runtime via toolbar.
- Filtros, drag, multi-select, lasso, labels funcionando.
- Persistencia de layout entre sesiones.
- App registrada en registry.db con uses_functions correcto.
- Sub-repo
dataforge/graph_explorercon master limpio y pushed. - Feature flag
osint_graph_v1=true. - Issue 0049 + sub-issues movidos a completed.
Riesgos
| Riesgo | Mitigacion |
|---|---|
| Parser YAML pesa: anadir libreria | Usar yaml-cpp si ya esta vendoreada; si no, parser minimal hand-rolled (10 tipos no necesita full YAML) |
Mapeo ti-user → codepoint requiere tabla nueva |
Generar a partir del icons_tabler.h existente con un script una sola vez |
| Inspector con metadata grande satura el panel | Truncar a ~512 chars + scroll del panel |
| Save layout en grafo grande es lento | UPSERT por nodo es O(N) con prepared statement; para 50k = ~100 ms aceptable en boton, no en frame |
| Operations.db de un app esta locked si la app corre | SQLite con mode=ro o immutable=1 en el URI |