Plataforma de administración de bases de datos con interfaz visual estilo DBeaver/Workbench,
motor de pipelines de datos (jobs), gráficas, reportes PDF y gestor de bloques de transformación reutilizables.
┌─────────────────────────────────────────────────────────┐
│ Frontend (React 18 + Vite) │
│ • Editor SQL con autocompletado (CodeMirror) │
│ • Canvas visual de pipelines (@xyflow/react) │
│ • Dashboard, Gráficas (Recharts), Reportes PDF │
└────────────────────┬────────────────────────────────────┘
│ HTTP / REST (Bearer JWT)
┌────────────────────▼────────────────────────────────────┐
│ Backend (FastAPI + Python) │
│ • /db/v1/* Administración de bases de datos │
│ • /jobs/v1/* Motor de pipelines y jobs │
│ • /charts/v1/* Gráficas guardadas │
│ • /reports/v1/* Reportes PDF │
│ • /transform-blocks/v1/* Bloques reutilizables │
│ • /admin/users/* Gestión de usuarios ACL │
│ • /oauth/token Autenticación JWT │
└──────┬──────────────────────────┬───────────────────────┘
│ │
┌──────▼──────┐ ┌────────▼──────────────────────┐
│ app_state │ │ Bases de datos administradas │
│ (SQLite / │ │ MySQL / PostgreSQL / SQLite │
│ MySQL / │ │ (una o varias, configuradas │
│ PostgreSQL)│ │ en .env como SERVERS) │
│ │ └────────────────────────────────┘
│ users_acl │
│ charts │
│ jobs │
│ job_runs │
│ job_run_steps│
│ reports │
│ transform_ │
│ blocks │
└─────────────┘
python_api/)| Módulo | Descripción |
|---|---|
app/api/ |
Routers FastAPI — uno por recurso |
app/services/jobs_engine.py |
Motor de ejecución de pipelines. 20+ tipos de paso: SQL, transformación, calidad de datos, flujo, Python en sandbox |
app/services/jobs_service.py |
CRUD de jobs, disparo de corridas (manual/scheduler) |
app/services/transform_blocks_service.py |
CRUD de bloques de transformación reutilizables |
app/services/charts_service.py |
CRUD de gráficas + ejecución de consultas |
app/services/reports_service.py |
Generación de PDFs con ReportLab |
app/services/python_sandbox.py |
Sandbox real con bwrap (bubblewrap): aislamiento de red/filesystem/CPU/RAM |
app/core/acl.py |
Motor de autorización por scopes |
app/core/acl_users.py |
CRUD de usuarios ACL en la BD |
app/core/security.py |
Emisión y validación de JWT |
app/db/connection.py |
Pool de conexiones SQLAlchemy a las BDs administradas |
app/db/app_state.py |
BD de estado propio de la app (SQLite por defecto) |
app/support/audit_logger.py |
Logging estructurado por categoría (ops, security, jobs, errors) |
frontend/)| Componente | Descripción |
|---|---|
SqlEditorTab.jsx |
Editor SQL con autocompletado de esquema via CodeMirror |
JobCanvas.jsx |
Canvas visual de pipelines con drag & drop (@xyflow/react) |
JobEditorTab.jsx |
Editor completo de un job (canvas + metadatos) |
ChartsTab.jsx |
Vista de gráficas con Recharts |
TransformBlockFormModal.jsx |
Editor de bloques de transformación (sub-canvas) |
ScopeBuilder.jsx |
Constructor visual de permisos ACL |
bwrap (bubblewrap) para el paso Python en sandbox:bash
sudo apt install bubblewrap # Debian/Ubuntucd python_api
pip install -r requirements.txt
# Configurar variables (ver sección Variables de entorno)
cp ../.env.example ../.env
# Editar .env con los datos de los servidores de BD
# Arrancar (desarrollo)
cd ..
./run-dev-mysql.sh
# o: ENABLE_ACL=true ./run-dev-mysql.sh
# El backend queda en http://localhost:3560
# Swagger completo: /docs o /swagger
# Swagger SQL + consultas: /swagger-consultas
# Swagger solo API datos: /swagger-api
cd frontend
npm install
npm run dev # desarrollo (http://localhost:5173)
npm run build # producción → dist/
Con ENABLE_ACL=true, la app requiere un usuario para hacer login. Si no hay ninguno en la BD (arranque fresco), el script hash_password.py genera el hash:
cd python_api
python hash_password.py MiPassword123!
# Copia el hash y ejecuta el endpoint POST /admin/users con admin auth
# o importa acl_users.json.example como acl_users.json antes del primer arranque
Todas van en el .env en la raíz del repo. Las marcadas con * son obligatorias en producción.
| Variable | Default | Descripción |
|---|---|---|
JWT_SECRET * |
— | Clave para firmar JWTs. Mínimo 32 caracteres aleatorios |
ENABLE_ACL |
false |
true = requiere login y aplica scopes |
APP_DB_URL |
sqlite:///./app_state.db |
BD de estado de la app. Cambiar a MySQL/PostgreSQL en producción |
SERVERS |
{} |
JSON con los servidores de BD administrados (ver ejemplo abajo) |
DATABASE_TYPE |
mysql |
mysql | postgresql | sqlite |
PORT |
3560 |
Puerto del backend |
ALLOW_RAW_SQL |
false |
true = permite exec-query sin CTE (requiere scope db:xxx:sql) |
ENABLE_DOCS |
true |
false = deshabilita Swagger en producción |
LOG_DIR |
logs/ |
Directorio de logs |
JOB_OUTPUTS_DIR |
job_outputs/ |
Archivos generados por jobs |
JOB_UPLOADS_DIR |
job_uploads/ |
CSVs/XLSXs subidos para pasos file_input |
JOB_UPLOAD_MAX_MB |
50 |
Tamaño máximo de archivo subido |
SERVERS)SERVERS='{
"produccion": {
"type": "mysql",
"host": "db.empresa.com",
"port": 3306,
"user": "dbstudio",
"password": "secreto",
"databases": ["crm", "ventas", "logistica"]
},
"analytics": {
"type": "postgresql",
"host": "analytics.empresa.com",
"port": 5432,
"user": "readonly",
"password": "otro_secreto",
"databases": ["warehouse"]
}
}'
APP_DB_URL=mysql+pymysql://usuario:clave@servidor:3306/dbstudio_meta
# o
APP_DB_URL=postgresql+psycopg://usuario:clave@servidor:5432/dbstudio_meta
Las tablas se crean automáticamente al arrancar (sin migraciones manuales).
Con ENABLE_ACL=false (default): cualquier JWT válido tiene acceso total.
Con ENABLE_ACL=true: cada usuario tiene un conjunto de scopes.
admin Acceso total — bypasea todo lo demás
# Bases de datos
db:<bd>:read Leer cualquier tabla de <bd>
db:<bd>:write Escribir/actualizar/borrar en <bd>
db:<bd>:schema Crear/editar vistas, procedimientos, triggers
db:<bd>:sql Ejecutar SQL crudo y CTEs
db:<bd>:table:<tabla>:read Lectura granular a una tabla
db:<bd>:table:<tabla>:write Escritura granular a una tabla
db:*:read / db:*:write / etc. Wildcard — aplica a todas las BDs
# Herramientas globales
download Exportar resultados como CSV/XLSX
copy Copiar datos de la grilla (solo UX)
# Módulos de la aplicación
charts:read / charts:write Gráficas guardadas
reports:read / reports:write Reportes PDF
jobs:read / jobs:write Definiciones de jobs
jobs:execute Disparar corridas manuales
jobs:python Guardar pasos con código Python (sandbox)
transform_blocks:read / :write Bloques de transformación reutilizables
| Perfil | Scopes |
|---|---|
| Admin | admin |
| Desarrollador | db:xxx:read write sql schema + todos los módulos |
| Analista | db:xxx:read sql download charts:read reports:read jobs:read |
| Operador de jobs | db:xxx:read sql jobs:read jobs:execute |
| Solo lectura | db:xxx:read download |
| Categoría | Tipos |
|---|---|
| Entrada | sql_source, generate_rows (plantilla o tabla), file_input |
| Salida | save_table, export_file (CSV/XLSX/JSON/JSON_objeto/XML), render_chart (PNG), generate_report (PDF) |
| Transformación | filter_rows, sort_rows, select_values, calculator, group_by, pivot_table |
| Uniones | join_rows (SQL join via pandas), union_rows |
| Flujo | dummy, switch_case |
| Calidad | data_cleanse, data_validate |
| Script | python_transform (sandbox bwrap) |
| Bloques | transform_block (referencia a un bloque reutilizable guardado) |
Un paso sql_source que recibe datos de un paso anterior los materializa como tabla temporal en el servidor destino, permitiendo JOINs entre datos de distintos servidores sin conexión directa entre ellos. Los datos viajan en memoria vía Python.
El paso python_transform corre en un sandbox real con bwrap (mismo aislamiento de Flatpak):
resource.setrlimitpandas, numpy, math, datetime, json, re, statistics, itertools, collectionsPOST /oauth/token
Content-Type: application/x-www-form-urlencoded
username=ana&password=secreto
Respuesta: {"access_token": "<JWT>", "token_type": "bearer"}
Todos los demás endpoints requieren Authorization: Bearer <token>.
| URL | Contenido |
|---|---|
/docs |
Swagger completo — todos los endpoints |
/swagger-consultas |
Solo exec-query, CTE, export + endpoints de consumo de datos |
/swagger-api |
Solo API de consumo de datos (para integrar con Grafana, Power BI, etc.) |
# Datos de la última salida exitosa de un step (para polling periódico)
GET /jobs/v1/{job_id}/data/{step_id}
→ {"data": [...filas...], "count": N, "meta": {...}}
# Archivo de la última salida (CSV, JSON, XML, PNG, XLSX)
GET /jobs/v1/{job_id}/latest-output/{step_id}
→ archivo con Content-Type apropiado (sin forced download)
# Datos de una gráfica guardada
POST /charts/v1/{chart_id}/data
→ {"data": [...filas...], "meta": {...}}
# Generar PDF de un reporte
POST /reports/v1/{report_id}/generate
→ archivo PDF
Los logs se generan en logs/ con rotación diaria (30 días de retención).
| Archivo | Contenido | Retención |
|---|---|---|
logs/ops.log |
Requests normales (< 400): consultas, exports, reads | 30 días |
logs/security.log |
Login, logout, creación/modificación de usuarios | 90 días |
logs/jobs.log |
Ciclo de vida de jobs: creación, corridas, fallos por paso | 30 días |
logs/errors.log |
Requests con status ≥ 400, excepciones inesperadas | 7 días |
[2026-07-01 14:32:01] INFO dbstudio.ops REQUEST_OK method=POST path=/db/v1/cte user=ana ip=10.0.0.5 status=200 duration_ms=142 db=crm
[2026-07-01 14:32:05] INFO dbstudio.security LOGIN_OK username=ana ip=10.0.0.5 status=200 duration_ms=38
[2026-07-01 14:33:00] INFO dbstudio.jobs RUN_START job_id=3 job_name="Export diario" run_id=17 trigger=schedule user=sistema steps=4
[2026-07-01 14:33:02] INFO dbstudio.jobs RUN_COMPLETE job_id=3 job_name="Export diario" run_id=17 trigger=schedule user=sistema
[2026-07-01 14:40:01] WARNING dbstudio.security LOGIN_FAIL username=hacker ip=192.168.1.100 status=401 duration_ms=250
| Evento | Log | Nivel |
|---|---|---|
| Login exitoso | security.log |
INFO |
| Login fallido | security.log |
WARNING |
| Usuario creado/modificado/borrado | security.log |
INFO |
| Job creado/borrado | jobs.log |
INFO |
| Corrida iniciada/completada | jobs.log |
INFO |
| Paso de job fallido | jobs.log |
WARNING |
| Request con error 4xx | errors.log |
WARNING |
| Request con error 5xx | errors.log |
ERROR |
api-mysql/
├── .env # Variables de entorno (no commitear)
├── .env.example # Plantilla de configuración
├── run-dev-mysql.sh # Script de arranque del backend
├── hash_password.py # CLI para generar hashes bcrypt
├── acl_users.json.example # Ejemplo de usuarios ACL
│
├── python_api/ # Backend FastAPI
│ ├── app/
│ │ ├── main.py # App factory, routers, Swagger x3
│ │ ├── api/ # Routers HTTP
│ │ │ ├── jobs.py # /jobs/v1/*
│ │ │ ├── charts.py # /charts/v1/*
│ │ │ ├── reports.py # /reports/v1/*
│ │ │ ├── transform_blocks.py # /transform-blocks/v1/*
│ │ │ ├── admin_users.py # /admin/users/*
│ │ │ └── oauth.py # /oauth/token
│ │ ├── core/
│ │ │ ├── acl.py # Motor de scopes
│ │ │ ├── acl_users.py # CRUD de usuarios en BD
│ │ │ ├── config.py # Settings via pydantic-settings
│ │ │ └── security.py # JWT (emisión y validación)
│ │ ├── db/
│ │ │ ├── app_state.py # Motor SQLAlchemy para estado propio
│ │ │ ├── models_app.py # ORM: UserModel, ChartModel, JobModel...
│ │ │ └── connection.py # Pool de conexiones a BDs administradas
│ │ ├── services/
│ │ │ ├── jobs_engine.py # Motor de ejecución de pipelines
│ │ │ ├── jobs_service.py # CRUD + scheduler de jobs
│ │ │ ├── python_sandbox.py # Sandbox bwrap para python_transform
│ │ │ ├── charts_service.py
│ │ │ ├── reports_service.py
│ │ │ └── transform_blocks_service.py
│ │ ├── http/
│ │ │ └── middlewares/
│ │ │ └── audit_log.py # Middleware de logging por request
│ │ └── support/
│ │ └── audit_logger.py # Loggers por categoría con rotación
│ └── requirements.txt
│
├── frontend/ # React + Vite
│ ├── src/
│ │ ├── App.jsx # Shell principal + routing por tabs
│ │ ├── components/ # UI components
│ │ │ ├── SqlEditorTab.jsx
│ │ │ ├── JobCanvas.jsx # Canvas visual de pipelines
│ │ │ ├── JobEditorTab.jsx
│ │ │ ├── ChartsTab.jsx
│ │ │ └── ...
│ │ ├── api/client.js # Cliente HTTP (axios + manejo de errores)
│ │ ├── hooks/
│ │ │ └── useSqlCompletion.js # Autocompletado SQL por schema
│ │ ├── store/AppContext.jsx # Estado global (tabs, auth, theme)
│ │ └── utils/sqlUtils.js # Detección de bindings y modo de query
│ └── package.json
│
├── logs/ # Logs de la app (generados en runtime)
│ ├── ops.log
│ ├── security.log
│ ├── jobs.log
│ └── errors.log
│
├── job_outputs/ # Archivos generados por jobs
└── job_uploads/ # Archivos subidos para pasos file_input