3ebda4fcca
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
7.0 KiB
7.0 KiB
0008 — SQLite API Web
Metadata
| Campo | Valor |
|---|---|
| ID | 0008 |
| Estado | completado |
| Prioridad | alta |
| Tipo | feature |
Dependencias
Ninguna.
Objetivo
App que expone registry.db y los operations.db de cada app como API REST HTTP, permitiendo que herramientas externas (dashboards, scripts, agentes, frontends) consulten las bases de datos del registry sin necesidad de acceso directo al filesystem ni SQLite CLI.
Contexto
- Actualmente para consultar
registry.dbhay que estar en la misma máquina y usarsqlite3directamente o funciones Go que abren el archivo. - Las apps existentes (metabase_registry, registry_dashboard) acceden a SQLite localmente. Cualquier herramienta nueva que necesite datos del registry tiene que reimplementar la conexión.
- Con una API web, cualquier cliente HTTP (curl, fetch, Python requests, frontends React) puede consultar el registry de forma uniforme.
- Metabase ya resuelve visualización, pero no da acceso programático limpio a los datos para agentes y scripts remotos.
Arquitectura
apps/sqlite_api/
├── main.go — NEW: Entry point, configura rutas y arranca servidor
├── handlers.go — NEW: Handlers HTTP (query, tables, schema)
├── config.go — NEW: Configuración (puerto, DBs permitidas, read-only)
├── app.md — NEW: Metadata de la app (tag: service)
└── operations.db — Runtime: operaciones propias
Patrón pure core / impure shell
- Funciones del registry usadas:
http_get_json_go_infra,http_post_json_go_infra(para tests/clientes),cache_to_sqlite_go_infra(opcional para cache de queries) - Core puro: validación de queries (solo SELECT/PRAGMA permitidos), parsing de parámetros, formateo de resultados JSON
- Shell impuro: servidor HTTP, apertura de SQLite, ejecución de queries
Diseño de API
Endpoints
GET /api/databases — Lista de DBs disponibles
GET /api/databases/:db/tables — Lista tablas de una DB
GET /api/databases/:db/schema — Schema completo (.schema)
POST /api/databases/:db/query — Ejecuta query SQL (solo SELECT)
GET /api/databases/:db/fts?q=texto&table=functions — Búsqueda FTS5 directa
GET /health — Health check
Bases de datos expuestas
| Alias | Path real | Descripción |
|---|---|---|
registry |
registry.db (raíz) |
Funciones, tipos, proposals |
ops:{app} |
apps/{app}/operations.db |
Entities, relations, executions de cada app |
Seguridad
- Read-only obligatorio: Solo queries SELECT y PRAGMA. Cualquier INSERT/UPDATE/DELETE/DROP se rechaza antes de ejecutar.
- Bind por defecto a localhost (
127.0.0.1:8484). Flag--bindpara cambiar. - Sin autenticación en v1 (solo acceso local). Documentar cómo poner detrás de reverse proxy si se necesita auth.
- Query timeout: máximo 5 segundos por query para evitar bloqueos.
- Apertura con
?mode=roen el connection string de SQLite para doble protección.
Formato de respuesta
// POST /api/databases/registry/query
// Body: {"sql": "SELECT id, name, purity FROM functions WHERE domain = 'core' LIMIT 5"}
{
"columns": ["id", "name", "purity"],
"rows": [
["filter_slice_go_core", "filter_slice", "pure"],
["map_slice_go_core", "map_slice", "pure"]
],
"count": 2,
"duration_ms": 3
}
Tareas
Fase 1: Servidor base
- 1.1 Crear
apps/sqlite_api/conmain.go,go.mod(o usar módulo raíz) - 1.2 Handler
/healthy/api/databases(lista estática de DBs detectadas) - 1.3 Handler
POST /api/databases/:db/querycon validación read-only - 1.4 Abrir DBs con
?mode=roy-tags fts5 - 1.5
app.mdcon tagservice, documentar puerto y health check
Fase 2: Endpoints de exploración
- 2.1 Handler
/api/databases/:db/tables(lista tablas víasqlite_master) - 2.2 Handler
/api/databases/:db/schema(output de.schema) - 2.3 Handler
/api/databases/:db/ftspara búsqueda FTS5 sin escribir SQL
Fase 3: Operations discovery
- 3.1 Auto-detectar
apps/*/operations.dbal arrancar - 3.2 Exponer cada operations.db como
ops:{app_name} - 3.3 Endpoint
GET /api/databasesincluye las operations detectadas
Fase 4: Cleanup y docs
- Crear
app.mdcompleto - Ejecutar
go vetygo test - Actualizar issue en
dev/issues/README.md
Ejemplo de uso
# Arrancar el servicio
cd apps/sqlite_api && go run . --port 8484
# Health check
curl http://localhost:8484/health
# Listar databases disponibles
curl http://localhost:8484/api/databases
# Query al registry
curl -X POST http://localhost:8484/api/databases/registry/query \
-H "Content-Type: application/json" \
-d '{"sql": "SELECT id, purity, description FROM functions WHERE domain = '\''core'\'' LIMIT 5"}'
# Búsqueda FTS5
curl "http://localhost:8484/api/databases/registry/fts?q=slice&table=functions"
# Schema
curl http://localhost:8484/api/databases/registry/schema
# Query a operations de una app
curl -X POST http://localhost:8484/api/databases/ops:pipeline_launcher/query \
-H "Content-Type: application/json" \
-d '{"sql": "SELECT * FROM executions ORDER BY started_at DESC LIMIT 10"}'
# Desde Python
import requests
r = requests.post("http://localhost:8484/api/databases/registry/query", json={
"sql": "SELECT id, name FROM functions WHERE purity = 'pure' AND domain = 'core'"
})
data = r.json()
for row in data["rows"]:
print(row[0], row[1])
Decisiones de diseño
- Go con net/http estándar: sin framework externo, coherente con el resto del registry. Router simple con
http.ServeMux. - Puerto 8484: no colisiona con Metabase (3000), Jupyter (8888), ni otros servicios comunes.
- Read-only estricto: la API nunca modifica datos. Para escribir se usan los mecanismos existentes (
fn ops,fn index). - Sin ORM: queries se pasan tal cual a SQLite. El valor es el acceso HTTP, no una capa de abstracción SQL.
- Auto-discovery de operations.db: escanea
apps/*/operations.dbal inicio para no tener que configurar cada app manualmente.
Riesgos
- SQL injection vía queries arbitrarias: Mitigado con apertura read-only (
?mode=ro) + validación de que el statement empieza con SELECT o PRAGMA. - Queries pesadas bloquean el servidor: Mitigado con timeout de 5s por query y context cancelable.
- Archivos SQLite bloqueados por escritores concurrentes: Mitigado con
journal_mode=waly apertura read-only que no bloquea escritores.
Criterios de aceptación
curl localhost:8484/healthretorna 200- Queries SELECT funcionan contra registry.db
- Queries INSERT/UPDATE/DELETE son rechazadas con 400
- Operations.db de apps existentes son accesibles como
ops:{nombre} - FTS5 funciona a través de la API
- Tag
serviceen app.md - El servidor arranca con
go run .sin configuración adicional