0c1727fef7
Sub-issues activables de 0071 con plan concreto: API, dependencias, migracion, tests, anti-patrones. - 0071a (alta): claude_chat_panel — 2 consumidores reales (graph_explorer + navegator_dashboard, ~2500 LoC dup). Depende de 0071f. - 0071b (media): jobs_queue_panel — absorbe issue 0065. Depende de 0071f. Pre-requisito: auditar dup vs odr_console. - 0071g (media): app_db_init Tier 4 — 4+ duplicaciones en graph_explorer. Bajo riesgo. README actualizado. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
4.7 KiB
4.7 KiB
id, title, status, priority, created, parent, related_apps
| id | title | status | priority | created | parent | related_apps | |||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| 0071g | Extraer `app_db_init` a cpp/functions/core/ (sub-issue de 0071, Tier 4) | pending | media | 2026-05-10 | 0071 |
|
Contexto
Sub-issue derivado de 0071. Primitiva Tier 4 — sirve a TODOS los paneles de cualquier app que use SQLite. Bajo riesgo, alta reusabilidad.
Cada app C++ del registry repite el mismo patron al abrir su SQLite local:
- Resolver path:
<exe_dir>/local_files/<app>.dbviafn::local_path(). - Abrir con
sqlite3_open_v2(SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE). PRAGMA journal_mode=WAL.PRAGMA foreign_keys=ON.PRAGMA busy_timeout=5000.- Aplicar migrations desde
embed.FSo array de strings (migrations/001_*.sql,002_*.sql, ...). - Catch "duplicate column" / "already exists" para idempotencia.
- Verificar version con tabla
_migrationso assumir orden archivos.
Sitios actuales con esta logica embebida (~300 LoC duplicadas):
projects/osint_graph/apps/graph_explorer/project_manager.cpp:37-100(graph_explorer.db)projects/osint_graph/apps/graph_explorer/jobs.cpp(jobs persistence)projects/osint_graph/apps/graph_explorer/layout_store.cpp(layout positions)projects/osint_graph/apps/graph_explorer/node_groups.cpp(groups)apps/kanban/db.go::ensureColumns(Go, fuera de scope C++ pero patron equivalente)- Proxima
navegator_dashboard/local_api.cpp(history, tabs)
5+ duplicaciones C++ confirmadas. Rule of three superada con creces.
Objetivo
Funcion app_db_init en cpp/functions/core/ que recibe un path + lista de migraciones SQL y devuelve un sqlite3* listo, con todos los pragmas + migraciones aplicadas.
API propuesta
namespace fn_core {
struct AppDbConfig {
std::string path; // path absoluto al .db
std::vector<std::pair<std::string, std::string>> migrations;
// ^ pares (nombre_archivo, sql). Aplicados en orden de aparicion.
// Ej: {"001_init.sql", "CREATE TABLE ..."}, {"002_add_x.sql", "ALTER ..."}
bool wal = true;
bool foreign_keys = true;
int busy_timeout_ms = 5000;
};
struct AppDbResult {
sqlite3* conn; // null si error
std::string error; // descripcion del error si conn==null
int migrations_applied; // cuantas se ejecutaron sin error de duplicado
int migrations_skipped; // cuantas eran idempotentes ya aplicadas
};
AppDbResult app_db_init(const AppDbConfig& cfg);
// Helper para apps que tienen migrations en disco (no embebidas):
std::vector<std::pair<std::string, std::string>>
app_db_load_migrations_from_dir(const std::string& dir_path);
} // namespace fn_core
Behavior
- Crea el directorio del path si no existe.
- Aplica cada migracion en transaccion individual.
- Captura errores de tipo "duplicate column" / "table already exists" → no fail, suma a
skipped. - Cualquier otro error de SQL → cierra conn, devuelve null + mensaje.
- Logging via
fn_log::log_debugcon nombre del archivo aplicado.
Migracion
- Crear
cpp/functions/core/app_db_init.{h,cpp,md}+ tests. - Tests en primitives_gallery:
- DB nueva con 1 migracion → tabla creada, 1 applied.
- DB existente con la misma migracion → 0 applied, 1 skipped.
- DB con 2 migraciones, segunda falla por SQL invalido → conn null, error claro.
- DB con migracion que añade columna existente → catch "duplicate column", continua.
- Migrar consumidores uno a uno:
- graph_explorer: project_manager.cpp primero (mas codigo).
- graph_explorer: jobs, layout_store, node_groups.
- navegator_dashboard cuando empiece a tocar SQLite serio.
- Cada migracion en commit propio.
Definicion de hecho
app_db_init.{h,cpp,md}registrado.- Tests pasan (>= 4 casos).
- 4 consumidores migrados en graph_explorer.
- LoC eliminadas: ~300 (los 4 sitios reducidos a llamadas de ~5 LoC).
app.mdde cada app actualizado.
Riesgos
- Bajo. La operacion es read+exec SQL. No hay concurrencia compleja. Falla detectable inmediato.
- Riesgo unico: si la app espera un schema custom no via migrations (ej.
CREATE TABLE IF NOT EXISTSinline), hay que mover ese SQL a un stringmigrations/001_init.sqlantes.
Anti-patrones
- Auto-detectar formato (YAML/JSON) de migrations — recibir
vector<pair<name, sql>>directo. KISS. - Versioning con tabla
_migrations— para apps pequeñas basta el archivo numerado + idempotencia. Si una app crece, ella misma migra al patron tabla. - Embedded
embed.FSbaked-in — la funcion recibe pares ya cargados; cada app decide si los embebe con#embed(C++23) o los carga del filesystem. - Wrapper RAII sobre
sqlite3*— fuera de scope. Devuelve raw pointer, la app lo maneja con su propia clase.