Dos bugs encadenados. El segundo es mucho peor que el que se veía.
1. EL ERROR VISIBLE. RunBatchQuery leía conx_db_id del formulario y lo guardaba
bien, y después lo pisaba con cero. El struct del body solo tenía etiquetas
json, pero en multipart Fiber mapea por la etiqueta form: no encontraba
conx_db_id, dejaba el campo en cero — y BodyParser NO devuelve error cuando
no mapea nada, así que la rama se ejecutaba igual y sobreescribía el valor
bueno. De ahí el "conx_db_id inválido" con la conexión bien elegida en
pantalla. Reproducido con un test antes de tocar nada.
2. EL QUE NO SE VEÍA. El script se partía con split(';') y se descartaba todo
trozo que empezara con "--". En un script documentado, donde cada sentencia
va debajo de su encabezado en comentarios, eso se saltaba casi todo el
archivo en silencio. Con el .sql que lo destapó: de 10 sentencias reales
pasaban 3 — y una de esas tres era un fragmento corrupto, porque un punto y
coma dentro de un comentario había partido una sentencia al medio. Se
perdían los dos INSERT de alta y el ALTER TABLE, que era el único cambio
estructural del script.
Es decir: arreglar solo el bug 1 habría sido peor que dejarlo. El usuario
habría leído "3 consultas ejecutadas" y se habría ido tranquilo con la
migración a medio aplicar.
DividirSentenciasSQL parte respetando dónde el punto y coma no separa nada:
comentarios de línea (-- y #), de bloque, y cadenas con ' " ` incluyendo
escapes con barra y comillas duplicadas. Y en vez de descartar lo que empieza
con "--", pregunta si al trozo le queda SQL después de sacarle los comentarios
— un "--" adentro de una cadena ya no oculta la sentencia.
Mismo criterio en los dos lados: el front arma las sentencias y el backend
divide los archivos subidos, y las dos implementaciones dan las mismas 10 sobre
el archivo real.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Prepara el terreno para que el cliente cargue su propia cuenta de IA sin
que su clave quede en texto plano ni que el selector le muestre las de
los demás.
- ClaveEnClaro() descifra con fallback a texto plano: las filas viejas se
leen igual y quedan cifradas al primer guardado, sin script ni downtime.
utils.Decrypt hace panic (no devuelve error) con entrada que no es un
ciphertext válido, así que el fallback va sobre recover — eso mismo es
el mecanismo de detección de "todavía está en claro".
- Migrados TODOS los lectores: uMind (chat y embeddings), bot de Telegram,
Whisper, Query Runner, streaming de IA y Landing Generator. Un lector
sin migrar mandaría el ciphertext como API key.
- AiConfig gana TenantID (null = global del staff) y
GetAiConfigSelectPorTenants para acotar el selector.
- Test de los 4 casos del fallback, incluido hex válido que no descifra.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- GetSchemaRelations: trae todas las llaves foráneas de la base con
consulta específica por motor (Postgres/MySQL/MSSQL/SQLite). No
aplica a Redis/Mongo (schemaless).
- Endpoint GET /query-runner/relations, con el mismo chequeo de
autorización por conexión que ya usa RunQuery — de paso se lo
agrego también a GetDatabases/GetTables, que no lo tenían.
- UI: botón "Ver relaciones" (diagrama completo) y un ícono por tabla
en el árbol lateral (relaciones solo de esa tabla), renderizado con
Mermaid.js servido localmente (public/js/mermaid.min.js, sin CDN).
- Los seeds que creaban módulos nuevos asignaban esos submódulos a TODOS los
roles en cada arranque (idempotente contra re-agregar lo ya quitado, pero
igual tocaba roles personalizados/restringidos por primera vez apenas
existían). Ahora solo se asignan automáticamente al rol "Administrador";
cualquier rol restringido que crees para un empleado ya no recibe módulos
nuevos sin que tú se los habilites a propósito desde /app/roles.
- Se revierte el bloqueo "solo administrador" que había puesto en
/query-runner/run y /run-batch: bloqueaba también a usuarios con el
submódulo Query Runner correctamente asignado a su rol. En su lugar se
agrega la validación real que faltaba — RunQuery/RunBatchQuery no
verificaban que el conx_db_id recibido perteneciera al rol del usuario
(solo el listado de conexiones del selector estaba filtrado); ahora si no
es admin, se verifica contra Role.ConxDBs antes de ejecutar cualquier SQL.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- Agrega provider 'ollama' al panel de AiConfig con badge azul y hint de URL
- ia_controller: reemplaza webhook n8n hardcodeado por llamada directa a Ollama vía AiConfig (módulo 'ia')
- query_runner: agrega soporte explícito de ollama (model fallback gemma3:1b, Basic Auth para URL pública)
- HTML: agrega módulo 'IA / vCard' en el selector de módulos
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>