docs(issues): planning issues 0005-0010 (types schema, projects, type editor, inspector, fts, table node)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
---
|
||||
id: 0005
|
||||
title: Type schema en types.yaml — fields por tipo + principal_field
|
||||
status: pending
|
||||
priority: high
|
||||
created: 2026-04-30
|
||||
---
|
||||
|
||||
## Objetivo
|
||||
|
||||
Extender `types.yaml` para declarar el **esquema de campos** de cada entity
|
||||
type, ademas de la cosmetica que ya existe (color/shape/icon). Es la base
|
||||
sobre la que tiran 0007 (Type Editor) y 0008 (Inspector editable).
|
||||
|
||||
## Formato propuesto
|
||||
|
||||
```yaml
|
||||
entities:
|
||||
- name: Person
|
||||
color: "#5B8DEF"
|
||||
shape: circle
|
||||
icon: ti-user
|
||||
principal_field: name # opcional, default = "name"
|
||||
fields:
|
||||
- { name: name, type: string, required: true }
|
||||
- { name: first_name, type: string }
|
||||
- { name: last_name, type: string }
|
||||
- { name: age, type: int }
|
||||
- { name: nationality, type: string }
|
||||
- { name: birth_date, type: date }
|
||||
- { name: gender, type: enum, values: [male, female, other] }
|
||||
```
|
||||
|
||||
Tipos soportados (v1): `string`, `int`, `float`, `bool`, `date`, `url`,
|
||||
`enum`. `enum` requiere `values: [...]`.
|
||||
|
||||
`principal_field` es el campo que el viewport usa como label visible del
|
||||
nodo cuando no hay otro override (sustituye al actual `name` hardcodeado).
|
||||
|
||||
## Cambios en codigo
|
||||
|
||||
- `types_registry.h`:
|
||||
- Nuevo `FieldSpec { string name; FieldKind kind; bool required; vector<string> enum_values; }`.
|
||||
- `EntitySpec` gana `string principal_field` y `vector<FieldSpec> fields`.
|
||||
- `types_registry.cpp`:
|
||||
- Parser tolerante: ignora `fields:` si no esta presente; tipos
|
||||
desconocidos se mapean a `string` con warning.
|
||||
- **Writer** nuevo: `bool types_save_yaml(const char* path, const ParsedTypes& types, string* error_msg)`. Round-trip que preserva el orden de claves y el formato compacto del ejemplo.
|
||||
- `examples/types.yaml`: anadir `fields` a Person, Email, Domain, Phone, Org como semilla.
|
||||
|
||||
## Definicion de hecho
|
||||
|
||||
- Parser lee el yaml extendido sin romper el yaml existente (sin `fields`).
|
||||
- Writer regenera un yaml legible y re-parseable (test round-trip).
|
||||
- `examples/types.yaml` incluye `fields` para los 10 tipos existentes.
|
||||
- `apply_types_yaml` no se rompe (no toca `fields` aun, eso es 0007/0008).
|
||||
@@ -0,0 +1,68 @@
|
||||
---
|
||||
id: 0006
|
||||
title: Sistema de proyectos dentro de la app — subcarpetas + switcher
|
||||
status: pending
|
||||
priority: high
|
||||
created: 2026-04-30
|
||||
---
|
||||
|
||||
## Objetivo
|
||||
|
||||
Cada "proyecto" es una subcarpeta junto al exe que contiene su propio
|
||||
`operations.db`, `types.yaml` y `graph_explorer.db` (layouts). El usuario
|
||||
crea proyectos, los nombra, y conmuta entre ellos sin reiniciar la app.
|
||||
Esto es lo que va a permitir guardar muchos datos separados por caso/tema
|
||||
sin acumularlos en un solo grafo.
|
||||
|
||||
Independiente del concepto de "project" del registry (`projects/` raiz
|
||||
del repo) — aqui es organizativo, dentro de la app desplegada.
|
||||
|
||||
## Layout en disco (junto al exe)
|
||||
|
||||
```
|
||||
graph_explorer.exe
|
||||
graph_explorer.ini # estado global: ultimo proyecto abierto, recientes
|
||||
projects/
|
||||
default/
|
||||
operations.db
|
||||
types.yaml # copia editable; semilla = examples/types.yaml
|
||||
graph_explorer.db # layouts de este proyecto
|
||||
notes/ # opcional, .md sueltos
|
||||
caso_aurgi/
|
||||
operations.db
|
||||
types.yaml
|
||||
graph_explorer.db
|
||||
osint_demo/
|
||||
...
|
||||
```
|
||||
|
||||
## UI
|
||||
|
||||
- Menu "Project" en la menubar:
|
||||
- `New...` (input de nombre, valida slug, crea carpeta + semilla types.yaml + operations.db vacio con schema migrado).
|
||||
- `Open...` (combo con los proyectos detectados en `./projects/`).
|
||||
- `Recent` (lista los ultimos 5 desde `graph_explorer.ini`).
|
||||
- `Reveal in explorer` (abre la carpeta del proyecto activo).
|
||||
- Title bar muestra `graph_explorer — <proyecto activo>`.
|
||||
- Switch de proyecto: cierra BDs, limpia grafo + viewport, abre nuevas BDs, hace reload.
|
||||
|
||||
## Cambios en codigo
|
||||
|
||||
- `main.cpp`:
|
||||
- Resolver paths a traves de `g_active_project` en vez de `./operations.db` y `./graph_explorer.db` directos.
|
||||
- Modo legacy: si arranca con `--input <path>` o positional, no usa proyecto (compatibilidad con flujo actual).
|
||||
- `app_state` nuevo campo `string active_project_dir`.
|
||||
- Nueva fn `project_create(name)` que escribe schema base de operations.db (entities/relations/...) — extraerlo de lo que ya hace el registry o copiar el DDL.
|
||||
- `graph_explorer.ini` lee/escribe via `app_settings_*` ya existente.
|
||||
|
||||
## Migracion del flujo actual
|
||||
|
||||
- Al primer arranque sin `--input`, si no existe `./projects/`, crear `./projects/default/` y mover `./operations.db` + `./graph_explorer.db` ahi (si existen).
|
||||
- Issues 0005/0007/0008 ya asumen este layout.
|
||||
|
||||
## Definicion de hecho
|
||||
|
||||
- Crear, abrir y conmutar proyectos sin reiniciar.
|
||||
- Cada proyecto tiene su `operations.db`, `types.yaml`, `graph_explorer.db` aislados.
|
||||
- "Recent" persiste entre sesiones via `graph_explorer.ini`.
|
||||
- El layout (posiciones de nodos) es por-proyecto: cambiar de proyecto recupera las posiciones del nuevo, no las del anterior.
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
id: 0007
|
||||
title: Type Editor panel — CRUD de tipos desde la app
|
||||
status: pending
|
||||
priority: medium
|
||||
created: 2026-04-30
|
||||
depends_on: [0005, 0006]
|
||||
---
|
||||
|
||||
## Objetivo
|
||||
|
||||
Panel "Types" dockeable que permita editar el `types.yaml` del proyecto
|
||||
activo desde dentro de la app. Cosmetica (color/shape/icon) y schema de
|
||||
campos (lista de fields con tipo). Save reescribe el yaml y dispara
|
||||
`apply_types_yaml` + reload del grafo.
|
||||
|
||||
## UI
|
||||
|
||||
- Tabs: "Entities" / "Relations".
|
||||
- Lista a la izquierda con los tipos. Botones `+` (anadir), `-` (borrar), drag para reordenar.
|
||||
- Panel derecho con la edicion del tipo seleccionado:
|
||||
- Entities: name, color (color picker), shape (combo), icon (input + preview), principal_field (combo entre los fields).
|
||||
- Relations: name, color, style.
|
||||
- Sub-seccion **Fields** (solo entities): tabla con name / type / required / values (para enum). Botones para anadir/quitar/reordenar fila.
|
||||
- Footer: `Save to types.yaml` (deshabilitado si no hay cambios) + `Reload from disk` (descarta cambios).
|
||||
|
||||
## Cambios en codigo
|
||||
|
||||
- `views.{h,cpp}`: nueva fn `views_type_editor(AppState&)` + entrada en panels menu.
|
||||
- `app_state`: anade `ParsedTypes types_draft;` y `bool types_dirty;`.
|
||||
- Usa `types_save_yaml` de 0005 para persistir.
|
||||
- Tras Save: `apply_types_yaml(graph, types_draft)` + rebuild del IconAtlas.
|
||||
|
||||
## Notas
|
||||
|
||||
- Borrar un tipo NO toca las entidades existentes con ese `type_ref` — se quedan con un tipo "huerfano" hasta que el usuario las cambie. Mostrar warning antes del delete con conteo de entidades afectadas.
|
||||
- Cambiar `principal_field` de un tipo regenera los labels visibles.
|
||||
|
||||
## Definicion de hecho
|
||||
|
||||
- Crear, editar y borrar entity/relation types desde la UI.
|
||||
- Editar fields (anadir, cambiar type, marcar required, definir enum values).
|
||||
- Save persiste a `projects/<activo>/types.yaml` y aplica al grafo en vivo.
|
||||
- Reload from disk descarta cambios.
|
||||
@@ -0,0 +1,55 @@
|
||||
---
|
||||
id: 0008
|
||||
title: Inspector editable — campos del schema + tags + extras
|
||||
status: pending
|
||||
priority: high
|
||||
created: 2026-04-30
|
||||
depends_on: [0005]
|
||||
---
|
||||
|
||||
## Objetivo
|
||||
|
||||
Refactor del Inspector (`views_inspector`) de read-only a editable. El usuario
|
||||
edita los datos de un nodo y al pulsar Save se persisten en `operations.db`
|
||||
con un solo UPDATE.
|
||||
|
||||
## Bloques del nuevo Inspector
|
||||
|
||||
1. **Identidad**
|
||||
- `name` (InputText), `type_ref` (combo con tipos del proyecto), `description` (InputTextMultiline corto), `status` (combo: active/stale/corrupted/archived).
|
||||
|
||||
2. **Fields del tipo** (driven by 0005)
|
||||
- Render automatico segun `EntitySpec.fields`:
|
||||
- `string` → InputText.
|
||||
- `int` → InputInt.
|
||||
- `float` → InputDouble.
|
||||
- `bool` → Checkbox.
|
||||
- `date` → InputText con placeholder `YYYY-MM-DD` + validacion.
|
||||
- `url` → InputText + boton "Open" que lanza el navegador.
|
||||
- `enum` → Combo con `values`.
|
||||
- Lee/escribe a `entities.metadata` (JSON). Campos requeridos marcados con `*`.
|
||||
|
||||
3. **Extras** (campos fuera del schema del tipo)
|
||||
- Lista key-value, "+" para anadir. Tipo siempre string en v1.
|
||||
- Permite que el usuario meta info ad-hoc sin tocar el schema.
|
||||
|
||||
4. **Tags**
|
||||
- Chips con boton X para quitar. Input al final con autocomplete (lista de tags ya existentes en la BD via `SELECT DISTINCT json_each.value FROM entities, json_each(entities.tags)`).
|
||||
- Enter o coma valida el chip.
|
||||
|
||||
5. **Notes** — sigue en su panel actual, pero anadir un boton "Open notes" en el Inspector que enfoca el panel Note.
|
||||
|
||||
## Cambios en codigo
|
||||
|
||||
- `entity_ops.{h,cpp}`:
|
||||
- `bool entity_update(db_path, id, name, type_ref, description, status, tags_json, metadata_json)` — un solo UPDATE.
|
||||
- `bool entity_list_distinct_tags(db_path, vector<string>* out)` para autocomplete.
|
||||
- `views.cpp::views_inspector`: reemplazo completo. Estado de edicion en `AppState` para que cerrar y reabrir conserve el draft hasta Save.
|
||||
- Save → reload del grafo (mismo flujo que toolbar add-node hoy).
|
||||
|
||||
## Definicion de hecho
|
||||
|
||||
- Editar name, type_ref, description, status, tags, fields tipados y extras.
|
||||
- Save persiste y el viewport refleja los cambios (label, color del tipo, etc.).
|
||||
- Cancelar / cambiar de seleccion sin guardar muestra un confirm dialog.
|
||||
- Tags se autocompletan con las existentes en la BD.
|
||||
@@ -0,0 +1,37 @@
|
||||
---
|
||||
id: 0009
|
||||
title: Filtro por tag + busqueda FTS5 en toolbar
|
||||
status: pending
|
||||
priority: medium
|
||||
created: 2026-04-30
|
||||
depends_on: [0008]
|
||||
---
|
||||
|
||||
## Objetivo
|
||||
|
||||
Buscar y filtrar entidades por nombre/tag/description directamente desde la
|
||||
toolbar, aprovechando el `entities_fts` que ya existe en `operations.db`.
|
||||
|
||||
## UI
|
||||
|
||||
- Toolbar: input de busqueda + chip-list de tags activas como filtro.
|
||||
- Mientras se escribe, dropdown con resultados (max 20). Click en resultado selecciona/centra el nodo.
|
||||
- Click en un tag (en Inspector o en el dropdown) lo anade como chip de filtro.
|
||||
- Modos de filtro:
|
||||
- **Highlight**: nodos no-coincidentes se atenuan (alpha bajado), pero siguen presentes.
|
||||
- **Hide**: nodos no-coincidentes se ocultan del viewport.
|
||||
- Toggle en la toolbar.
|
||||
|
||||
## Cambios en codigo
|
||||
|
||||
- Nueva fn `entity_search_fts(db_path, query, limit, vector<EntityHit>* out)` con resultados ordenados por rank.
|
||||
- Filtro vive en `AppState`: vector de tags + query string + modo (highlight/hide).
|
||||
- En `graph_viewport.cpp` o donde aplique: aplicar mascara de visibilidad/alpha segun el filtro activo (sin tocar la BD).
|
||||
- Reset filter desde la toolbar.
|
||||
|
||||
## Definicion de hecho
|
||||
|
||||
- FTS sobre name/description/tags/domain funciona y los resultados centran el viewport.
|
||||
- Multiples chips de tag combinan con AND.
|
||||
- Modo highlight y modo hide funcionan sin recargar el grafo.
|
||||
- Limpiar filtro restaura visibilidad completa.
|
||||
@@ -0,0 +1,71 @@
|
||||
---
|
||||
id: 0010
|
||||
title: Nodo tabla — contenedor cuadrado con filas que son nodos del grafo
|
||||
status: pending
|
||||
priority: medium
|
||||
created: 2026-04-30
|
||||
depends_on: [0004, 0005, 0008]
|
||||
---
|
||||
|
||||
## Objetivo
|
||||
|
||||
Un tipo especial de nodo, **Table**, que se renderiza en el viewport como
|
||||
un rectangulo (no circulo) y agrupa visualmente N entidades del grafo. Cada
|
||||
fila de la tabla = un nodo real del grafo (con su `type_ref`, sus fields,
|
||||
sus tags). Las filas se pueden **extraer** (salen al canvas como nodos
|
||||
sueltos) y **meter** (un nodo suelto entra como fila).
|
||||
|
||||
Distinto del issue 0004 (vista tabla global por tipo): ese es una **ventana
|
||||
auxiliar** que tabula entidades existentes; este es un **nodo en el grafo**
|
||||
que existe en `entities` y posee filas via relaciones.
|
||||
|
||||
## Modelo de datos
|
||||
|
||||
- El nodo tabla es una entidad normal con `type_ref = 'Table'` y metadata:
|
||||
```json
|
||||
{
|
||||
"row_type": "Person", // tipo esperado de las filas (puede ser vacio = mixto)
|
||||
"columns": ["name","age","email"], // subset de fields del row_type a mostrar como columnas
|
||||
"expanded": true // estado de UI persistido
|
||||
}
|
||||
```
|
||||
- La pertenencia se modela con relaciones:
|
||||
- `name = "CONTAINS_ROW"`, `from_entity = <table_id>`, `to_entity = <row_entity_id>`, `order = N`.
|
||||
- Una fila puede pertenecer a varias tablas (varias relaciones `CONTAINS_ROW` apuntando al mismo nodo). Confirmado en la conversacion.
|
||||
- Las columnas pueden ser fijas (`row_type` definido → columnas = subset de los `fields` de ese tipo) o libres (definidas por el creador de la tabla en `columns`).
|
||||
|
||||
## Render en viewport
|
||||
|
||||
- Forma: `square` o `rounded_square` con tamano dependiente del numero de filas (clamp a min/max).
|
||||
- Cuando esta **colapsada**: caja con titulo + contador (`Table · 23 filas`).
|
||||
- Cuando esta **expandida**: caja crece y dibuja un grid interno (filas x columnas) con los valores principales. Las filas son arrastrables individualmente.
|
||||
- Las relaciones `CONTAINS_ROW` no se dibujan como aristas normales (serian ruido visual). En su lugar, una fila extraida muestra una arista fina punteada hacia su tabla de origen.
|
||||
- Aristas entrantes/salientes del nodo tabla se dibujan al borde del rectangulo, no al centro.
|
||||
|
||||
## Operaciones
|
||||
|
||||
- **Crear tabla**: en context menu del viewport, "New table here". Pide `row_type` opcional. Crea entidad `Table` y la posiciona donde el click.
|
||||
- **Anadir fila** (tabla expandida o seleccionada): boton "+ row" que crea una entidad nueva con `type_ref = row_type` (si esta definido) y la engancha via `CONTAINS_ROW`.
|
||||
- **Extraer fila**: borra la relacion `CONTAINS_ROW`. La fila queda como nodo libre, posicionada al lado de la tabla.
|
||||
- **Extraer multiples**: shift+click en filas dentro de la tabla expandida, "Extract selected".
|
||||
- **Meter fila**: drag de un nodo sobre el rectangulo de una tabla. Confirm dialog si su `type_ref` no coincide con `row_type` de la tabla.
|
||||
- **Editar fila**: doble-click en fila → abre Inspector con esa entidad seleccionada.
|
||||
|
||||
## Cambios en codigo
|
||||
|
||||
- `entity_ops`:
|
||||
- `bool table_create(db_path, name, row_type, columns_csv, char* out_id)`.
|
||||
- `bool table_add_row(db_path, table_id, char* out_row_id)` (crea entidad + relacion CONTAINS_ROW).
|
||||
- `bool table_extract_row(db_path, table_id, row_id)` (borra solo la relacion).
|
||||
- `bool table_attach_row(db_path, table_id, row_id, int order)`.
|
||||
- `bool table_list_rows(db_path, table_id, vector<string>* out_row_ids)`.
|
||||
- Renderer del viewport (`graph_viewport.cpp` y/o `graph_renderer`): branch para `is_table_node` (detectado por `type_ref == "Table"`) que dibuja rectangulo + grid expandido y devuelve hit-testing por filas individuales.
|
||||
- `graph_load_from_operations`: filtrar las aristas `CONTAINS_ROW` para que no entren en el layout fisico (no aplican fuerzas).
|
||||
|
||||
## Definicion de hecho
|
||||
|
||||
- Crear tabla, anadir filas, extraer y meter filas funciona round-trip via SQLite.
|
||||
- Tabla colapsada y expandida se renderizan correctamente en el viewport.
|
||||
- Doble-click en fila enfoca el Inspector con esa entidad.
|
||||
- Una fila puede pertenecer a varias tablas sin duplicarse.
|
||||
- Borrar la tabla pregunta: "borrar tabla y todas sus filas" o "extraer filas y borrar solo la tabla".
|
||||
Reference in New Issue
Block a user