Notas de la versión

Todas las versiones publicadas de WUIC Framework, de la más reciente a la más antigua, con las notas completas de cada una.

Volver a las descargas

v1.7.21

Volver al índice

Versión anterior publicada: 1.7.20 (1 de octubre de 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


Versión dedicada a la seguridad y al acceso a los datos. Cierra los hallazgos de una revisión de seguridad completa del framework y lleva OData al mismo nivel de permisos que el CRUD. En resumen:

  • enableCookieAuthentication acepta un tercer valor, "signed": cookie firmada por el servidor, varias sesiones por usuario, cierre de sesión por sesión individual;
  • OData aplica los permisos de route y de columna, las restricciones de fila del usuario y escribe pasando por el CRUD del framework;
  • los tokens personales permiten conectar Power BI, Excel y scripts a los endpoints OData;
  • la opción "secure upload" de las columnas de upload vuelve a proteger los archivos de la columna;
  • la modificación y la eliminación respetan la restricción por usuario también en el CRUD de la interfaz;
  • los errores muestran al usuario un mensaje traducido con un código de seguimiento, los detalles técnicos solo al superadmin.

Los cambios en el esquema de los metadatos se aplican solos al arrancar. Las funcionalidades se verificaron con los tests end-to-end en SQL Server, MySQL, PostgreSQL y Oracle, en los tres modos de enableCookieAuthentication.


🔐 Autenticación y sesiones

  • Tres modos. enableCookieAuthentication vale false, true o "signed". Con false el usuario es el que declara la cookie del navegador: solo para desarrollo. Al arrancar un mensaje [security] lo indica, el editor AppSettings lo describe y pide confirmación al guardar. Un valor no reconocido vale como "signed", con aviso en el log.
  • "signed". El servidor firma la cookie k-user (HMAC-SHA256, caducidad dentro de la firma): una cookie modificada o caducada vale como ausente. El mismo usuario puede tener varias sesiones abiertas, cada una con su identificador.
  • Cierre de sesión y revocación. El cierre de sesión cierra solo la sesión desde la que se hace, incluidas las copias de la cookie. El cierre de sesión de un usuario hecho por un administrador, el restablecimiento y el cambio de contraseña cierran todas las sesiones de ese usuario en su empresa.
  • Duración máxima. Con signedSessionMaxLifetimeHours (24 por defecto, 0 = sin límite) una sesión firmada caduca a esa edad desde el inicio de sesión, aunque se use de forma continua.
  • Clave de firma. cookie-signing-key se genera en el primer arranque y se guarda en appsettings.json. Al arrancar el log muestra la huella de la clave (nunca la clave) y avisa si la clave no se ha guardado.
  • Llamadas verificadas en el servidor. Con false la cookie ya no lleva privilegios falsificados (administrador, rol, empresa): el usuario se vuelve a leer de la base de datos.

🔗 OData

  • Permisos. Cada entity set requiere el permiso de lectura sobre la route. Una columna denegada al usuario y citada en $select, $filter, $orderby o $expand responde 403; si no, vuelve vacía.
  • Restricciones de fila. La consulta parte del mismo SELECT que el CRUD con la restricción por usuario, rol o empresa, el filtro por defecto y la eliminación lógica. $filter, $orderby, $skip, $top y $count se aplican fuera y solo pueden restringir: or 1 eq 1 no amplía el resultado.
  • $expand. Admitido hacia routes legibles sin restricciones de fila ni eliminación lógica; 403 en los demás casos.
  • Escrituras. POST, PATCH y DELETE pasan por insertRecord, updateRecord y deleteRecord: permisos, columnas no modificables, triggers, campos de registro, change log, workflows y eliminación lógica valen como desde la interfaz. Una fila oculta al usuario responde 404.
  • Multiempresa. La conexión de datos es la de la empresa del usuario, como en el CRUD.
  • Descubrimiento. /odata, /odata/$metadata y /odata/openapi.json requieren la sesión. Con odataPublicMetadata=true vuelven a ser públicos; los datos siguen protegidos.
  • Tokens personales. Con apiTokensEnabled=true cada usuario crea desde el menú de usuario ("Tokens de API") tokens wuic_pat_… con nombre, caducidad (90 días por defecto, máximo apiTokenMaxLifetimeDays) y permiso de solo lectura o también de escritura. Solo valen en /odata, con los permisos del propietario. Power BI y Excel los usan como contraseña con credenciales "Basic"; los scripts con Authorization: Bearer. El token se ve una sola vez; el superadmin ve y revoca los de todos.

🛡️ Seguridad

Hardening best-effort en toda la superficie: controles sobre los valores que terminan en las consultas (ordenaciones, operadores, agregados, claves, filtros numéricos) alineados en los cuatro proveedores; rutas de upload y de informes confinadas en sus carpetas; funciones de administración (diseñador de informes, eliminación y scaffolding de informes, reordenación de columnas, reinicio, scaffold OData) reservadas al superadmin verificado en la base de datos; correos de los workflows solo de quien puede ejecutar el workflow; datos de ejemplo de las herramientas para asistentes de IA solo al superadmin y nunca con columnas de credenciales; protecciones sobre usuarios y roles ligadas a la tabla, no al nombre de la route; clave pública de la licencia incorporada en el paquete.

📎 Upload

  • "Secure upload" por columna. Los archivos de una columna con upload_secure solo se leen con una sesión válida y con la columna visible para el usuario, tanto desde /upload como desde /api/UploadImage. Los archivos de las demás columnas siguen siendo públicos. Las columnas que guardan el archivo en la base de datos están protegidas por /api/UploadImage.
  • Nombres de archivo. Se aceptan los nombres con puntos internos (factura-acme.com.pdf); siguen rechazándose los nombres con extensiones ejecutables por el servidor aunque estén en medio (foto.aspx.png).

🚦 Errores

Al usuario le llega un mensaje traducido con un código de seguimiento (botón "Copiar código" en el diálogo de error). El mismo código se registra con la pila completa en _error__logs. SQL, pilas y mensajes internos solo llegan al superadmin. Las traducciones de los nuevos mensajes de error se añaden solas al arrancar.

🐛 Correcciones destacadas

  • Restricción por usuario en modificación y eliminación. El UPDATE y el DELETE del CRUD solo contenían la clave: conociendo el id, un usuario podía modificar la fila de otro. Ahora la fila debe estar entre las que el usuario ve; si no, 403 errors.auth.route_read_forbidden.
  • Filtro por defecto con filtros en OR. Con el operador OR el filtro por defecto de la route desaparecía y la grid mostraba las filas que debía ocultar. Ahora se mantiene en AND.
  • Oracle. Booleanos escritos como 1/0 también en columnas con tipo UI booleano, en los filtros y en los parámetros de los procedimientos almacenados; funciones distinguidas de los procedimientos en el esquema correcto; OData sobre el esquema de datos incluso con el usuario SYSTEM (antes, errores ORA-00942 intermitentes).
  • PostgreSQL y Oracle. La inserción con una clave identity no enviada por el cliente ya no falla; los informes aplican los permisos y los filtros del usuario como en SQL Server y MySQL.
  • Primer arranque en IIS. La configuración inicial ya no devuelve un 500 tras una instalación correcta: las migraciones se completan al reiniciarse el worker.
  • Spreadsheet y sincronización. Con un filtro activo, la modificación y la eliminación afectaban a la fila equivocada; una selección más allá de la página ya no alcanza los registros de las páginas siguientes; el guardado por lotes del kanban y la sincronización sin conexión solo reintentan lo que ha fallado.
  • Menú. La barra aparece con las etiquetas ya traducidas, sin mostrar por un instante las claves.

📦 Paquetes actualizados

Paquete De A
WuicCore 1.7.20 1.7.21
Wuic.Webcore 1.7.20 1.7.21
WuicOData 1.7.20 1.7.21
RuntimeEfCore 1.7.20 1.7.21
Wuic.MySqlProvider 1.7.20 1.7.21
Wuic.PostgresProvider 1.7.20 1.7.21
Wuic.OracleProvider 1.7.20 1.7.21
wuic-framework-lib (npm) 1.7.20 1.7.21

🔧 Actualizaciones operativas recomendadas

  1. Modo de la cookie: en producción, configurar enableCookieAuthentication como "signed" (o true); false es solo para desarrollo.
  2. Varias instancias detrás de un balanceador: copiar la misma cookie-signing-key en todas las instancias; con claves distintas una sesión solo vale en la instancia que la creó. Comprobar en el log que la huella coincide.
  3. Clientes OData: los clientes que leían $metadata sin sesión deben autenticarse, o configurar odataPublicMetadata=true. Las escrituras OData ahora ejecutan los triggers y el registro del CRUD y, en las routes con eliminación lógica, marcan el indicador en lugar de eliminar la fila.
  4. md_service_apply_default_filter: obsoleto. El filtro por defecto se aplica siempre, también vía OData.
  5. Licencia: la sustitución de la huella de la máquina solo se configura con la variable de entorno WUIC_LICENSE_MACHINE_FINGERPRINT; las claves license-machine-fingerprint-override y license-public-key-pem de appsettings.json se ignoran.
  6. Tokens API: para conectar Power BI, Excel o scripts, configurar apiTokensEnabled=true (y opcionalmente apiTokenMaxLifetimeDays) desde el editor AppSettings.

v1.7.20

Volver al índice

Versión anterior publicada: 1.7.18 (1 de octubre de 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


Versión de corrección: reúne los defectos detectados al desarrollar una aplicación con los cinco patrones de desarrollo documentados, partiendo del proyecto de ejemplo de los paquetes de código fuente, y acelera el motor RAG en las máquinas sin GPU. Incluye también las correcciones de la 1.7.19, publicada solo como paquetes NuGet y npm: estas notas cubren ambas. En resumen:

  • volver a ejecutar el scaffolding con "Create Menu" ya no duplica la entrada de menú;
  • en PostgreSQL y Oracle se aplica la ordenación del lado del servidor solicitada por la cuadrícula, también cuando la lista lleva arriba un registro destacado;
  • con ng serve, las exportaciones también se descargan desde el servidor de desarrollo;
  • las búsquedas del motor RAG en CPU son hasta unas tres veces más rápidas en máquinas con pocos núcleos;
  • las páginas de los cinco patrones de desarrollo tienen ejemplos de código que compilan, en los cinco idiomas.

Ningún cambio en metadatos, traducciones o esquema de la base de datos: la actualización no requiere scripts.


🗄️ Proveedores PostgreSQL y Oracle

  • Ordenación del lado del servidor. Con las operaciones del lado del servidor activas, la ordenación elegida en una columna de la cuadrícula no llegaba a la consulta: los registros volvían siempre ordenados por clave primaria, incluso pidiendo orden descendente por otro campo. Ahora el ORDER BY usa las columnas solicitadas y añade la clave primaria solo como último criterio, como en SQL Server y MySQL.
  • Ordenación con un registro destacado. Cuando la lista lleva arriba un registro concreto, la ordenación solicitada se seguía descartando en la 1.7.19. Ahora el orden es: registro destacado, columnas solicitadas, clave primaria.

🤖 Motor RAG

  • Búsquedas más rápidas en CPU. Sin GPU, los hilos de cálculo de los modelos seguían activos en espera entre una operación y la siguiente, y el calentamiento de la caché en segundo plano se ejecutaba en paralelo a la primera búsqueda: en las máquinas con pocos núcleos competían por la CPU. Ahora los hilos ya no esperan de forma activa y los cálculos de los modelos se ejecutan de uno en uno dentro del proceso. Las búsquedas (chat y herramientas MCP) son hasta unas tres veces más rápidas en máquinas con pocos núcleos, y la primera búsqueda ya no se ralentiza por el calentamiento en curso. En los PC con núcleos libres los tiempos no cambian.

🐛 Correcciones destacadas

  • Entrada de menú duplicada en el scaffolding. Volver a ejecutar "Scaffold Table" o "Scaffold View" con "Create Menu" sobre una tabla o vista ya generada añadía una segunda entrada de menú para la misma ruta. Ahora la entrada se crea solo si la ruta todavía no tiene una.
  • Exportaciones con el servidor de desarrollo. En el proyecto cliente de los paquetes de código fuente, proxy.conf.js no reenviaba la ruta /Tmp_export al backend: con ng serve el enlace del archivo exportado (Excel, CSV, PDF) devolvía la página de la aplicación en lugar del archivo. Ahora la ruta se reenvía y la descarga funciona como en la instalación publicada.

📚 Documentación

Las páginas de los cinco patrones de desarrollo se han corregido en todos los idiomas:

  • Framework + manual: el ejemplo pasa la fuente de datos con [hardcodedDatasource] y establece [autoload]="true"; sin autoload la lista carga solo el esquema, no los registros.
  • Datos del framework + componente personalizado: nuevo ejemplo de setCurrent, addNewRecord, syncData y fetchData llamados desde el componente personalizado.
  • Componente del framework + datos personalizados: los filtros del lado del cliente construyen un filtro por columna, tal como lo lee la list-grid.
  • Full custom: el componente declara los imports necesarios (TableModule, CheckboxModule, ButtonModule, FormsModule).
  • Full autogeneration: la hoja de cálculo requiere la funcionalidad con licencia (sin ella, la ruta se abre como lista); el dashboard no es un arquetipo de ruta y la página ya no lo enumera entre las páginas generadas.

La documentación está incluida en la librería npm y publicada en el sitio web.

📦 Paquetes actualizados

Paquete De A
WuicCore 1.7.18 1.7.20
Wuic.Webcore 1.7.18 1.7.20
WuicOData 1.7.18 1.7.20
RuntimeEfCore 1.7.18 1.7.20
Wuic.MySqlProvider 1.7.18 1.7.20
Wuic.PostgresProvider 1.7.18 1.7.20
Wuic.OracleProvider 1.7.18 1.7.20
wuic-framework-lib (npm) 1.7.18 1.7.20

Quien ya haya actualizado los paquetes a la 1.7.19 encuentra en la 1.7.20, además, la ordenación con un registro destacado, el motor RAG más rápido y la corrección de la página del patrón full autogeneration.

🔧 Actualizaciones operativas recomendadas

  1. Proyectos creados a partir de los paquetes de código fuente: la actualización de los paquetes no sobrescribe el proxy.conf.js del proyecto. Añadir la entrada '/Tmp_export' con la misma configuración que las demás entradas hacia el backend (o copiarla del proxy.conf.js del paquete) y reiniciar ng serve.
  2. Menús duplicados: si al volver a ejecutar el scaffolding con una versión anterior aparecieron entradas de menú dobles, eliminar las sobrantes desde la gestión del menú.
  3. PostgreSQL y Oracle: ninguna acción; tras la actualización, las cuadrículas con operaciones del lado del servidor ordenan según lo solicitado.
  4. Motor RAG: ninguna acción; el motor actualizado está en la carpeta rag-engine del paquete y la corrección se aplica a la ejecución en CPU.

v1.7.18

Volver al índice

Versión anterior publicada: 1.7.17 (30 de septiembre de 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


Versión de corrección: reúne los defectos detectados al instalar la 1.7.17 desde cero en máquinas limpias, con las cuatro bases de datos soportadas. En resumen:

  • las herramientas MCP de búsqueda ya no agotan el tiempo de espera mientras se carga el motor RAG;
  • en PostgreSQL el motor RAG vuelve a cargarse solo tras el arranque;
  • en Oracle XE 21c el scaffolding de tablas y vistas vuelve a escribir los metadatos, también en el primer arranque;
  • los stack trace enviados por el crash reporting se reconstruyen por completo.

Ningún cambio en metadatos, traducciones ni esquema de la base de datos: la actualización no requiere scripts.


⚠️ Comportamientos que cambian

  • Herramientas MCP durante la carga del motor. wuic_codebase_search y wuic_ask esperan hasta 30 segundos (antes 60) a que el motor RAG esté listo; si todavía no lo está responden con un error que pide reintentar en unos 60 segundos. La carga continúa en el backend, y la llamada repetida encuentra el motor listo.

🤖 Motor RAG

  • Timeout de las herramientas MCP. Mientras el motor se cargaba, el servidor MCP lanzaba una búsqueda de calentamiento que se ejecutaba en paralelo con la búsqueda real: en una máquina sin GPU las dos se ralentizaban mutuamente y la llamada superaba los 120 segundos de espera del cliente, también en Windows. Ahora el servidor MCP solo inicia la carga y la espera, y la búsqueda real dispone de todo el tiempo del cliente.
  • /api/Rag/Health inicia siempre la carga. El endpoint inicia la carga del motor en segundo plano incluso cuando no encuentra un usuario administrador al que notificar el progreso: en ese caso el motor se carga sin notificaciones.
  • PostgreSQL. La búsqueda del administrador fallaba en PostgreSQL, donde isAdmin es un campo boolean: el motor nunca arrancaba desde /api/Rag/Health y las herramientas MCP se quedaban "cargando". Ahora el administrador se encuentra y el motor arranca como en las demás bases de datos.

🗄️ Proveedor Oracle

  • Scaffolding en Oracle XE 21c. Las versiones recientes del driver de Oracle envían los valores true/false como tipo BOOLEAN, que Oracle anterior a la 23 rechaza (ORA-00932). El scaffolding de tablas y vistas (desde la interfaz y en el primer arranque) respondía con un error y el primer arranque terminaba sin los metadatos de las tablas de la aplicación. Ahora los flags de los metadatos se escriben como 0/1, que las columnas NUMBER de las tablas de metadatos aceptan en cualquier versión de Oracle.

🐛 Correcciones destacadas

  • Crash reporting, stack trace ilegibles. Con CrashReporting:Enabled=true los stack trace enviados por las instalaciones no se reconstruían en el receiver: los nombres internos del framework seguían ilegibles y el análisis de los fallos se resentía. Desde la 1.7.18 los informes se reconstruyen por completo. Ningún cambio en la configuración ni en los datos enviados.

📦 Paquetes actualizados

Paquete De A
WuicCore 1.7.17 1.7.18
Wuic.Webcore 1.7.17 1.7.18
WuicOData 1.7.17 1.7.18
RuntimeEfCore 1.7.17 1.7.18
Wuic.MySqlProvider 1.7.17 1.7.18
Wuic.PostgresProvider 1.7.17 1.7.18
Wuic.OracleProvider 1.7.17 1.7.18
wuic-framework-lib (npm) 1.7.17 1.7.18

🔧 Actualizaciones operativas recomendadas

  1. Asistentes de código con el servidor MCP de WUIC: en una instalación existente el workspace contiene la copia anterior de scripts/mcp/wuic-rag-mcp.mjs. Sustituirla por la del paquete (llm-workspace/templates/app-llm-workspace/scripts/mcp/) o regenerar el workspace como se describe en llm-workspace/README.md, y después reiniciar el cliente MCP.
  2. Oracle XE 21c: si un primer arranque con la 1.7.17 o anteriores terminó sin los metadatos de las tablas de la aplicación, repetir el scaffolding de esas tablas desde la interfaz tras la actualización.
  3. Crash reporting: quien lo usa no tiene que hacer nada; los informes de versiones anteriores quedan como están, los nuevos se leen por completo.

v1.7.17

Volver al índice

Versión anterior publicada: 1.7.16 (29 de septiembre de 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


Versión de corrección: reúne los defectos detectados al instalar la 1.7.16 desde cero en máquinas limpias, Windows y Linux. En resumen:

  • el mapa ya no carga Google Maps con una clave falsa cuando no se ha configurado ninguna clave;
  • el motor RAG se carga mucho más rápido en el primer uso, y se puede cargar al arrancar;
  • las herramientas MCP de búsqueda esperan al motor en lugar de agotar el tiempo;
  • el AppSettings Editor se abre en pocos segundos;
  • el row template de la list-grid ya no se rompe en la primera carga directa de una página.

Ningún cambio en metadatos, traducciones o esquema de la base de datos: la actualización no requiere scripts.


⚠️ Comportamientos que cambian

  • Clave de Google Maps no configurada. El valor de instalación __SET_GOOGLE_MAPS_API_KEY__, si no se ha sustituido, ahora cuenta como clave ausente: el mapa muestra el aviso de clave ausente. Antes el navegador cargaba Google Maps con ese texto como clave (InvalidKeyMapError y errores internos de Google en la consola). Se aplica a cualquier valor de la forma __SET_...__ en GoogleMaps:ApiKey.
  • Herramientas MCP durante la carga del motor. wuic_codebase_search y wuic_ask esperan hasta 60 segundos a que el motor RAG esté listo; si todavía no lo está, responden con un error que pide volver a intentarlo en unos 60 segundos, en lugar de dejar que la llamada del cliente agote el tiempo.

🤖 Motor RAG

  • Primer uso más rápido. El calentamiento del motor tras la carga ejecutaba una búsqueda completa, unas 35 pasadas del reranker: en una máquina Linux sin GPU suponía unos 133 de los 139 segundos de la carga en frío. Ahora hace una sola pasada del embedder y una del reranker sobre un texto corto. Los resultados de las búsquedas no cambian.
  • Carga al arrancar, opcional. Nueva clave AppSettings:rag-engine-eager-load (por defecto false). Con true, si los modelos ya están descargados, el backend carga el motor en segundo plano al arrancar, sin notificaciones, y la primera búsqueda (chat o MCP) no paga la carga en frío. El coste es la RAM del motor, 4,5-6,5 GB, ocupada aunque no se use el RAG. Con false el motor se carga en la primera petición, como antes.
  • Servidor MCP. La espera del motor está en el servidor MCP que el primer arranque instala en el workspace para los asistentes de código (scripts/mcp/wuic-rag-mcp.mjs). Mientras espera, el propio servidor inicia la carga del motor en el backend.

🐛 Correcciones destacadas

  • AppSettings Editor lento al abrirse. Con muchas claves el editor podía tardar decenas de segundos en aparecer tras la respuesta del servidor, porque cada pulsación o actualización de un campo de texto volvía a comprobar todo el editor y recalculaba todas las etiquetas traducidas. Ahora cada campo de texto se actualiza por su cuenta y las etiquetas se calculan una sola vez: la apertura baja a pocos segundos.
  • List-grid, row template en la primera carga. Al abrir directamente la URL de una página con una list-grid alimentada por un datasource que responde enseguida (endpoint personalizado, hardcodedDatasource), los datos podían llegar antes de que la aplicación publicara los imports del row template (gridRowImports). El template compilado sin esos pipes quedaba en caché y las filas no se mostraban (en producción, error onDestroy sobre undefined). Ahora la grid compila el row template después de la publicación de los imports; si la aplicación no los publica nunca, compila sin ellos pasados 10 segundos, como antes.

📦 Paquetes actualizados

Paquete De A
WuicCore 1.7.16 1.7.17
Wuic.Webcore 1.7.16 1.7.17
WuicOData 1.7.16 1.7.17
RuntimeEfCore 1.7.16 1.7.17
Wuic.MySqlProvider 1.7.16 1.7.17
Wuic.PostgresProvider 1.7.16 1.7.17
Wuic.OracleProvider 1.7.16 1.7.17
wuic-framework-lib (npm) 1.7.16 1.7.17

🔧 Actualizaciones operativas recomendadas

  1. Mapas: comprobar que GoogleMaps:ApiKey contiene una clave real. Si todavía contiene __SET_GOOGLE_MAPS_API_KEY__, tras la actualización los mapas muestran el aviso de clave ausente: es el comportamiento esperado hasta que se configure la clave.
  2. RAG en servidores dedicados: quien use el chat o las herramientas MCP justo después de cada reinicio y tenga RAM suficiente puede configurar "rag-engine-eager-load": "true" en AppSettings. En máquinas compartidas, dejar el valor por defecto.
  3. Asistentes de código con el servidor MCP de WUIC: en una instalación existente el workspace contiene la copia anterior de scripts/mcp/wuic-rag-mcp.mjs. Para tener la espera del motor, sustituirla por la del paquete (llm-workspace/templates/app-llm-workspace/scripts/mcp/) o regenerar el workspace como se describe en llm-workspace/README.md. Un cliente que recibe la petición de reintentar simplemente debe repetir la llamada.

v1.7.16

Volver al índice

Versión anterior publicada: 1.7.15 (28 de septiembre de 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


Esta versión corrige los defectos encontrados en una prueba de estrés con 100 usuarios sobre las cuatro bases de datos instaladas en Linux, y reduce el trabajo que el servidor hace en cada petición. En resumen:

  • columnas geográficas escritas correctamente en Oracle y PostgreSQL, con formatos de punto documentados y un error 400 para los valores no válidos;
  • un texto más largo que la columna responde 400 en lugar de 500;
  • Oracle mucho más rápido bajo carga;
  • límite de intentos de login por IP configurable.

Cómo se ha verificado. 100 usuarios virtuales durante 10 minutos (listas, filtros, ordenaciones, inserciones, modificaciones, borrados, importación, exportación, informes) en SQL Server, MySQL, PostgreSQL y Oracle Free, cada uno en Ubuntu 24.04 con nginx: entre 11.340 y 11.490 operaciones por base de datos, 0 errores HTTP y ninguna fila en el log de errores de la aplicación. Cuando un punto se ha verificado de otra forma, se indica.


⚠️ Comportamientos que cambian

  • Límite de login por IP desactivado por defecto. Hasta la 1.7.15 era fijo en 30 intentos por minuto por IP. Ahora vale loginRateLimitPerIpPerMinute, por defecto 0 (desactivado). El límite por usuario (5 contraseñas erróneas en 5 minutos) sigue siempre activo. En las instalaciones expuestas a internet configurar 30.
  • Posición no válida rechazada. Un valor de una columna point en un formato no reconocido responde ahora HTTP 400 errors.input.geo_point.invalid y el registro no se guarda. Antes SQL Server y MySQL guardaban NULL sin error, Oracle y PostgreSQL respondían 500. Un valor vacío guarda NULL como antes.
  • Texto demasiado largo: 400. Un texto más largo que la columna física responde HTTP 400 errors.input.value_too_long (o errors.input.value_too_long.column con args.column, cuando la base de datos nombra la columna) en lugar de 500 errors.db.sql_exception.
  • Última actividad de la sesión. LastActivityDate se actualiza como máximo una vez por minuto por usuario, ya no en cada petición. La caducidad de la sesión puede desplazarse como máximo 60 segundos.
  • Caché de sys_info en todas las bases de datos. Antes solo SQL Server mantenía la fila en caché durante 5 segundos; ahora también MySQL, PostgreSQL y Oracle. Un cambio hecho desde fuera (SQL a mano, otro nodo) se ve en 5 segundos, y un aumento de project_metadata_version hecho por otro nodo vacía ahora las cachés de metadatos también en estas tres bases de datos.
  • Oracle, instalaciones nuevas. El primer arranque crea en cada esquema cargado el trigger de logon WUIC_SESSION_CURSOR_SHARING (ver la sección Oracle).

🛡️ Seguridad

Best-effort hardening: límite de intentos de login por IP configurable (loginRateLimitPerIpPerMinute, respuesta HTTP 429 errors.auth.login_rate_limited con retryAfterSeconds) con una lista de IP exentas (loginRateLimitExemptIps, IP separadas por comas, tratadas como el loopback: nunca limitadas ni contadas), ambas leídas en cada login; en PostgreSQL y Oracle las consultas que leen usuarios y roles por id, nombre de usuario o email pasan los valores como parámetros en lugar de concatenarlos en el texto SQL.

🗺️ Columnas geográficas

  • Oracle: toda inserción o modificación con una columna point o geometry con valor fallaba (ORA-50028), porque el proveedor escribía la sintaxis de SQL Server. Ahora el valor se convierte a WKB (SRID 0, el mismo formato que los datos del tutorial) y se pasa como parámetro.
  • PostgreSQL: el mismo defecto, toda inserción o modificación con una posición con valor fallaba. Ahora el valor se escribe con ST_GeomFromText (SRID 0).
  • Formatos aceptados para las columnas point: JSON {"lat": 45.4642, "lng": 9.19} (también lon/long), par 45.4642, 9.19 (latitud, longitud), WKT POINT(9.19 45.4642) (longitud, latitud), texto Lat: 45.4642, Long: 9.19. El separador decimal es el punto. En lectura la posición vuelve siempre como JSON.
  • Valores no válidos: HTTP 400 errors.input.geo_point.invalid con la columna y el valor recibido. En Oracle las columnas geometry aceptan WKT POINT, POLYGON y MULTIPOLYGON de dos dimensiones; un WKT no válido responde errors.input.geo_wkt.invalid. Mensajes traducidos a los 5 idiomas.

Verificación: una prueba end-to-end en las cuatro bases de datos inserta y modifica una posición en cada uno de los cuatro formatos y la vuelve a leer con las coordenadas esperadas, comprueba que un valor no válido se rechaza con 400 sin tocar el dato y que un valor vacío guarda NULL.

🗄️ Oracle bajo carga

  • Primer arranque: tras cargar cada esquema el framework crea el trigger de logon WUIC_SESSION_CURSOR_SHARING, que establece CURSOR_SHARING = FORCE para las sesiones de la aplicación, y recoge las estadísticas del esquema (DBMS_STATS.GATHER_SCHEMA_STATS). Si uno de los dos pasos falla, el error va al log y el primer arranque continúa.
  • Autenticación: el id de usuario se compara con la columna sin TO_CHAR, así Oracle usa el índice de la clave en lugar de leer toda la tabla de usuarios en cada petición.
  • Lectura de las columnas espaciales: el BLOB se convierte a JSON o WKT en el servidor de aplicaciones después de la lectura, ya no con una función PL/SQL ejecutada fila por fila.
  • Clave MAX: con inserciones simultáneas en tablas padre e hija, el bloque que calcula la clave podía terminar en deadlock (ORA-00060). Ahora reintenta hasta 3 veces.

Medido con la misma carga, antes y después de estos cambios (incluidos los de la sección siguiente), en una instalación existente a la que se aplicaron a mano trigger y estadísticas: tiempo de base de datos en sentencias SQL de 794 a 61 segundos, hard parse de 73.719 a 7.379, CPU de Oracle en el percentil 95 del 26,5 % al 6,4 %. En el percentil 95 las listas pasan de 1,6 s a 0,16 s, la lectura de un registro de 1,28 s a 68 ms, getTableMetadata de 1,95 s a 0,32 s.

⚡ Menos trabajo por petición

  • sys_info: la fila se volvía a leer unas 7 veces por petición en MySQL, PostgreSQL y Oracle (en MySQL el 23,7 % del tiempo de la base de datos en la prueba de estrés). Ahora se lee como máximo una vez cada 5 segundos por tenant, en todas las bases de datos.
  • LastActivityDate: el UPDATE en cada petición autenticada suponía el 34,7 % del tiempo de la base de datos en MySQL. Ahora se ejecuta como máximo una vez por minuto por usuario, en todas las bases de datos; los segundos desde la última actividad los calcula la base de datos, con su propio reloj.
  • PostgreSQL: en el primer arranque, tras cargar los scripts, el framework ejecuta ANALYZE, así las primeras consultas no se planifican sin estadísticas. El instalador Linux hace lo mismo.
  • Informes: cada impresión escribía una fila "report call" en el log de errores (_error__logs). Ya no la escribe.

🐛 Correcciones destacadas

  • PostgreSQL, filtros sobre columnas boolean: un filtro sobre una columna boolean nativa fallaba con 42883: operator does not exist: boolean = integer.
  • PostgreSQL, errores SQL en las listas: llegan al cliente como errors.db.sql_exception con el código SQLSTATE, en lugar de errors.server.unhandled.
  • Change log de borrados y modificaciones: en MySQL el change log de los borrados no se escribía nunca. En MySQL y SQL Server la fecha se pasaba como texto y la conversión dependía del idioma del servidor (en SQL Server sobre Linux fallaba en cada borrado). Ahora la fecha es un parámetro tipado.
  • Uploads guardados en la base de datos: modificar un registro con una columna de upload en base de datos cuyo nombre tiene mayúsculas fallaba en PostgreSQL (42703). El nombre de la columna ahora va entre comillas, y lo mismo vale en MySQL y SQL Server.
  • MySQL, ordenación por defecto: en una tabla sin clave en los metadatos la lista se ordenaba por la primera columna aunque fuera espacial o binaria, con Out of sort memory. Ahora las columnas espaciales y binarias quedan excluidas.
  • MySQL, índices de los metadatos: el script que crea los índices sobre rutas y columnas de los metadatos fallaba en cada arranque y los índices nunca se creaban. Ahora se crean al arrancar.
  • Longitud máxima en los metadatos: mc_max_length de las columnas nvarchar/nchar se registraba en bytes, es decir el doble de los caracteres: en los formularios se podía escribir hasta el doble de caracteres y luego el guardado fallaba. Ahora el scaffolding registra caracteres y en los scripts del primer arranque las longitudes son las físicas: 127 columnas corregidas en el tutorial de SQL Server (incluidas las vistas del tutorial y tablas de sistema como _mail_recipients, _mailing_lists, _notifications, _wuic_workflow_instance_log y scheduler_execution), 21 en el perfil mínimo de SQL Server, 41 en MySQL, 34 en PostgreSQL y 34 en Oracle. El control de la longitud máxima en los formularios corresponde ahora a la columna.
  • Tutorial, archivo de temperaturas: en SQL Server la primera página de la lista de Warehouse.ColdRoomTemperatures_Archive (3,65 millones de filas) agotaba el tiempo de espera bajo carga. Dos índices creados al arrancar la llevan de 5,4 s a 6 ms (medido en SQL Server sobre Linux). En MySQL, PostgreSQL y Oracle se crea al arrancar un índice sobre la clave; allí el caso no se ha medido.

🐧 Instalador Linux

  • nginx: worker_connections 4096, worker_rlimit_nofile 16384, y conexiones keep-alive hacia Kestrel en lugar de una conexión nueva por cada petición (WebSocket sin cambios).
  • Bases de datos: MySQL y PostgreSQL con 300 conexiones y buffers al 25 % de la RAM (entre 128 MB y 8 GB), Oracle Free con PROCESSES 400 (un reinicio del contenedor durante la instalación). SQL Server sigue siendo Express.
  • Están pensados para algunos cientos de usuarios: con 100 usuarios los valores por defecto aún bastaban (MySQL 59 conexiones de 151, Oracle 148 procesos de 200). La prueba de estrés descrita arriba se ejecutó con los valores anteriores; estos pasos del instalador todavía no se han probado en una instalación desde cero.
  • Una instalación existente conserva los valores anteriores. Los comandos para subirlos a mano están en el README del tarball Linux, sección "Capacity for hundreds of concurrent users".

📦 Paquetes actualizados

Paquete De A
WuicCore 1.7.15 1.7.16
Wuic.Webcore 1.7.15 1.7.16
WuicOData 1.7.15 1.7.16
RuntimeEfCore 1.7.15 1.7.16
Wuic.MySqlProvider 1.7.15 1.7.16
Wuic.PostgresProvider 1.7.15 1.7.16
Wuic.OracleProvider 1.7.15 1.7.16
wuic-framework-lib (npm) 1.7.15 1.7.16

🔧 Actualizaciones operativas recomendadas

  1. Instalaciones expuestas a internet: configurar en AppSettings "loginRateLimitPerIpPerMinute": "30", el valor fijo de la 1.7.15. Para pruebas de estrés desde una sola IP añadir esa IP a loginRateLimitExemptIps.
  2. Clientes que gestionan los códigos de error: un texto demasiado largo y una posición no válida llegan ahora como HTTP 400 con los códigos errors.input.value_too_long, errors.input.value_too_long.column y errors.input.geo_point.invalid. En todas las bases de datos las instalaciones nuevas tienen los mensajes de los cuatro nuevos códigos (errors.input.geo_point.invalid, errors.input.geo_wkt.invalid, errors.input.value_too_long, errors.input.value_too_long.column) traducidos a los 5 idiomas; en una instalación existente aparece el mensaje de reserva hasta que se añaden las traducciones desde la gestión de traducciones de la interfaz.
  3. Oracle, instalaciones existentes: para tener el trigger y las estadísticas de las instalaciones nuevas, ejecutar como usuario de cada esquema (datos y metadatos):
    CREATE OR REPLACE TRIGGER WUIC_SESSION_CURSOR_SHARING AFTER LOGON ON SCHEMA
    BEGIN EXECUTE IMMEDIATE 'ALTER SESSION SET CURSOR_SHARING = FORCE';
    EXCEPTION WHEN OTHERS THEN NULL; END;
    /
    BEGIN DBMS_STATS.GATHER_SCHEMA_STATS(ownname => SYS_CONTEXT('USERENV', 'CURRENT_SCHEMA')); END;
    /
    
    Para volver al comportamiento anterior: DROP TRIGGER WUIC_SESSION_CURSOR_SHARING.
  4. Linux con muchos usuarios simultáneos: en una instalación existente subir los límites de nginx y de la base de datos con los comandos del README del tarball Linux.
  5. Tutorial en SQL Server: el primer arranque tras la actualización construye dos índices sobre Warehouse.ColdRoomTemperatures_Archive (15-25 segundos cada uno, medidos): ese arranque dura más, una sola vez.
  6. Varios nodos sobre la misma base de datos: los cambios en sys_info hechos por un nodo llegan a los demás en 5 segundos.
  7. Longitudes en los metadatos, instalaciones existentes: los metadatos ya presentes no se corrigen automáticamente. Quien quiera alinearlos puede relanzar el scaffolding de la tabla o fijar mc_max_length de la columna al número de caracteres.

v1.7.15

Volver al índice

Versión anterior publicada: 1.7.14 (25 de septiembre de 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


Esta versión corrige los defectos detectados por la prueba de carga de la 1.7.14 y por una campaña de pruebas en instalaciones limpias de las cuatro bases de datos (SQL Server, MySQL, PostgreSQL, Oracle). En resumen:

  • abrir una ruta es unas diez veces más rápido bajo carga;
  • las claves MAX ya no se duplican con inserciones simultáneas, y en SQL Server una exportación ya no bloquea las escrituras;
  • la importación y la exportación son portables entre bases de datos, con defectos corregidos en Oracle y PostgreSQL;
  • el cierre de sesión en Oracle ahora cierra realmente la sesión.

🛡️ Seguridad

Cierre de sesión en Oracle. En Oracle el cierre de sesión no invalidaba el token de sesión: tras cerrar sesión, la misma cookie seguía leyendo los datos. Ahora el cierre de sesión cierra la sesión también en Oracle. Quien use Oracle debería actualizar.

⚡ Rendimiento

Metadatos al abrir una ruta. La lectura de los metadatos de una ruta (getTableMetadata) es unas diez veces más rápida. Los permisos por usuario, rol y empresa se evalúan sin compilar una expresión por cada columna, y la serialización reutiliza su configuración en lugar de reconstruirla en cada llamada. El resultado no cambia: mismos permisos, mismo JSON.

En el servidor de demostración (SQL Server, 100 usuarios simultáneos) el percentil 95 de la llamada bajó de 2,4-4,5 s a 0,2-0,4 s, y el percentil 95 de la CPU del proceso del 54 % al 31 %.

🔑 Clave primaria MAX

En las rutas con md_primary_key_type = "MAX" la clave de una fila nueva es el máximo + 1. Hasta la 1.7.14 el máximo se leía con una consulta separada del insert: dos usuarios que guardaban en el mismo instante podían recibir la misma clave, y el segundo guardado fallaba por una violación de clave primaria.

  • El máximo se calcula ahora dentro del insert, con un bloqueo de la tabla hasta el commit: las inserciones simultáneas reciben claves consecutivas.
  • Vale también para la «clave dependiente» de las claves compuestas (máximo + 1 por cada valor de la clave padre).
  • Vale para la inserción desde el formulario, la duplicación de un registro y la importación desde Excel.
  • El mecanismo de bloqueo depende de la base de datos: UPDLOCK, HOLDLOCK en SQL Server, SELECT ... FOR UPDATE en MySQL, un advisory lock de transacción en PostgreSQL, LOCK TABLE ... IN EXCLUSIVE MODE en Oracle.

Una importación que inserta filas nuevas en una tabla con clave MAX mantiene el bloqueo hasta el final del archivo: mientras tanto las demás inserciones en la misma tabla esperan, y en Oracle también modificaciones y borrados.

📤 Exportación en SQL Server

Una exportación lee la tabla durante todo el tiempo en que escribe el archivo. Con el aislamiento predeterminado de SQL Server esa lectura bloqueaba inserciones y modificaciones en la misma tabla hasta el final de la exportación (medido: un update en espera durante 5,5 s mientras se exportaban 70.000 filas).

  • Si la base de datos tiene ALLOW_SNAPSHOT_ISOLATION ON, la exportación lee en aislamiento snapshot y las escrituras ya no esperan (mismo update: unos 100 ms). El archivo contiene los mismos datos.
  • La opción vale solo para la exportación: las demás lecturas no cambian de comportamiento. Convive con READ_COMMITTED_SNAPSHOT ON.
  • Sin la opción la exportación funciona como antes.
  • La base de datos del tutorial se crea con READ_COMMITTED_SNAPSHOT ON, que elimina el mismo bloqueo también en las lecturas de las grillas.

📥 Importación y exportación entre bases de datos

  • Oracle, lookups en la exportación. En las columnas lookup la exportación escribía la clave en lugar de la descripción (por ejemplo 16 en lugar del nombre de la persona). El archivo no se volvía a importar: «no record of 'people' has this description». Ahora la exportación escribe la descripción, y el ciclo exportar → modificar → importar funciona en Oracle como en las demás bases.
  • PostgreSQL, importación. Cada importación que buscaba filas existentes por clave fallaba con 42883: operator does not exist: integer = text. La clave leída del archivo se convierte ahora al tipo de la columna.
  • Encabezados portables. La columna clave de un lookup (modo clave + descripción) y los paréntesis que distinguen dos columnas con la misma etiqueta usan ahora el nombre de la columna en los metadatos WUIC, igual en todas las bases, y no el nombre físico (en Oracle en mayúsculas, por ejemplo CONTACTPERSONID). Un archivo exportado desde una base se importa en otra. Los archivos exportados antes, con el nombre físico, se importan como antes.

🌐 Página «Traducciones de datos»

La página de administración de las traducciones de registros (_record_field_translations) muestra ahora las traducciones guardadas, con los nombres de tabla y de usuario, en las cuatro bases de datos.

  • MySQL: la lista respondía con un error de la base de datos.
  • Oracle: la lista fallaba con ORA-00942, porque las tablas de usuarios y de metadatos están en otro esquema. El framework ahora califica el esquema y concede al usuario de datos el SELECT necesario en el primer uso.
  • PostgreSQL: la lista leía la tabla equivocada y no mostraba las traducciones guardadas. Ahora lee la de la base de datos de la aplicación. Como PostgreSQL no une tablas de bases distintas, los nombres de usuarios y tablas se leen con una consulta separada. La ordenación y la agrupación en estas columnas trabajan sobre la clave.

🗄️ Oracle

  • Reinstalación sobre una base existente. En el primer arranque, la confirmación de volver a crear la base fallaba con ORA-01940 si el usuario aún tenía sesiones abiertas. Ahora las sesiones se cierran y se esperan antes del DROP USER.
  • Metadatos del tutorial. Los metadatos del tutorial Oracle están alineados con los de SQL Server: descripciones de los lookups y otras propiedades de las columnas. Vale para las instalaciones nuevas del tutorial.

🐛 Correcciones destacadas

  • Editor de código SQL: en MySQL, PostgreSQL y Oracle las sugerencias de esquemas, tablas y columnas llegaban vacías. Ahora están completas.
  • Caché de datos: con cacheDataMinutes activo, el recuento de filas en caché no caducaba nunca, y una entrada caducada ya no volvía a la caché. Filas y recuentos caducan ahora tras el tiempo configurado.
  • Pivot: guardar por segunda vez la misma configuración pivot respondía 500.
  • Agrupación (SQL Server): agrupar en el servidor sin agregados respondía 500.
  • Instalador de Windows (IIS): en algunos casos la aplicación arrancaba antes de que el sitio estuviera configurado y quedaba en error hasta reciclar el pool. El instalador ahora recicla el pool antes de iniciar el sitio.

📦 Paquetes actualizados

Paquete De A
WuicCore 1.7.14 1.7.15
Wuic.Webcore 1.7.14 1.7.15
WuicOData 1.7.14 1.7.15
RuntimeEfCore 1.7.14 1.7.15
Wuic.MySqlProvider 1.7.14 1.7.15
Wuic.PostgresProvider 1.7.14 1.7.15
Wuic.OracleProvider 1.7.14 1.7.15
wuic-framework-lib (npm) 1.7.14 1.7.15

🔧 Actualizaciones operativas recomendadas

  1. SQL Server, exportación sin bloqueos: ejecutar una vez ALTER DATABASE [<base de datos>] SET ALLOW_SNAPSHOT_ISOLATION ON. La opción aumenta el uso de tempdb mientras haya transacciones abiertas.
  2. Importaciones grandes en tablas con clave MAX muy usadas: poner la clave en el archivo, o pasar la tabla a IDENTITY/SEQUENCE, para no mantener el bloqueo durante toda la importación.
  3. Página «Traducciones de datos» en instalaciones existentes de MySQL, PostgreSQL y Oracle: en los metadatos de tablas, la ruta _record_field_translations debe usar la conexión DataSQLConnection y no ser una ruta de sistema. Las instalaciones nuevas ya lo tienen así.
  4. Oracle: actualizar, aunque solo sea por el cierre de sesión.

v1.7.14

Volver al índice

Versión anterior publicada: 1.7.13 (24 de septiembre de 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


Esta versión nace de una prueba de carga con muchos usuarios simultáneos en una instalación pública: exportación e importación del mismo archivo, filtros, ordenaciones, informes. La exportación es cuatro veces más rápida y pasa por una cola que protege el servidor; la importación vuelve a leer correctamente los archivos producidos por la exportación, también con lookups resueltos a partir de una descripción repetida. También se corrigen dos defectos de las grids con lookups y columnas geográficas.


📤 Exportación

  • Más rápida y más ligera. Una exportación XLSX de 230.000 filas pasa de 28,5 s a 7,4 s y de 12,2 GB a 2,3 GB de memoria asignada. El contenido del archivo no cambia.
  • Cola de exportaciones. El servidor ejecuta como máximo maxConcurrentExports exportaciones a la vez (por defecto: la mitad de los núcleos, al menos 1). Las demás esperan por orden de llegada, hasta maxQueuedExports (por defecto 10). Por encima, la petición responde 503 errors.metaservice.export.queue_full.
  • Espera visible. Mientras la exportación está en cola, el diálogo de progreso y la campana de notificaciones muestran "En cola: posición N". Una exportación en cola se puede cancelar.
  • Ajustes con efecto inmediato. Las dos claves están en el editor de ajustes (sección App Runtime) y se leen en cada exportación, sin reinicio.
  • Nombre de archivo único. Dos exportaciones de la misma ruta iniciadas en el mismo segundo ya no escriben el mismo archivo (antes todas menos una respondían 500).

📥 Importación

Columnas lookup en el archivo: fkey_mode. Una ruta importable elige cómo aparecen sus columnas lookup en el archivo, con import.fkey_mode en el props bag de la ruta:

  • description (por defecto): la descripción, como en la grid;
  • key: el valor de la clave;
  • both: ambas, la descripción bajo el título de la columna y la clave bajo el nombre físico.

El diálogo de importación muestra la opción preseleccionada y permite cambiarla para una sola importación. La exportación sigue la misma opción, así que un archivo exportado se vuelve a importar tal cual. use_descriptive_fkey sigue aceptándose desde los clientes que no conocen fkey_mode.

Encabezados. Cada columna tiene su título como encabezado. Solo cuando dos columnas del mismo archivo tienen el mismo título aparece entre paréntesis el nombre físico de la columna.

Reglas para los lookups leídos desde la descripción.

  • Descripción única: se usa su clave.
  • Descripción compartida por varios registros: en una actualización el registro conserva su clave actual, si es una de las posibles; en los demás casos la fila se rechaza con la lista de claves candidatas.
  • Clave y descripción en el mismo archivo que no coinciden: la fila se rechaza.

Otras correcciones.

  • Las celdas de fecha de Excel se leen como fechas: un archivo exportado y reimportado sin cambios ya no se rechaza.
  • Una clave primaria que también es lookup se resuelve antes de la comprobación de existencia del registro.
  • La comprobación de existencia usa parámetros SQL en lugar de concatenar los valores del archivo.

🐛 Correcciones destacadas

  • Dos lookups hacia la misma tabla: la segunda columna mostraba la descripción vacía. Cada clave foránea tiene ahora su propio alias en la consulta, en todas las bases de datos.
  • Columnas geográficas: ordenar la grid por una columna geography fallaba en SQL Server (error 249). En los scripts de primer arranque las columnas geográficas tienen mc_disable_sorting activado, así que la grid no ofrece la ordenación.
  • Idiomas disponibles: GetSupportedLanguages devuelve los idiomas de la tabla lingue.
  • Informes: reportQueryTimeout es opcional, con 120 segundos si falta; la clave está en los appsettings.json de los paquetes.
  • Scripts de primer arranque: sequences e identities empiezan después de los datos cargados, así que la primera inserción no choca con una clave existente. En el tutorial, Countries, DeliveryMethods, People, StateProvinces, Customers e Invoices generan la clave por sí mismas en lugar de pedirla en el formulario.
  • Oracle: las identities se realinean al arrancar.

📦 Paquetes actualizados

Paquete De A
WuicCore 1.7.13 1.7.14
Wuic.Webcore 1.7.13 1.7.14
WuicOData 1.7.13 1.7.14
RuntimeEfCore 1.7.13 1.7.14
Wuic.MySqlProvider 1.7.13 1.7.14
Wuic.PostgresProvider 1.7.13 1.7.14
Wuic.OracleProvider 1.7.13 1.7.14
wuic-framework-lib (npm) 1.7.13 1.7.14

🔧 Actualizaciones operativas recomendadas al actualizar

  1. Dimensionar la cola de exportaciones: cada exportación completa de una tabla grande usa alrededor de un núcleo y 300 MB durante la escritura. En un servidor compartido con otras aplicaciones, configurar maxConcurrentExports por debajo del valor por defecto (por ejemplo 2).
  2. Rutas importables: si sus archivos contienen claves y no descripciones, configurar "import": { "fkey_mode": "key" } en el props bag de la ruta; con both la exportación produce también las columnas clave.
  3. Instalaciones con el tutorial ya cargado: los scripts de primer arranque solo valen para instalaciones nuevas. Para quitar la ordenación de las columnas geográficas existentes, ejecutar en la base de datos de metadatos UPDATE _metadati__colonne SET mcdisablesorting = 1 WHERE LOWER(mc_db_column_type) IN ('point', 'geography', 'geometry') y vaciar la caché de metadatos.
  4. Clientes que leen el progreso desde el WebSocket de notificaciones: el mensaje de progreso de la exportación tiene el nuevo campo queuePosition, presente mientras la exportación espera en la cola.

v1.7.13

Volver al índice

Versión anterior publicada: 1.7.12 (20 de septiembre de 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


Esta versión es sobre todo una versión de seguridad. Una auditoría de toda la superficie de las API encontró métodos y controladores accesibles sin iniciar sesión, o por un usuario sin derechos de administración, y datos de sesión tomados de la petición en vez del servidor. Se cerraron todos, con una prueba automática para cada caso. Junto con ellos llegan las correcciones surgidas de las celdas de prueba en PostgreSQL, MySQL y Oracle, y la finalización del soporte multi-tenant.

Se recomienda actualizar todas las instalaciones. Lea la sección final «Actualizaciones operativas recomendadas»: un par de comportamientos cambian.


🛡️ Seguridad

Llamadas AsmxProxy cerradas por defecto. Todo método accesible desde /api/Meta/AsmxProxy/{servicio}.{metodo} requiere ahora una sesión válida, salvo los declarados anónimos. Tres atributos del namespace WEB_UI_CRAFTER.Helpers gobiernan el acceso:

  • [AsmxAnonymous]: método invocable sin iniciar sesión (login, me, traducciones, registro, restablecimiento de contraseña);
  • [AsmxAdmin]: reservado a los administradores (rol superadmin);
  • [AsmxFirstRun]: anónimo solo durante el primer arranque, después reservado a los administradores.

El proxy además solo invoca las clases de servicio (MetaService, scaffolding, los servicios de la aplicación en WEB_UI_CRAFTER.ProjectData.Servizi): un nombre de clase completo de otros namespaces es rechazado.

Sesión verificada en todas partes. Hardening best-effort en toda la gestión de la sesión:

  • la cookie k-user se valida en el servidor también con los proveedores PostgreSQL y Oracle (token, caducidad, sesión sustituida por un nuevo inicio de sesión);
  • el usuario de la configuración personal, el menú y el pivot es el de la sesión, no el indicado en la petición;
  • el cierre de sesión cierra solo la propia sesión;
  • en multi-tenant, el indicador superadmin de la cookie solo cuenta si la base de datos lo confirma;
  • la lista de usuarios ya no devuelve tokens ni IP de sesión.

También se han alineado los endpoints de los controladores:

  • el editor de appsettings.json, OData, la subida de archivos y el informe verifican sesión y rol en el servidor;
  • la subida permanece en la carpeta del registro;
  • el diseñador solo acepta hojas .css del proyecto;
  • las funciones de administración de webhooks, métricas y licencia están reservadas a los administradores.

Notificaciones. Los endpoints REST y WebSocket de las notificaciones están ligados al usuario de la sesión: una petición para otro usuario recibe 403 errors.auth.notification_forbidden. El WebSocket funciona también detrás de un reverse proxy, gracias a X-Forwarded-For.

Registro desactivado por defecto. Solo se activa con registrationEnabled=true en appsettings.json y nunca asigna un rol admin o superadmin: default-role-id debe indicar un rol existente sin derechos de administración.

Primer arranque.

  • La contraseña elegida en el asistente para el administrador se aplica incluso si el nombre coincide con un usuario ya existente.
  • Los scripts de primer arranque de MySQL y Oracle ya no contienen los usuarios de las pruebas automáticas.
  • El usuario dedicado wuic_assistant (WUIC Assistant, servidor MCP) se crea con una contraseña generada para cada instalación, guardada en scripts/mcp/wuic-assistant.credentials.json (excluido de git).

🤖 RAG y WUIC Assistant

  • /api/Rag/Chat requiere iniciar sesión; /api/Rag/Query sigue sin necesitarla.
  • Los detalles de /api/Rag/MetadataDetail que devuelven datos (sample_records, lookup_value, db_*) están reservados a los administradores.
  • La clave LLM configurada en el servidor nunca se envía a un proveedor o dirección elegidos por quien llama.
  • El servidor MCP wuic-rag abre la sesión por sí solo cuando hace falta, con WUIC_USER/WUIC_PASSWORD o con el archivo de credenciales del usuario wuic_assistant.

🏢 Multi-tenant

  • Cachés separadas por tenant para el menú, los permisos de tabla y columna, los estilos, las rutas disponibles y la caché de datos: un tenant ya no ve las entradas de otro.
  • La propagación de una tabla a los tenants invalida la caché de cada tenant de destino, de modo que la nueva entrada aparece de inmediato en los menús.
  • Notificaciones por tenant.
  • Soporte de PostgreSQL.

🗄️ Proveedores de base de datos

  • PostgreSQL: paginación, caché de datos, filtros many-to-many vacíos, temas, fechas con cualquier host.
  • MySQL: recuentos en selects distinct, restricciones del sistema, carga de los proveedores en Linux.
  • Oracle:
    • paginación, filtros geográficos (área y distancia), restricción de los registros por usuario y rol, nombres de las stored procedures, booleanos en columnas numéricas, agrupación sobre texto largo, caché de datos;
    • traducciones mucho más rápidas: de 3-4,6 s a 0,3-0,7 s;
    • número correcto de filas actualizadas y eliminadas;
    • datos geográficos completos en los scripts de primer arranque (todos los estados y países);
    • demo del workflow de aprobación de pedidos;
    • nombres de las columnas de la timeline alineados con las demás bases de datos.
  • Todos: error de concurrencia optimista tipado (409 errors.validation.optimistic_concurrency), ruta de subida única, fechas de creación de las notificaciones en UTC (migración automática), restricciones por rol correctas para los usuarios con varios roles.

🐛 Correcciones destacadas

  • Navegación entre registros vía URL: al pasar de un registro a otro en edición o en detalle, el diálogo recarga el registro nuevo en vez de mostrar el anterior.
  • data-record-loaded vuelve a false cuando el diálogo recarga el registro, para que las pruebas automáticas no lean datos antiguos.
  • Filtro geográfico espera a que cargue Google Maps antes de dibujar.
  • Lista del scheduler aplica la plantilla antes de recargar los datos.

📦 Paquetes actualizados

Paquete De A
WuicCore 1.7.12 1.7.13
Wuic.Webcore 1.7.12 1.7.13
WuicOData 1.7.12 1.7.13
RuntimeEfCore 1.7.12 1.7.13
Wuic.MySqlProvider 1.7.12 1.7.13
Wuic.PostgresProvider 1.7.12 1.7.13
Wuic.OracleProvider 1.7.12 1.7.13
wuic-framework-lib (npm) 1.7.12 1.7.13

🔧 Actualizaciones operativas recomendadas

  1. Servicios personalizados llamados antes del login: los métodos de sus servicios en WEB_UI_CRAFTER.ProjectData.Servizi que deban responder sin sesión hay que marcarlos [AsmxAnonymous]; sin ello, responden 401 errors.auth.unauthenticated.
  2. Registro: si lo usan, configuren registrationEnabled=true y verifiquen que default-role-id indique un rol sin derechos de administración.
  3. Usuario wuic_assistant en instalaciones existentes: la antigua contraseña predeterminada ya no se acepta. Establezcan una nueva desde un administrador y escríbanla en scripts/mcp/wuic-assistant.credentials.json (o en la configuración de la extensión WUIC Assistant).
  4. Instalaciones Oracle y MySQL con tutoriales hasta la 1.7.12: revisen la tabla de usuarios y eliminen los usuarios wuic_e2e_admin, wuic_e2e_admin_2, wuic_e2e_admin_3 y guest_1, si están presentes.
  5. Herramientas que leían datos de /api/Rag/MetadataDetail o usaban /api/Rag/Chat sin iniciar sesión: ahora deben autenticarse (para los datos, con un administrador).

v1.7.12

Volver al índice

Versión anterior publicada: 1.7.11 (20 de septiembre de 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


Esta versión cierra de verdad los informes que imprimían una página vacía en MySQL y PostgreSQL. Las dos versiones anteriores daban por corregido ese defecto actuando sobre la consulta: la consulta no era el problema, y el informe seguía saliendo con su cabecera y ni una sola fila. La causa real se encontró comparando, en la misma instalación, un informe entregado en el paquete y otro construido en el momento con las columnas de esa instalación: los dos imprimían en blanco, así que el problema no estaba en el archivo del informe.


📊 Los informes imprimen sus datos en MySQL y PostgreSQL

Un informe de Stimulsoft guarda en su diccionario dos cosas distintas: la conexión a la base de datos y el tipo de la fuente de datos. Al abrir un informe, el framework sustituía la conexión por la del motor en uso —StiMySqlDatabase, StiPostgreSQLDatabase— pero dejaba la fuente de datos con el tipo con el que se había creado, StiSqlSource, que para Stimulsoft significa SQL Server.

Una fuente de SQL Server apoyada en una base MySQL no lanza ningún error: simplemente devuelve un conjunto de datos vacío. El informe se dibujaba correctamente —cabecera, marco, «página 1 de 1»— y no imprimía ninguna fila.

La conversión de la fuente al tipo del motor ya existía en el producto, pero solo para Oracle, en dos lugares distintos (el visor y el diseñador). Ahora cubre MySQL y PostgreSQL en ambos. Si tiene informes que imprimían en blanco, no hay nada que regenerar: vuelva a abrirlos.

🔑 Índices de los metadatos en MySQL

En las instalaciones MySQL creadas por el primer arranque guiado, la migración que crea los índices en los caminos calientes de los metadatos fallaba con Fatal error encountered during command execution.

El motivo está en la cadena de conexión que escribe el asistente: sin Allow User Variables=True el controlador de MySQL lee cada @nombre presente en un script como un parámetro en vez de como variable del servidor. Las consultas normales del framework sí usan parámetros, por eso funcionaban; esa migración usa variables del servidor, y moría. La clave se añade ahora a la conexión de los metadatos, tanto cuando la compone el asistente como cuando la reescribe el backend.

🧩 Consulta dinámica en PostgreSQL

La pasarela de PostgreSQL llamaba a la función que construye las consultas dinámicas pasándole 19 argumentos, mientras que el satélite de PostgreSQL acepta 15: la llamada fallaba siempre, con MissingMethodException. Ahora los argumentos son los correctos, y el mensaje de error de esa pasarela dice además cuántos argumentos se han pasado y cuántas versiones del método existen —porque «método no encontrado», por sí solo, manda a buscar un método que sí está ahí.

📦 Paquetes actualizados

Paquete De A
WuicCore 1.7.11 1.7.12
Wuic.Webcore 1.7.11 1.7.12
WuicOData 1.7.11 1.7.12
RuntimeEfCore 1.7.11 1.7.12
Wuic.MySqlProvider 1.7.11 1.7.12
Wuic.PostgresProvider 1.7.11 1.7.12
Wuic.OracleProvider 1.7.11 1.7.12
wuic-framework-lib (npm) 1.7.11 1.7.12

🔧 Actualizaciones operativas recomendadas

  1. Ningún cambio de configuración: las claves de appsettings.json no cambian.
  2. Si tiene informes que imprimían en blanco en MySQL o PostgreSQL, vuelva a abrirlos: no hay nada que regenerar.
  3. En instalaciones MySQL ya en servicio, si quiere que la migración de los índices llegue a término, añada Allow User Variables=True a MetaDataSQLConnection en appsettings.json. Las instalaciones nuevas la reciben del primer arranque guiado. En MySQL el impacto es limitado: dos de los tres índices ya están cubiertos por la restricción de unicidad de la ruta y por el índice que InnoDB crea por su cuenta para las claves ajenas.

v1.7.11

Volver al índice

Versión anterior publicada: 1.7.10 (19 de septiembre de 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


Esta versión cierra dos defectos que la 1.7.10 daba por corregidos y que seguían apareciendo: los informes generados que imprimen una página vacía, y el scaffolding de una tabla desde la interfaz que responde con un error. Los encontró la misma ronda de instalaciones en máquinas limpias que produjo la versión anterior, repetida esta vez contra el producto publicado para comprobar las correcciones. Siguen afectando a quien no usa SQL Server.


📊 Los informes generados imprimen de verdad sus datos en MySQL y PostgreSQL

La 1.7.10 introducía la reescritura de la consulta de los informes generados por el framework, porque el .mrt que viaja en el paquete lleva los identificadores del motor en el que se creó. Esa reescritura, sin embargo, nunca llegaba a ejecutarse: buscaba la tabla de metadatos por el nombre de la base de datos del diccionario —que siempre vale Connessione— en lugar del nombre de la fuente de datos, que es la ruta. Al no encontrar ninguna tabla con ese nombre salía en silencio, no reescribía nada y no dejaba rastro, y el informe seguía imprimiendo la página con su cabecera y ni una sola fila.

Ahora la ruta se lee del sitio correcto, y cada caso en el que la reescritura no puede producirse —ninguna tabla con ese nombre, tabla sin columnas— deja una línea en el registro del backend. Un informe vacío sin explicación es exactamente lo que hacía difícil ver este defecto.

Si tiene informes generados que imprimían en blanco en MySQL o PostgreSQL, no hay nada que regenerar: vuelva a abrirlos.

🧱 Scaffolding de una tabla desde la interfaz en Oracle

En Oracle, generar una tabla desde la interfaz respondía HTTP 500 con ORA-00001: unique constraint ... violated sobre la tabla de menús, y la ruta no se creaba.

Es el mismo defecto corregido para PostgreSQL en la versión anterior, que en Oracle había quedado al descubierto. El esquema declara la clave del menú como GENERATED BY DEFAULT AS IDENTITY, pero el framework inserta sus propias entradas de sistema con la clave calculada a mano: el generador no avanza, y la primera fila que se apoya en él pide una clave ya ocupada. La realineación del generador cubre ahora los dos motores.

📦 Paquetes actualizados

Paquete De A
WuicCore 1.7.10 1.7.11
Wuic.Webcore 1.7.10 1.7.11
WuicOData 1.7.10 1.7.11
RuntimeEfCore 1.7.10 1.7.11
Wuic.MySqlProvider 1.7.10 1.7.11
Wuic.PostgresProvider 1.7.10 1.7.11
Wuic.OracleProvider 1.7.10 1.7.11
wuic-framework-lib (npm) 1.7.10 1.7.11

🔧 Actualizaciones operativas recomendadas

  1. Ningún cambio de configuración: las claves de appsettings.json no cambian.
  2. Si tiene informes generados en MySQL o PostgreSQL que imprimían en blanco, vuelva a abrirlos: la consulta se reescribe en el momento del render, no hay nada que regenerar.
  3. En Oracle, si el scaffolding de una tabla desde la interfaz le respondía con un error de clave duplicada, inténtelo de nuevo: el generador de claves del menú se realinea después de cada inserción con clave explícita.

v1.7.10

Volver al índice

Versión anterior publicada: 1.7.9 (18 de septiembre de 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


Esta versión nace de una ronda completa de instalaciones de extremo a extremo en máquinas limpias: dieciséis combinaciones, los cuatro paquetes de distribución contra los cuatro motores soportados, partiendo cada vez del zip publicado y siguiendo la documentación como lo haría quien instala por primera vez. Casi todo lo que salió afecta a quien no usa SQL Server: informes que imprimían una página vacía, un scaffolding que fallaba, índices que nunca se creaban. Todos silenciosos — ningún mensaje en pantalla, solo una función que no funcionaba.


📊 Los informes vuelven a imprimir sus datos en MySQL y PostgreSQL

Al abrir un informe del tutorial en MySQL o PostgreSQL el visor dibujaba la página — cabecera, marco, «página 1 de 1» — y no imprimía ni una fila. El mismo informe funcionaba en SQL Server.

El motivo es que un informe generado por el framework lleva dentro la consulta que lo alimenta, y esa consulta está escrita con los identificadores del motor en el que se generó. El archivo .mrt, sin embargo, viaja en el paquete y es el mismo para los cuatro motores: el de los tutoriales contiene identificadores sin comillas en mayúsculas. En SQL Server pasa, porque allí la comparación no distingue mayúsculas; en PostgreSQL un identificador sin comillas se pliega a minúsculas y ya no encuentra las columnas, que el tutorial crea entrecomilladas en PascalCase.

Ahora, antes de renderizar, los informes generados por el framework — reconocibles por el marcador que llevan en el SELECT — regeneran su consulta a partir de los metadatos para el motor de la instalación actual, con las reglas de comillas correctas. Los informes escritos a mano en el diseñador no se tocan: su consulta sigue siendo la que usted escribió.

🧱 Scaffolding de una tabla desde la interfaz en PostgreSQL

En PostgreSQL, generar una tabla desde la interfaz respondía HTTP 500 con una violación de clave ajena sobre _metadati__colonne, y la ruta generada se quedaba sin filas.

El defecto real estaba antes, y era doble. La secuencia identity de la tabla de menús se queda atrás cuando se insertan filas con la clave explícita — algo que el framework hace al añadir sus propias entradas de sistema: a partir de ahí, la primera inserción que se apoya en la secuencia pide una clave ya ocupada. Y cuando la creación de la entrada de menú fallaba, el código borraba la fila de metadatos de la tabla recién insertada, dejando las columnas sin su padre: el error que llegaba al usuario hablaba entonces de claves ajenas y de una tabla que no tenía nada que ver.

Ahora la secuencia se realinea después de cada inserción con clave explícita, y un menú que no se crea ya no se lleva por delante los metadatos de la tabla: como mucho, la entrada de menú se añade desde el diseñador.

⚡ Los índices de los metadatos ahora se crean de verdad

Las migraciones de esquema que crean los índices en los caminos calientes de los metadatos — nombre de la ruta, columnas por tabla, scheduler — no se aplicaban en una instalación nueva, por dos motivos distintos.

El primero: al arrancar una aplicación recién instalada las cadenas de conexión todavía no están, así que las migraciones fallaban; y como el intento se daba por consumido, ya no se reintentaban en el proceso. En una instalación nueva, donde nadie reinicia el servicio justo después, esos índices no nacían nunca. La condición «base de datos aún no configurada» ya no consume el intento, y las migraciones corren en cuanto el asistente de primer arranque ha escrito las cadenas de conexión.

El segundo, solo en Oracle: el script de los índices citaba las columnas entrecomilladas en minúsculas mientras el esquema las crea en mayúsculas, con lo que respondía ORA-00904 y la migración se detenía ahí.

El efecto para quien usa el producto se ve en las páginas que dependen de esos índices: abrir una lista desde el menú, volver a una lista ya visitada, la primera entrada del menú Administración. Sin índices esas operaciones llegaban a decenas de segundos en PostgreSQL.

🤖 El asistente de VS Code responde a las preguntas en vez de escribir código

Al preguntarle «¿qué columnas tiene la ruta X?» — incluso añadiendo «no modifiques archivos» — el asistente generaba un componente y respondía describiendo lo que había escrito. La pregunta se quedaba sin respuesta y el proyecto se modificaba contra la instrucción.

Una petición que es una pregunta, o que prohíbe explícitamente los cambios, pone ahora al asistente en solo lectura: las herramientas que tocan el proyecto se rechazan, y la respuesta se construye con las de consulta (columnas y metadatos de la ruta, búsqueda en el código y en la documentación).

🔧 Instalaciones más tolerantes con los tropiezos pasajeros

  • Windows: cuando winget responde que ya hay otra instalación en curso — el caso típico es Windows Update justo tras el arranque — el instalador ya no se detiene diciendo «instálalo a mano»: reintenta tres veces con espera creciente. Esa condición se libera sola en unas decenas de segundos.
  • Linux, Oracle: el contenedor de Oracle declara el listener listo mientras el primer arranque todavía está aplicando la contraseña del usuario system. El instalador salía con error ORA-01017; ahora espera a que las credenciales sean válidas y, si no lo son, lo dice con claridad en lugar de dejar que el error reaparezca más adelante disfrazado de otra cosa.

📚 Documentación

  • Patrón «Framework component + Custom data»: una sección nueva explica que en Oracle, cuando abre usted la conexión con DataSQLConnection, hay que llevar la sesión a su esquema (ALTER SESSION SET CURRENT_SCHEMA) o calificar las tablas — si no, la primera consulta responde ORA-00942 aunque la tabla exista. Los otros motores no lo necesitan, porque la base de datos está en la cadena de conexión.
  • Getting started: el camino de VS Code (archivo de workspace, arranque con F5, lanzador Fullstack) está ahora en el texto de la página y no solo dentro de un bloque de código.
  • FIRST_STEPS del paquete (inglés, francés, español, alemán): añadida la sección sobre cómo abrir el proyecto en VS Code y qué script npm sirve el frontend. Antes solo estaba en la versión italiana.
  • README del kit de fuentes Linux: añadida la sección sobre el renombrado del proyecto, hasta ahora documentado solo para Windows.

📦 Paquetes actualizados

Paquete De A
WuicCore 1.7.9 1.7.10
Wuic.Webcore 1.7.9 1.7.10
WuicOData 1.7.9 1.7.10
RuntimeEfCore 1.7.9 1.7.10
Wuic.MySqlProvider 1.7.9 1.7.10
Wuic.PostgresProvider 1.7.9 1.7.10
Wuic.OracleProvider 1.7.9 1.7.10
wuic-framework-lib (npm) 1.7.9 1.7.10

🔧 Actualizaciones operativas recomendadas

  1. Ningún cambio de configuración: las claves de appsettings.json no cambian.
  2. En instalaciones PostgreSQL y Oracle ya en servicio, los índices que faltaban se crean en el primer arranque con la 1.7.10: ese arranque puede durar unos segundos más, una sola vez.
  3. Si tiene informes generados en MySQL, PostgreSQL u Oracle que imprimían en blanco, vuelva a abrirlos: no hay que regenerar nada, la consulta se reescribe en el momento del render.
  4. Si alguno de sus controladores abre conexiones propias en Oracle, compruebe que lleve la sesión al esquema de datos o que califique las tablas: vea la nota en la página de patrones.

v1.7.9

Volver al índice

Versión anterior publicada: 1.7.8 (18 de septiembre de 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


Una versión corta y concreta: el indicador de carga mentía. En una ruta lenta la página se quedaba vacía durante toda la consulta, y lo que llegaba a aparecer ya había apagado el indicador a mitad de camino. Quien probaba el producto sobre una tabla grande veía una pantalla en blanco y concluía que estaba bloqueado.


⏳ La rejilla aparece enseguida, y la espera se ve

El defecto tenía dos mitades, y cada una escondía a la otra.

La rejilla todavía no existía. La tabla — y con ella la capa de carga, que le pertenece — se construía solo cuando llegaban los datos: el componente recibía los metadatos junto con el resultado de la consulta, no antes. En una ruta lenta eso significaba ninguna cabecera, ninguna barra de comandos, ninguna señal de actividad: solo el título de la página, durante todos los segundos de la consulta. Ahora los metadatos se publican antes de lanzar la lectura de datos: la rejilla se monta vacía y el indicador gira durante toda la espera. Medido en una ruta que responde en 4 segundos: la tabla está en pantalla a los 330 ms en vez de a los 4.300.

El indicador se apagaba a mitad. Cada llamada al servidor encendía y apagaba el estado «ocupado» sin contar cuántas operaciones había en curso. Al abrir una ruta con columnas lookup, el framework lanza una docena de lecturas de metadatos en paralelo con la consulta de datos: la primera en responder — medio segundo después — apagaba el indicador para todos, mientras la consulta de verdad seguía otros tres segundos.

Ahora las operaciones en vuelo se cuentan, y el estado vuelve a libre solo cuando termina la última. En la misma ruta el indicador cubre toda la espera en lugar de 600 milisegundos.

La corrección se ha verificado en todos los arquetipos — list, map, scheduler, chart, carousel, kanban, timeline, tree, spreadsheet — midiendo en cada uno cuándo se enciende el indicador, cuándo se apaga y cuándo aparecen los datos: en ninguno se apaga antes que los datos.

Un efecto que conviene conocer: en rutas con muchas columnas lookup el indicador ahora se queda encendido unos segundos después de que las filas sean legibles, porque esas lecturas de metadatos siguen de verdad en marcha. Antes desaparecía antes, pero mintiendo.

🧩 El sugeridor del props bag enciende de verdad el flag

En el panel Sugerir md_props_bag del editor de metadatos, marcar una entrada booleana — por ejemplo archetypes.list.advancedFilter, la que sustituye los filtros de columna por la barra de filtros — insertaba en el JSON "advancedFilter": false. La marca creaba la clave pero copiaba el valor de ejemplo, que para esos flags es false: había que darse cuenta y corregirlo a mano.

Ahora una entrada booleana marcada entra como true. Quien no quiera el flag simplemente no lo marca: el valor por defecto en ejecución ya es false. Las entradas no booleanas siguen llevando el valor de ejemplo, que ahí sirve de plantilla que rellenar. Vale para ambos sugeridores, el de la tabla y el de la columna.

📦 Paquetes actualizados

Paquete De A
WuicCore 1.7.8 1.7.9
Wuic.Webcore 1.7.8 1.7.9
WuicOData 1.7.8 1.7.9
RuntimeEfCore 1.7.8 1.7.9
Wuic.MySqlProvider 1.7.8 1.7.9
Wuic.PostgresProvider 1.7.8 1.7.9
Wuic.OracleProvider 1.7.8 1.7.9
wuic-framework-lib (npm) 1.7.8 1.7.9

🔧 Actualizaciones operativas recomendadas

  1. Ningún cambio de configuración: las claves de appsettings.json no cambian.
  2. Una vez actualizada la librería npm, reconstruir el frontend: ambas correcciones viven en los componentes, no en los metadatos.
  3. Si vuestra aplicación lee el estado «ocupado» del framework para gobernar una interfaz propia, comprobadla: ese estado ahora permanece activo hasta que acaba la última operación en vuelo, así que dura más que antes. Es el comportamiento correcto, pero es un cambio observable.
  4. Si algún código vuestro apagaba el estado «ocupado» escribiendo directamente en él, pasad a los métodos beginBusy / endBusy del toolbox, o a resetBusy si se trata de un camino de recuperación tras un error: una escritura directa apaga el indicador también para las operaciones de los demás.

v1.7.8

Volver al índice

Versión anterior publicada: 1.7.7 (17 de septiembre de 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


Una versión nacida de usar el producto en vez de leerlo: un gesto que faltaba en las listas, un ejemplo presente en tres bases de datos de cuatro, textos que seguían en italiano en instalaciones que no lo eran, y páginas de documentación que describían pantallas distintas de las reales.


🖱️ Doble clic en una fila: se abre la modificación

Hasta ayer el formulario de modificación de un registro se abría solo desde la entrada Modificar del menú de acciones de la fila. Ahora también lo abre un doble clic sobre la fila.

No es un atajo paralelo que reescriba la misma lógica: el framework sube desde la fila pulsada hasta su menú de acciones y ejecuta ese mismo comando. Se aplican los mismos permisos (md_editable) y la misma regla condicional evaluada sobre ese registro (md_conditional_update_rule): donde el lápiz no está o está deshabilitado, el doble clic no hace nada. Es una garantía estructural, no una promesa: si mañana cambian las reglas de quién puede modificar, cambian para ambos a la vez.

El gesto se ignora cuando apunta a otra cosa: doble clic sobre un botón, un enlace o un campo de texto (estás usando ese control, o seleccionando texto), o fila ya abierta en edición en línea.

Vale también en el layout móvil de tarjetas, donde la lista reconoce dos toques seguidos sobre la misma tarjeta. Hacía falta porque, cuando el gesto nace de un toque, el navegador no siempre entrega el evento de doble clic: dos taps se quedan en dos clics separados.

🗓️ El tutorial en SQL Server ya tiene la página Timeline / Gantt

La documentación describe el arquetipo timeline/gantt y la base del tutorial ya trae los datos de ejemplo, pero en SQL Server faltaban la ruta y la entrada de menú que los abren: solo existían en MySQL, PostgreSQL y Oracle. Quien instalaba el tutorial en el motor por defecto no tenía forma de ver esa vista, y la página de documentación quedaba sin poder comprobarse.

El tutorial de SQL Server tiene ahora Ejemplos → Timeline (Gantt): nueve tareas en dos proyectos, con dependencias entre tareas, hitos, avance y agrupación por proyecto. Es un ejemplo completo y funcional de md_props_bag.archetypes.timeline del que copiar la configuración, incluidas las dos partes que más se equivocan: los predecesores sobre una columna multiselect con tabla puente autorreferenciada, y la agrupación sobre un lookup en vez de sobre texto libre.

🌍 Textos que seguían en italiano

  • Chatbot RAG. Mientras el motor arranca, el chat responde que todavía no está listo. Ese mensaje estaba escrito a mano en italiano en el código y llegaba igual a una instalación inglesa, francesa, española o alemana. Ahora es una clave traducida a cinco idiomas. Tampoco habla ya de «descarga de los modelos»: desde que la instalación los precarga, la espera es la carga en memoria, no la descarga — el mensaje describía algo que no estaba ocurriendo.
  • Workflow designer. Seis comandos del menú (Reabrir, Nuevo grafo, Guardar grafo, Eliminar, Re-disposición automática, Abrir el runner en una pestaña nueva) eran literales italianos en el código: en una instalación en otro idioma el menú salía medio traducido.
  • El aviso del mapa sin clave de Google. Existía en dos idiomas y solo en los paquetes de SQL Server; en los demás motores aparecía la clave en bruto en lugar del mensaje. Ahora son cinco idiomas en los cuatro motores.

🧹 Un tutorial más limpio

Del menú del tutorial desaparecen las veinte entradas Cline Prompt Tests, restos de pruebas internas que no tenían por qué estar en una base de ejemplo.

📚 Documentación

Las páginas de abajo describían el producto de forma inexacta. No son retoques de forma: eran instrucciones que llevaban por el camino equivocado.

  • Primer arranque. El asistente no estaba descrito en absoluto. La guía de introducción explica ahora los dos modos de instalación (Base de datos existente y Tutorial WideWorldImporters, el segundo presente solo si el paquete trae el tutorial), el campo DataSQLConnection y el botón de prueba del que depende todo lo demás — hasta que no lo pulsas, la lista de bases permanece deshabilitada —, el usuario admin inicial, y cuánto dura el aprovisionamiento: 30 s – 2 min en modo tutorial, 1–4 min sobre una base existente con el scaffold automático activado.
  • No existe una contraseña predeterminada. La misma página declaraba admin / admin como credenciales tras el primer arranque. Es falso: la contraseña es la elegida en el asistente, y no hay otra.
  • Licencia. El procedimiento decía que había que escribir los valores en el archivo de configuración y reiniciar el backend, y nunca mencionaba que la interfaz existe. Pegando la licencia desde Administración → Editor AppSettings, sección License, el backend recarga por su cuenta la validación y la licencia vale desde la siguiente petición. El reinicio solo hace falta en el otro caso, cuando los valores se escriben a mano en el archivo.
  • Scaffolding inicial. No decía que en los paquetes tutorial no hay nada que scaffoldar: la base de metadatos llega ya poblada, y la casilla que registra las tablas solo existe en modo Base de datos existente.
  • List Grid. Una nueva sección enumera los botones que la toolbar muestra realmente al abrir una ruta, y la condición de cada uno. La página solo nombraba comandos opcionales o transitorios — los del diálogo de progreso de import/export, que solo existe mientras un import o un export está en curso — y ninguno de los que se ven nada más abrir una lista.
  • Designer. La lista de la paleta nombraba cinco entradas, tres de ellas inexistentes con ese nombre, y callaba sobre las demás. Ahora están los tres grupos reales y los nombres verdaderos de los componentes.
  • Modo Trial. Una instalación sin licencia limita cada consulta a 20 registros: una lista que indica «20 de 20» sobre una tabla de miles de filas está funcionando en Trial, no está averiada. Ahora está escrito donde hace falta — en la página de descargas y en la guía de introducción — y no solo en la de precios.

📦 Paquetes actualizados

Paquete De A
WuicCore 1.7.7 1.7.8
Wuic.Webcore 1.7.7 1.7.8
WuicOData 1.7.7 1.7.8
RuntimeEfCore 1.7.7 1.7.8
Wuic.MySqlProvider 1.7.7 1.7.8
Wuic.PostgresProvider 1.7.7 1.7.8
Wuic.OracleProvider 1.7.7 1.7.8
wuic-framework-lib (npm) 1.7.7 1.7.8

🔧 Actualizaciones operativas recomendadas

  1. Ningún cambio de configuración: las claves de appsettings.json no cambian.
  2. Una vez actualizada la librería npm, reconstruir el frontend: el doble clic vive en el componente de lista, no en los metadatos.
  3. Si vuestra aplicación ya tenía un comportamiento ligado al doble clic sobre una fila de lista, comprobadlo: el framework abre ahora el formulario de modificación con ese mismo gesto.
  4. La entrada Timeline (Gantt) aparece en las instalaciones tutorial nuevas sobre SQL Server. Una instalación ya hecha no hay que rehacerla: los datos de ejemplo ya están, solo faltan la ruta y la entrada de menú, que se añaden desde la interfaz.

v1.7.7

Volver al índice

Versión anterior publicada: 1.7.6 (16 de septiembre de 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


Esta versión corrige cinco defectos encontrados instalando el framework en máquinas limpias, uno por cada combinación de sistema operativo y base de datos. El más importante afecta a Oracle y PostgreSQL, donde una página generada por el framework podía no abrirse según cómo se escribiera su nombre en la dirección. Los demás afectan a Oracle XE y al paquete de fuentes para Linux.


🔤 Las rutas se abren ahora sin importar las mayúsculas

El nombre de una ruta nace en minúsculas: una tabla Supplier se convierte en la ruta supplier. Abrir /Supplier/List — es decir, escribir el nombre de la propia tabla — funcionaba en SQL Server y MySQL, donde el motor ignora las mayúsculas, pero no en Oracle ni PostgreSQL, que respondían Ruta 'Supplier' no encontrada en los metadatos.

La misma dirección, el mismo scaffolding, un resultado distinto según la base que hubiera debajo. En Oracle el efecto se multiplicaba: la lista producida por el scaffolding inicial, la página creada desde la interfaz, los componentes que montan un widget del framework y las API de metadatos fallaban todos por la misma razón, y parecían cuatro averías distintas.

La resolución de una ruta ahora recurre a una comparación que ignora las mayúsculas cuando la exacta falla: el camino normal no cambia, y los nombres físicos de tablas y columnas siguen siendo los escritos en el esquema.

Si una instalación tuviera dos rutas que solo se diferencian por las mayúsculas, el framework no puede elegir una: ahora lo dice con un mensaje explícito (HTTP 409, errors.metadata.route.ambiguous_case) que enumera las rutas en conflicto, en lugar de responder «no encontrada».

🗄️ Oracle XE: el scaffolding desde la interfaz

Generar una página a partir de una tabla desde el menú de administración respondía 500 en Oracle XE:

ORA-00932: inconsistent datatypes: expected NUMBER got BOOLEAN

Las columnas de metadatos que representan un interruptor son numéricas, pero el provider escribía en ellas un booleano: un tipo que en SQL de Oracle existe solo a partir de 23ai. En 23ai la conversión implícita ocultaba el problema; en XE — la edición más extendida — el servidor rechazaba la inserción y el scaffolding se detenía. Ahora escribe 1 y 0, válidos en todas las versiones.

🐧 Paquete de fuentes para Linux

  • El chatbot RAG estaba apagado. El paquete declaraba el motor .NET activo en su propia configuración pero no lo distribuía: /api/Rag/Health respondía siempre not-initialized, con WuicRagEngine.dll no encontrado. El motor está ahora también aquí, como ya lo estaba en el paquete de Windows.
  • Los modelos se descargan durante la instalación. En la primera pregunta el chatbot tenía que descargar 4,4 GB entre modelos e índice, y durante varios minutos solo respondía «completando la inicialización». Ahora install.sh los descarga mientras instala, en paralelo con el resto: la primera pregunta responde de inmediato. La descarga se omite con --skip-prefetch, que restaura el comportamiento anterior. El paso nunca interrumpe la instalación: si la red falla, el chatbot los descargará en el primer uso.
  • Los archivos para los asistentes de código no se generaban. En Linux el primer arranque no escribía AGENTS.md, CLAUDE.md, .mcp.json ni las skills: la plantilla que los produce no estaba en el paquete, y la generación se omitía en silencio. Ahora se incluyen en ambos paquetes de Linux.
  • Renombrar el proyecto. rename-project.sh buscaba el proyecto solo en su propia carpeta y en la superior, mientras que en el paquete está un nivel más abajo: ejecutado como se documenta, salía con WuicTest.csproj no encontrado. Ahora también busca ahí y, si de verdad no encuentra nada, enumera las rutas que ha probado.
  • El paquete ya no arrastra los restos del antiguo stack RAG en Python (codebase_embeddings/, rag-setup.ps1, rag-start.ps1), sustituido por el motor .NET en junio.

📦 Paquetes actualizados

Paquete De A
WuicCore 1.7.6 1.7.7
Wuic.Webcore 1.7.6 1.7.7
WuicOData 1.7.6 1.7.7
RuntimeEfCore 1.7.6 1.7.7
Wuic.MySqlProvider 1.7.6 1.7.7
Wuic.PostgresProvider 1.7.6 1.7.7
Wuic.OracleProvider 1.7.6 1.7.7
wuic-framework-lib (npm) 1.7.6 1.7.7

🔧 Actualizaciones operativas recomendadas

  1. En Oracle y PostgreSQL: si habías marcado como no funcionales páginas generadas por el scaffolding, vuelve a probarlas tras actualizar — es muy probable que fuera esto.
  2. En Oracle XE: el scaffolding desde la interfaz es utilizable a partir de esta versión; las tablas expuestas antes no hay que rehacerlas.
  3. Instalar desde fuentes en Linux supone ahora 4,4 GB de descarga adicional durante la instalación, o añadir --skip-prefetch para posponerla al primer uso del chatbot.
  4. No se requiere ningún cambio de configuración: las claves de appsettings.json no cambian.

v1.7.6

Volver al índice

Versión publicada anterior: 1.7.4 (16 de septiembre de 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


Esta versión sale el mismo día que la 1.7.4 y corrige tres cosas encontradas al repetir la instalación en máquinas limpias justo después de publicarla. La más importante afecta a Oracle: el primer arranque sobre una base de datos existente llegaba al final declarando éxito, pero dejaba la aplicación sin las tablas del usuario. Las otras dos afectan al paquete de Linux.


🗄️ Oracle: primer arranque sobre una base de datos existente

Quien elegía el modo "base de datos existente", indicaba su propio esquema y pedía el scaffolding automático llegaba al inicio de sesión con el menú sin ninguna de sus tablas, y sin ningún error en pantalla. El motivo estaba escrito solo en firstrun-scaffold-error.log, junto a la aplicación:

firstRun scaffold failed for db='MIESQUEMA' dbms='oracle':
  ORA-01017: invalid credential or not authorized; logon denied

En Oracle la "base de datos de datos" es el esquema, y el framework construía la conexión poniendo como usuario el esquema elegido pero conservando la contraseña escrita en el asistente, que es la de quien está configurando: una credencial que nadie ha tecleado y que en general no existe. El scaffolding, que reutilizaba esa misma conexión, no lograba autenticarse; el error acababa en un bloque tolerante y el asistente declaraba éxito igualmente.

Ahora la conexión conserva el usuario indicado en el asistente — como ya ocurre en PostgreSQL, donde elegir la base de datos no cambia la identidad — y el esquema de trabajo se establece en la sesión con ALTER SESSION SET CURRENT_SCHEMA, que es la forma prevista por Oracle para operar dentro de un esquema sin ser su usuario. Las instalaciones en las que quien configura es el esquema (todas las del tutorial entre ellas) se comportan igual que antes.

En la práctica: del asistente al scaffolding y al inicio de sesión, las tablas aparecen en el menú y las listas muestran datos.

🐧 Paquete de Linux

  • El chat RAG estaba apagado en los cuatro motores. El motor .NET se instala correctamente, pero los perfiles appsettings.linux.*.json no contenían ninguna clave rag-*: el backend recurría a un servidor Python que el paquete de Linux no distribuye, y cada petición respondía 503. Las claves están ahora en los cuatro perfiles.
  • Las plantillas de informes no se distribuían. La carpeta Reports/ no llegaba al tarball, así que en Linux ninguna ruta ofrecía la entrada Report. Ahora se incluye.
  • Renombrar el proyecto en Linux. El paquete de código fuente ofrecía una sola forma de hacer tuyo el template, y era un script de PowerShell: en un Ubuntu limpio pwsh no está, el instalador no lo añade y los requisitos no lo piden. Junto a rename-project.ps1 está ahora rename-project.sh, con los mismos pasos — renombrar .csproj, controlador y workspace de VS Code, actualizar contenidos, alinear el nombre en package.json — con --name, --in-place y --backend-port. Por defecto clona en una carpeta nueva y deja intacta la original.
  • El smoke test suspendía instalaciones sanas. Al terminar la instalación el script intentaba un inicio de sesión administrativo incluso cuando la aplicación queda en primer arranque — condición normal en Oracle desde la 1.7.4, donde usuarios y metadatos los crea el asistente. La instalación cerraba con "Install completed but smoke tests failed" estando perfectamente bien. Ahora la comprobación se omite con un aviso que explica cómo completarla.

🔧 Actualizaciones operativas recomendadas

  1. Quien descargó el tarball de Linux de la 1.7.4 en sus primeras horas: descárguelo de nuevo. La primera copia publicada llevaba ensamblados de versiones desalineadas y el servicio no arrancaba (Could not load file or assembly 'WuicOData'); la copia actual es correcta, y esta versión la sustituye de todos modos.
  2. En Oracle, una instalación ya completada con la 1.7.4 y que quedó sin tablas en el menú no se repara sola: conviene rehacer el primer arranque sobre una base de datos de metadatos vacía.
  3. No se requiere ningún cambio de configuración: las claves de appsettings.json no cambian.

v1.7.4

Volver al índice

Versión publicada anterior: 1.7.3 (14 de septiembre de 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


Esta versión trata casi por completo de Oracle. Repetir la instalación y el primer arranque en máquinas limpias — en Windows con IIS y en Linux con nginx — sacó a la luz cuatro puntos en los que el recorrido se interrumpía antes de llegar a una aplicación en funcionamiento: la carga de los datos del tutorial, la creación de los usuarios, el chat RAG y, en Linux, la generación misma de la contraseña de la base de datos. Ninguno de los cuatro aparece en los demás motores.

El resto son correcciones del primer arranque válidas para todos los motores, más dos en el diagnóstico de los errores SQL.


🗄️ Oracle: datos del tutorial y primer arranque

La carga de los datos iniciales en Oracle tenía éxito en 472 instrucciones de 18.141. Las demás fallaban con ORA-01843: not a valid month, porque los scripts de primer arranque contienen fechas y números en la convención italiana mientras que la sesión de Oracle usaba los valores predeterminados del servidor. La ejecución de los scripts establece ahora NLS_DATE_LANGUAGE y NLS_NUMERIC_CHARACTERS antes de la primera instrucción: 17.889 instrucciones de 17.889, tanto en Windows como en Linux. Si probó Oracle con la 1.7.3 y encontró las tablas del tutorial medio vacías, ésta es la razón.

También en Oracle, tres correcciones en la instalación de Linux:

  • la contraseña generada para la base de datos podía contener el carácter @, que rompe la cadena easy-connect de sqlplus: la instalación se detenía con ORA-12262 en aproximadamente uno de cada tres casos, y el carácter culpable no aparecía en ningún mensaje;
  • la creación de las bases de datos del tutorial y la de los usuarios de autenticación se dejan ahora al asistente de primer arranque, que es el camino que las demás plataformas ya seguían. Los scripts de instalación preparaban en cambio un esquema que el asistente iba a rehacer de todos modos;
  • appsettings.linux.oracle.json se entrega con firstRun activo, de modo que la primera ventana del navegador lleva al asistente y no a una aplicación sin metadatos.

💬 Chat RAG en Oracle

El chat respondía 500 a la primera pregunta, con ORA-00933: SQL command not properly ended. Las consultas del chat terminan con punto y coma — correcto en SQL*Plus y en los demás motores, pero para el controlador de Oracle forma parte del texto de la instrucción. El punto y coma final se elimina ahora antes de la ejecución, salvo en los bloques PL/SQL, donde END; es legítimo.

🚀 Primer arranque (todos los motores)

  • El asistente se detiene con un mensaje si la base de datos de datos indicada no está entre las leídas del servidor. Antes continuaba: la instalación se completaba y el menú se abría, pero cada rejilla quedaba vacía porque los metadatos apuntaban a una base de datos inexistente. El mensaje está traducido a los 5 idiomas.
  • En Linux, appsettings.json en la carpeta de la aplicación es un enlace simbólico a /etc/wuiccore/appsettings.json. La escritura atómica de la configuración resuelve ahora el enlace antes de escribir: sin eso, el asistente escribía un archivo nuevo en lugar del enlace, la aplicación seguía leyendo el antiguo y el primer arranque no se cerraba nunca.
  • Los archivos de configuración escritos por el instalador siguen siendo escribibles por el servicio (modo 0660, grupo del servicio). El asistente fallaba al guardar al final en una instalación recién creada.

🔎 Diagnóstico de los errores SQL

El envelope de error que el diálogo muestra a un administrador afirmaba dos cosas falsas:

  • sqlProvider indicaba mssql para cualquier error que no fuera MySQL — por tanto también para las excepciones de Oracle y PostgreSQL. El valor deriva ahora del tipo de la excepción, y los proveedores no reconocidos declaran unknown en lugar de un nombre equivocado;
  • query quedaba vacía en los caminos que usan ADO.NET directamente en vez de la capa Dapper (entre ellos el chat RAG), incluso con el diagnóstico activo. La captura del comando cubre ahora ambos caminos, con el mismo enmascaramiento de los parámetros sensibles.

🐛 Correcciones destacables

  • Lista de modelos LLM sin clave de API: el endpoint contactaba con el proveedor incluso sin clave configurada, y la página de ajustes esperaba la respuesta de red. Sin clave se devuelve ahora de inmediato la lista curada local.

🔧 Actualizaciones operativas recomendadas

  1. Quien use Oracle debería actualizar antes de rehacer una instalación: las correcciones anteriores afectan al recorrido de primer arranque y no tienen efecto retroactivo sobre una base de datos ya poblada a medias. En una instalación ya estropeada conviene empezar de nuevo con una base de datos vacía.
  2. En Linux, comprobar tras la actualización que appsettings.json en la carpeta de la aplicación sigue siendo el enlace a /etc/wuiccore/appsettings.json y no un archivo autónomo dejado por un primer arranque de la 1.7.3.
  3. No se requiere ningún cambio de configuración: las claves de appsettings.json no cambian.

v1.7.3

Volver al índice

Versión anterior publicada: 1.7.0 (14 de agosto de 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


La novedad es la instalación en un solo comando en Windows. El resto son correcciones a la instalación y al primer arranque, encontradas repitiendo todo el procedimiento en máquinas limpias, en Windows y en Linux, con SQL Server, MySQL y PostgreSQL. Dos de ellas impedían siquiera llegar al asistente: en Linux con MySQL la carga de la base de datos se detenía en la primera instrucción, y el scaffolding automático del asistente no generaba los metadatos, dejando la aplicación con el menú vacío.


💾 Instalación en un solo comando en Windows

Desde una ventana de PowerShell:

irm https://wuic-framework.com/install.ps1 | iex

El script hace por sí solo todo lo que antes era una lista de pasos manuales: comprueba el runtime ASP.NET Core 10 y lo instala si falta, busca una instancia de SQL Server accesible y, si no encuentra ninguna, instala SQL Server 2022 Express, descarga el último paquete publicado, lo extrae y abre el navegador en el asistente de primer arranque. Es el gemelo para Windows de install.sh y funciona con Windows PowerShell 5.1, por lo que no requiere instalar PowerShell 7.

La aplicación se publica en IIS: el script habilita las características de IIS si faltan, instala el ASP.NET Core Hosting Bundle, crea el grupo de aplicaciones y el sitio en el puerto elegido, y concede a la identidad del grupo los permisos sobre la carpeta y un inicio de sesión en SQL Server. Se necesita elevación: el script la solicita una sola vez, con el aviso habitual de Windows.

Con -Kestrel no se toca nada de IIS y la aplicación se ejecuta en una ventana de consola, reiniciable con start-wuic.cmd. Es la opción adecuada cuando no se tienen derechos de administrador, cuando IIS está deshabilitado por políticas corporativas, o para una prueba desechable.

Las opciones más usadas: -WithTutorial descarga el paquete con la base de datos de demostración WideWorldImporters, -Port cambia el puerto, -ListenAll escucha en todas las interfaces en lugar de solo en localhost, -SqlServer apunta a una instancia existente, -Dbms mysql|postgres instala y configura un motor distinto de SQL Server.

Un requisito que conviene conocer antes de elegir el paquete: la variante del tutorial en formato .bak contiene una copia de seguridad nativa de SQL Server 2022 y requiere por tanto SQL Server 2022 o superior, porque la restauración no es compatible hacia atrás. En SQL Server 2019 hay que usar la variante con los scripts SQL, compatible desde 2019 en adelante; el instalador lo detecta por sí mismo y elige la variante adecuada para la instancia que encuentra.

Respecto a la primera versión del script se han corregido tres cosas con las que uno se topaba enseguida:

  • con -Dbms mysql o -Dbms postgres el instalador escribía sus propios secretos en la carpeta de instalación y después rechazaba esa misma carpeta por "no vacía", saliendo con código 2 doce segundos después de haberla llenado él mismo; además la extracción borraba la contraseña de root recién generada. Los archivos propios del instalador ya no cuentan en la comprobación y los secretos sobreviven a la extracción;
  • volver a ejecutar el comando en una máquina donde la instalación ya existía ya no termina en un callejón sin salida;
  • con -Dbms postgres el tutorial requiere la extensión PostGIS, que en Windows no se instala junto a PostgreSQL: la carga moría a mitad con extension "postgis" is not available, un error que parecía un defecto de los scripts SQL. El instalador ahora comprueba las extensiones disponibles y, si falta, instala el bundle para la versión de PostgreSQL que ha encontrado.

El instalador ahora cuenta lo que está haciendo también durante las fases largas: la instalación de SQL Server Express y npm install pueden pasar minutos sin imprimir una línea, y hasta ahora la ventana parecía bloqueada. Cada diez segundos de silencio aparece cuánto lleva trabajando y cuál fue la última línea útil.

🐧 Instalación en Linux

Tres correcciones, todas en el camino hacia el primer arranque.

El framework no arrancaba con los paquetes ofuscados. La protección anti-tamper aplicada en la fase de publicación impedía el arranque en Linux. Se ha eliminado: la ofuscación de los símbolos se mantiene, la protección que bloqueaba la ejecución no.

La carga de la base de datos MySQL se detenía en la primera instrucción. El script de bootstrap daba por hecho que ya había una base de datos seleccionada, mientras que los volcados ya no contienen la directiva USE, y la carga moría con ERROR 1046 (3D000): No database selected. Quien haya instalado con MySQL usando el paquete anterior sigue encontrando este error: es la razón principal para instalar esta versión.

El perfil de configuración no se copiaba en el proyecto. El appsettings.json que viaja en el paquete de fuentes apunta a una instancia con nombre de SQL Server, que en Linux no existe: siguiendo la documentación, dotnet run moría a los cuarenta y cinco segundos con error: 26 - Error Locating Server/Instance Specified y el asistente no aparecía nunca. Ahora las claves que dependen del motor se copian automáticamente en el proyecto.

Se documentan las versiones de Ubuntu realmente compatibles: 22.04 y 24.04 LTS. En 24.04 SQL Server requiere un arranque en compatibilidad; la 26.04 no está soportada por Microsoft para SQL Server.

🌍 Asistente de primer arranque en cinco idiomas

El asistente de primer arranque hablaba solo italiano, independientemente del navegador. Ahora se presenta en el idioma del navegador entre los cinco gestionados (italiano, inglés, francés, español, alemán) y, al elegir el idioma del usuario administrador, toda la página cambia a ese idioma de inmediato. Para un idioma no gestionado el repliegue es el inglés.

También están traducidos los mensajes que el asistente produce durante la configuración: resultado de la prueba de conexión, errores de validación de la cadena de conexión y confirmación de recreación de la base de datos de metadatos.

🐛 Correcciones destacables

  • El scaffolding automático del asistente no generaba los metadatos. En el primer arranque, con la casilla "Ejecutar scaffolding automático de las tablas de la BD seleccionada" marcada, la aplicación arrancaba con el menú vacío y sin rutas: el scaffolding se ejecutaba contra una conexión distinta de la recién elegida en el asistente. Ahora las conexiones elegidas en el asistente se usan realmente, y en el primer acceso el menú contiene las tablas del propio esquema.
  • Modificación o borrado sin clave: ahora rechazados. Si la carga útil de una actualización o un borrado no contenía ninguna columna reconocida por los metadatos, la cláusula WHERE generada quedaba vacía y la instrucción afectaba a todas las filas de la tabla, devolviendo además un resultado correcto. Es el caso de una clave primaria enviada con mayúsculas y minúsculas distintas de las del esquema. Ahora la operación se rechaza con HTTP 400 y el código errors.metaservice.crud.missing_key_predicate, y el mensaje enumera las claves recibidas para que la causa se entienda de inmediato.
  • Sin clave de Google Maps la aplicación quedaba bloqueada. La falta de la clave en GoogleMaps:ApiKey producía un error de JavaScript que subía hasta el diálogo de error de la aplicación y dejaba inutilizable toda la interfaz, no solo el mapa. Ahora el componente de mapa muestra un aviso discreto dentro de su propia vista y el resto de la aplicación sigue funcionando.
  • Scene 3D en el plan Professional. Las rutas del visor y del diseñador de Scene 3D declaran la función scene3d-designer como requerida, pero ningún plan la incluía: en cualquier instalación Professional la comprobación redirigía a la página de acceso denegado. La función ya forma parte del plan Professional.
  • Scripts de primer arranque dos órdenes de magnitud más pequeños. Los scripts de primer arranque contenían los datos de las tablas de registro, de las conversaciones del chatbot y de los contenidos de los paneles: registros de error y chats de desarrollo enviados dentro de cada paquete. Esas tablas viajan ahora solo con su estructura. El script de metadatos de primer arranque pasa de 468 MB a 3,7 MB en el perfil mínimo y a 14 MB en el del tutorial (los datos de demostración WideWorldImporters van aparte y mantienen su tamaño).
  • Documentación del chatbot alineada con el motor real. Las páginas de instalación seguían mencionando Python y un servicio aparte para el chatbot RAG. El motor es nativo .NET/ONNX y se ejecuta en el proceso de la aplicación desde la 1.3.0: no hace falta Python ni instalar nada aparte. También se ha corregido el tamaño de los modelos descargados en el primer uso, que es de unos 4,5 GB.
  • Cuatro páginas de documentación vacías (chatbot RAG, licencias, listas de distribución, tablas dinámicas) se han escrito, en los cinco idiomas.

🔧 Actualizaciones operativas recomendadas para quien actualiza

  1. Quien haya instalado con MySQL en Linux partiendo del paquete anterior debe reinstalar con esta versión: la carga de la base de datos se interrumpía y la instalación no era completa.
  2. Revisar las integraciones que escriben mediante las API CRUD: una llamada que hasta ahora actualizaba toda la tabla sin advertirlo ahora recibe HTTP 400. El mensaje de error enumera las claves recibidas, y la corrección casi siempre consiste en alinear el nombre de la clave primaria con las mayúsculas y minúsculas del esquema.
  3. Si se usa Scene 3D con una licencia Professional emitida antes de esta versión, solicitar una licencia actualizada: la función scene3d-designer debe estar incluida en el plan.
  4. Para una instalación nueva en Windows, usar el comando de un solo paso en lugar del procedimiento manual. En una instancia de SQL Server 2019, elegir la variante del tutorial con los scripts SQL.
  5. Si se usa el componente de mapa, configurar GoogleMaps:ApiKey en appsettings.json: sin clave el mapa muestra un aviso, pero el resto de la aplicación sigue siendo utilizable.

v1.7.1

Volver al índice

Versión publicada anteriormente: 1.7.0 (15 de agosto de 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


Una versión de consolidación con un frente nuevo — la instalación en Windows con un solo comando — y una serie de correcciones surgidas al instalar el producto desde cero en máquinas limpias, siguiendo la documentación al pie de la letra. Varias afectan a Linux, donde algunas cosas no funcionaban en absoluto: el chatbot faltaba en el paquete, los informes no se abrían y quien partía de las fuentes no lograba arrancar la aplicación.


💾 Instalación en Windows con un solo comando

Desde una ventana de PowerShell:

irm https://wuic-framework.com/install.ps1 | iex

El script hace por su cuenta todo lo que antes era una lista de pasos manuales: comprueba el runtime de ASP.NET Core 10 y lo instala si falta, busca una instancia de SQL Server accesible y, si no encuentra ninguna, instala SQL Server Express, descarga el último paquete publicado, lo extrae y abre el navegador en el asistente de primer arranque. Es el gemelo para Windows de install.sh y es compatible con Windows PowerShell 5.1, por lo que no requiere instalar PowerShell 7.

La aplicación se publica en IIS: el script habilita las funciones de IIS que falten, instala el ASP.NET Core Hosting Bundle, crea el grupo de aplicaciones y el sitio en el puerto elegido, y concede a la identidad del grupo los permisos sobre la carpeta y el inicio de sesión en SQL Server. Hace falta elevación: el script la pide una sola vez, con el aviso normal de Windows.

Con -Kestrel no se toca nada de IIS y la aplicación se ejecuta en una ventana de consola, reiniciable con start-wuic.cmd. Es la opción adecuada cuando no se tienen permisos de administrador, cuando IIS está deshabilitado por directivas corporativas o para una prueba desechable.

Las opciones más usadas: -WithTutorial descarga el paquete con la base de datos de demostración WideWorldImporters, -Port cambia el puerto, -ListenAll escucha en todas las interfaces en vez de solo en localhost, -SqlServer indica una instancia ya existente, -Dbms selecciona un motor distinto de SQL Server.

Un requisito que conviene conocer antes de elegir el paquete: la variante del tutorial en formato .bak contiene una copia de seguridad nativa de SQL Server 2022 y requiere por tanto SQL Server 2022 o superior, porque la restauración no es compatible con versiones anteriores. En SQL Server 2019 hay que usar la variante con scripts SQL, admitida desde 2019 en adelante; el instalador lo detecta por su cuenta y elige la variante adecuada para la instancia que encuentra.

En Windows Server el motor de base de datos debe instalarse antes. El comando obtiene los componentes que faltan mediante winget, que no está presente en Windows Server: sin una instancia ya accesible la instalación se detiene y lo indica. Vale para todos los motores, no solo para SQL Server.

🐧 Linux: el paquete por fin está completo

Quien instalaba en Linux se encontraba con tres cosas rotas, todas corregidas en esta versión.

El chatbot RAG no estaba. El motor de búsqueda semántica .NET/ONNX se incluía solo en los paquetes de Windows: cada tarball de Linux salía sin él y GET /api/Rag/Health respondía 503 rag-server-unreachable para siempre. El tarball ahora lo contiene, con las bibliotecas nativas linux-x64 completas: en una máquina con CUDA 12 y cuDNN 9 usa la GPU sin intervención manual, y en caso contrario recae en la CPU.

El motor semántico no encontraba sus propias bibliotecas nativas. Las buscaba en PATH, separadas por ;, que es la convención de Windows; en Linux el cargador usa LD_LIBRARY_PATH y dos puntos.

Los informes no se abrían. La ruta de la caché se construía con las barras invertidas de Windows y con una barra inicial, de modo que en Linux terminaba en la raíz del sistema de archivos en lugar de bajo la carpeta de la aplicación. El visor devolvía un error que parecía un problema de configuración.

Y para quien parte de las fuentes: la aplicación no arrancaba en absoluto. El paquete NuGet WuicCore incluía una protección antimanipulación cuyo código de inicialización no es compatible con el runtime de .NET en Linux, y fallaba antes de ejecutar una sola línea de la aplicación. En Windows esa misma biblioteca arrancaba sin problemas, motivo por el cual el defecto permaneció invisible tanto tiempo. La protección se ha eliminado; el resto de la ofuscación queda igual.

📦 Kit de fuentes: compila en una máquina limpia

El paquete para desarrolladores arrastraba algunas suposiciones que solo se cumplían en la máquina donde se construía.

  • El lock de dependencias viaja dentro del paquete. Sin él, npm install con npm 10.9.x — la versión que acompaña a Node.js 22 LTS, es decir la que la propia documentación exige — se detiene al resolver las dependencias peer. Ahora el lock está incluido, la instalación es reproducible y dos desarrolladores obtienen el mismo árbol.
  • Las bibliotecas 3D están declaradas. three, three-gpu-pathtracer, three-mesh-bvh y @dimforge/rapier3d-compat se importaban sin figurar entre las dependencias: en la máquina de quien desarrolla el framework estaban presentes por otras vías, en una máquina limpia la compilación se detenía en un import sin resolver. Son dependencias peer opcionales: quien no usa escenas 3D no se las lleva consigo.
  • Las rutas de los recursos de Angular apuntaban fuera del paquete y la compilación fallaba con archivos inexistentes.
  • El workspace preparado para asistentes LLM se generaba sin sus propios ajustes.

🌍 Asistente de primer arranque

El asistente hablaba solo italiano, independientemente del navegador. Ahora se presenta en el idioma del navegador entre los cinco admitidos (italiano, inglés, francés, español, alemán) y, al elegir el idioma del usuario administrador, toda la página cambia a ese idioma de inmediato. Para un idioma no admitido el recurso es el inglés. También están traducidos los mensajes producidos durante la configuración: resultado de la prueba de conexión, errores de validación de la cadena de conexión y confirmación de recreación de la base de datos de metadatos.

El scaffolding de una base de datos existente está ahora activo de forma predeterminada. Quien indicaba su propia base de datos y aceptaba los valores propuestos obtenía una aplicación sin ninguna ruta, con las tablas ignoradas. El modo tutorial no se ve afectado.

🐛 Correcciones destacadas

  • Modificación o borrado sin clave: ahora rechazados. Si la payload de una actualización o un borrado no contenía ninguna columna reconocida por los metadatos, la cláusula WHERE generada quedaba vacía y la instrucción afectaba a todas las filas de la tabla, devolviendo además un resultado correcto. Es el caso de una clave primaria enviada con mayúsculas y minúsculas distintas de las del esquema. La operación se rechaza ahora con HTTP 400 y el código errors.metaservice.crud.missing_key_predicate, y el mensaje enumera las claves recibidas para que la causa se vea de inmediato.
  • Mapas sin clave de Google: aviso en lugar de bloqueo. Cuando la Maps JavaScript API no está cargada — normalmente porque la clave no se ha configurado — el componente mostraba un diálogo modal que detenía toda la página. Ahora, en lugar del mapa, aparece un recuadro que explica qué falta, y el resto de la página sigue siendo utilizable.
  • Reinstalación sobre MySQL: se acabó el callejón sin salida. La contraseña del motor la genera el propio instalador; al reejecutar el comando en la misma máquina no lograba releerla, sondeaba con la contraseña vacía y concluía que la base de datos no respondía, cuando respondía perfectamente. También se ha corregido la comprobación de la versión mínima, que nunca llegaba a ejecutarse porque el aviso de MySQL sobre la contraseña en la línea de comandos acababa dentro de la salida analizada.
  • Scene 3D en el plan Professional. Las rutas del visor y del diseñador de Scene 3D declaran la función scene3d-designer como requerida, pero ningún plan la incluía: en cualquier instalación Professional la comprobación redirigía a la página de acceso denegado. La función forma parte ahora del plan Professional.
  • Los appsettings de ejemplo ya no contienen una contraseña real.
  • Documentación del chatbot alineada con el motor real. Las páginas de instalación seguían mencionando Python y un servicio aparte para el chatbot RAG. El motor es nativo .NET/ONNX y se ejecuta dentro del proceso de la aplicación desde la 1.3.0: no hace falta Python ni instalar nada por separado. También se ha corregido el tamaño de los modelos descargados en el primer uso, que es de unos 4,5 GB.
  • Cuatro páginas de documentación vacías (chatbot RAG, licencias, listas de distribución, tablas dinámicas) se han redactado, en los cinco idiomas.

📚 Requisitos corregidos en la documentación

Las páginas de inicio indicaban requisitos que no coincidían con lo medido instalando en máquinas limpias:

  • Node.js 22 LTS, no "20 o superior": es la versión con la que se prueba el paquete.
  • PowerShell 5.1 es suficiente. Los scripts incluidos funcionan con la PowerShell preinstalada en Windows; PowerShell 7 es recomendable, no obligatoria.
  • En Windows Server la base de datos debe instalarse antes del comando de instalación.

📦 Paquetes actualizados

Paquete De A
WuicCore (NuGet) 1.7.0 1.7.1
wuic-framework-lib (npm) 1.7.0 1.7.1

🔧 Actualizaciones operativas recomendadas para quien actualiza

  1. Revisar las integraciones que escriben mediante las API CRUD: una llamada que hasta ahora actualizaba toda la tabla sin advertirlo recibirá HTTP 400. El mensaje de error enumera las claves recibidas, y la corrección consiste casi siempre en alinear el nombre de la clave primaria con las mayúsculas y minúsculas del esquema.
  2. En Linux, sustituir el paquete por el de esta versión aunque la aplicación parezca funcionar: el chatbot RAG y el visor de informes no estaban operativos en versiones anteriores.
  3. Quien use Scene 3D con una licencia Professional emitida antes de esta versión debe solicitar una licencia actualizada: la función scene3d-designer debe estar incluida en el plan.
  4. Quien parta del kit de fuentes puede ejecutar npm install sin opciones adicionales: el lock incluido hace la instalación reproducible.
  5. Para una instalación nueva en Windows, usar el comando de un solo paso en lugar del procedimiento manual. En una instancia de SQL Server 2019 elegir la variante del tutorial con scripts SQL; en Windows Server instalar antes el motor de base de datos.

v1.7.0

Volver al índice

Versión publicada anterior: 1.5.0 (21 de julio de 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


Paquetes sustituidos el 15 de agosto de 2026. Los archivos publicados inicialmente incluían un appsettings.json con autoGeneratedQueryTimeout en 1: con ese valor, toda consulta que supere un segundo termina con un error del servidor. También habían quedado algunos ajustes de la cabecera (logotipo, orientación del menú, selector de temas, notificaciones) de una sesión de pruebas. Los archivos se han reconstruido y sus sumas de verificación actualizado.

Si descargaste antes del 15 de agosto: vuelve a descargar el paquete, o abre appsettings.json y devuelve autoGeneratedQueryTimeout a 30, eliminando las claves header-logo, header-logo-position, header-menu-orientation, header-show-theme-selector, header-menu-multicolumn-submenu y header-show-notifications si no las has definido tú. Ninguno de los dos ajustes afecta a los datos: basta con editar el archivo y reiniciar.


Tres semanas de trabajo en dos frentes. El primero es el aspecto: llega el Theme Builder, una página desde la que componer temas a medida — colores, tipografía, fondo, densidad, representación de la cuadrícula — que se aplican a todos los usuarios de la instalación, y la cabecera de la aplicación se ha rediseñado y hecho configurable. El segundo es la integración y la observabilidad: el nuevo Webhook Hub para recibir y enviar eventos con firma y reintentos, y el Performance Inspector que mide los tiempos de fetch y render por ruta. El chatbot aprende a actuar sobre otras tres superficies de la aplicación y a consultar el esquema de la base de datos.


🎨 Theme Builder

Una nueva página bajo Administración permite componer temas personalizados sin tocar código. Cada tema guardado aparece en el selector de temas de todos los usuarios de la instalación, junto a los predefinidos.

Qué se puede configurar:

  • Color principal, del que se genera la escala completa de 11 tonos: la escala sigue siendo pulsable, y elegir un tono más oscuro lo promueve a color principal. Una etiqueta indica la relación de contraste WCAG alcanzada (AAA / AA / AA-large / fail).
  • Superficies claras y oscuras, radio de las esquinas y densidad (cómoda o compacta).
  • Tipografía: familia tipográfica de un catálogo de fuentes del sistema o pila libre, y tamaño base que escala toda la interfaz.
  • Fondo de página: color sólido, degradado o imagen. El degradado puede tener una deriva lenta opcional que hace oscilar su inclinación con el tiempo; la imagen se configura con ajuste, repetición, posición y un velo oscuro para que el texto siga siendo legible.
  • Cuadrícula: las filas alternas y la fila seleccionada ya no son colores fijos sino mezclas entre la superficie y un acento, gobernadas por dos mandos de intensidad y con la opción de un acento distinto del color principal.
  • Modo claro/oscuro libre o impuesto por el tema.

La vista previa es en vivo y aplica el tema a toda la página mientras se compone, sin tocar las preferencias del usuario: al salir, recargar o cerrar el navegador vuelve el tema propio.

La exportación a Excel sigue el tema: un archivo exportado con un tema personalizado activo sale con los colores de ese tema — cabecera, filas alternas, bordes — en lugar de los grises genéricos. Se han añadido estilos de reserva para todas las familias de preajustes, de modo que un tema aún no muestreado hereda el aspecto de su familia.

El catálogo de temas predefinidos se amplía con nuevas variantes, y el tema activo se aplica ya en el primer fotograma tras una recarga, sin el parpadeo del tema anterior.

🖥️ Cabecera rediseñada y configurable

La cabecera de la aplicación es ahora un componente del framework: las instalaciones la heredan en lugar de mantener una copia. El bloque superior derecho se ha compactado — selector de temas, claro/oscuro, idioma, notificaciones y área de usuario viven en una tarjeta que se expande al pasar el ratón — y el área de usuario muestra nombre, rol, licencia y cierre de sesión.

Una nueva sección Header & Menu en los ajustes permite elegir la orientación del menú (horizontal arriba o abajo, vertical a la izquierda o a la derecha), cargar un logotipo y posicionarlo, y activar o desactivar el selector de idioma, el de temas y las notificaciones. También se puede desactivar la disposición automática en varias columnas de las entradas de submenú: en ese caso los submenús largos pasan a ser desplazables en vez de quedar cortados.

🔗 Webhook Hub

Nuevo sistema para integrar la aplicación con servicios externos, en ambas direcciones.

De salida: los eventos se encolan y se entregan de forma asíncrona, con firma HMAC del payload, reintentos a intervalo fijo o exponencial, cola de dead letter para las entregas fallidas definitivamente y posibilidad de reproducir una entrega. Cada intento queda registrado en los logs.

De entrada: el endpoint POST /api/webhooks/inbound acepta llamadas externas y las encamina según una configuración de metadatos — ejecución SQL, llamada HTTP o invocación de un método — con protección anti-replay.

Se incluyen además políticas de notificación con periodo de silencio configurable, una API administrativa para gestionar los endpoints y un job del planificador que vacía la cola. Toda la configuración — endpoints, eventos, suscripciones, reglas de entrada — vive en tablas de metadatos: añadir una integración no requiere ni código dedicado ni un nuevo despliegue. La página «Webhook Hub» de la documentación integrada recoge el procedimiento completo en 5 idiomas.

📈 Performance Inspector

El framework puede recoger métricas de fetch y render para cada ruta, agregarlas y mostrarlas en un panel administrativo: media, p95, máximo y recuento, con una retención de 7 días y activación ruta por ruta.

La función está desactivada de forma predeterminada y se habilita con AppSettings:enablePerformanceInspector, en hot-reload. Junto a las métricas hay un inspector de la calidad del dato, activable por ruta desde el props bag (extraProps.qualityInspector).

🤖 Chatbot: nuevas acciones y lectura del esquema

El chatbot RAG gana diez nuevos tipos de acción y la capacidad de consultar la estructura del proyecto.

  • Tres nuevas superficies contextuales: pivot builder, editor de ajustes y report designer. El chatbot propone acciones sobre la página en la que uno se encuentra. En el editor de ajustes los cambios solo se preparan: guardar sigue siendo un gesto explícito del usuario. En el volcado enviado al modelo los valores reservados — cadenas de conexión, contraseñas, claves, licencia — están enmascarados, y una lista de exclusión impide escribirlos. En el report designer se genera siempre un archivo nuevo con fecha y hora, sin tocar el informe abierto.
  • Operaciones sobre metadatos: creación de tabla, scaffolding de tablas, vistas y columnas, movimiento de entradas de menú. Las dos operaciones no reversibles — eliminar una columna y eliminar una entrada de menú — exigen una confirmación explícita verificada también en el servidor, de modo que se aplica incluso cuando la petición llega de un cliente sin interfaz.
  • Introspección: el chatbot puede enumerar conexiones (solo los nombres, nunca las cadenas de conexión), bases de datos, tablas, columnas y el árbol del menú. Sin estas lecturas no podía conocer los identificadores reales sobre los que operar.

Una nueva página de documentación enumera los prompts admitidos, verificada frente a las pruebas automáticas.

📊 Spreadsheet: visibilidad de columnas alineada con la cuadrícula

El spreadsheet respeta ahora los mismos indicadores de visibilidad que la list grid: mc_hide_in_list, mc_hide_in_edit y mc_show_in_filters. Una columna oculta en el listado ya no aparece en la hoja, y una columna oculta en edición ya no es editable en las celdas.

🛡️ Seguridad

Hardening best-effort en la generación asistida de informes: el nombre de archivo solicitado ahora se valida rechazando rutas absolutas y caracteres no permitidos, con una comprobación que se comporta igual en Windows y en Linux — antes se apoyaba en una normalización que filtraba de forma distinta en ambos sistemas. El error devuelto distingue una configuración no válida de un fallo de generación, de modo que quien integra el framework no busca el problema en el sitio equivocado.

🐛 Correcciones destacadas

  • Calendario, primera carga: la vista mostraba datos no filtrados por el intervalo visualizado — normalmente ningún evento en el mes actual, aun habiendo citas. La primera carga se lanzaba antes de que estuvieran disponibles los campos de inicio y fin configurados para el arquetipo, y ninguna petición posterior lo corregía. Ahora los campos se resuelven antes de componer el filtro y, si llegan después, los datos se vuelven a pedir una sola vez.
  • Escenas 3D con licencia professional: las páginas del diseñador y del visor 3D redirigían a la pantalla de acceso denegado, porque la funcionalidad no estaba incluida en ningún perfil de licencia. Ahora forma parte del perfil professional.
  • Informes en Linux: la generación asistida de un informe fallaba porque las fuentes se gestionaban mediante una biblioteca gráfica disponible solo en Windows.
  • Performance Inspector, agregación: dos ejecuciones solapadas del trabajo de agregación — el panel lo lanza en su propia recarga y además puede ejecutarse a mano — terminaban con un error de clave duplicada. Además, la ventana de datos en bruto no estaba alineada con el límite del bucket diario, por lo que el bucket más antiguo se reconstruía a partir de un subconjunto de los eventos.
  • Linux tras un proxy inverso: las URL absolutas generadas por el backend perdían el puerto y usaban el esquema equivocado cuando la instalación se sirve en un puerto no estándar o solo por HTTP.
  • Oracle, guardado de escenas 3D: el guardado fallaba por el uso de un nombre de parámetro reservado y por la conversión de los valores numéricos. Corregidos ambos, junto con el tratamiento de las columnas con nombre en minúsculas entrecomillado.
  • Oracle, exposición OData: las columnas se forzaban a mayúsculas en lugar de usar el nombre físico declarado en los metadatos, lo que hacía inalcanzables las entidades con nombres mixtos.
  • PostgreSQL y Oracle, lookups en gráficos y agrupaciones: el campo descriptivo de un lookup no se resolvía del nombre lógico al físico, y la agrupación mostraba valores vacíos o erróneos.
  • Chatbot, confirmaciones ausentes: en cuatro puntos la petición de confirmación no aparecía nunca por una llamada mal formada; en dos de ellos el borrado (historial y sesiones del chat) ocurría sin preguntar nada. Ahora toda confirmación pasa por el mismo camino y, ante un error, la respuesta es «cancelar».
  • Importación de metadatos: las rutas cuyo campo de base de datos está vacío — es decir, las que usan la base de datos predeterminada de la aplicación — no podían importarse, y el error sugería un problema de permisos o una base de datos equivocada.
  • Visor 3D: la escena ocupaba una franja horizontal en lugar de la altura completa de la página.
  • Interfaz, cuadrícula sobre fondo temático: el área bajo la última fila dejaba traslucir el fondo de la página, haciendo que la cuadrícula pareciera agujereada. Ahora la superficie de la cuadrícula sigue el tema, en claro y en oscuro.

🔧 Actualizaciones operativas recomendadas para quien actualiza

  1. Revisar appsettings.json tras la actualización: las claves nuevas tienen valores predeterminados prudentes y no requieren intervención, pero es un buen momento para repasarlas.
  2. Performance Inspector: poner AppSettings:enablePerformanceInspector en true para activarlo; permanece inactivo si la clave no existe.
  3. Webhook Hub: no hace falta ninguna intervención para que sea accesible. Tablas, rutas administrativas y entradas de menú — agrupadas en un submenú «Webhook Hub» bajo Administración — se crean en la primera carga del menú, tanto en una instalación nueva como al actualizar desde una versión anterior. Queda por configurar la integración: de salida son tres filas (el endpoint con URL de destino, secreto compartido, tiempo de espera y política de reintento; el evento; la suscripción que los enlaza), de entrada un endpoint con dirección inbound y una regla de encaminamiento. La firma viaja en la cabecera X-Wuic-Signature; el procedimiento completo está en la página «Webhook Hub» de la documentación integrada.
  4. Theme Builder: la tabla de temas se crea en el primer guardado. Si se usan temas personalizados, comprobar la exportación a Excel de una cuadrícula para confirmar que los colores son los esperados.
  5. Chatbot: las nuevas acciones están disponibles tras reiniciar el motor RAG; las operaciones no reversibles exigen confirmación y no pueden aplicarse sin ella.
  6. Linux tras un proxy inverso: si la instalación responde en un puerto no estándar o solo por HTTP, regenerar la configuración de nginx o alinear a mano el vhost existente con proxy_set_header Host $http_host; y proxy_set_header X-Forwarded-Proto $scheme;. Las actualizaciones no reescriben un vhost ya presente.

v1.5.0

Volver al índice

Versión publicada anterior: 1.3.2 (18 de junio de 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


Una versión amplia que reúne trabajo en varios frentes. El chatbot RAG estrena una configuración LLM simplificada y unificada, con la ejecución de un modelo local gratuito (Qwen vía Ollama) ahora como opción de primera clase y un motor endurecido frente a las particularidades de los modelos locales; un nuevo plugin para Visual Studio Code, WUIC Assistant, lleva el mismo enfoque agéntico dentro del editor. El nuevo Scene3D Designer trae la creación de escenas 3D dentro de la aplicación — materiales PBR, efectos de shader, luces con baking, física y un visor que vincula los objetos a los datos — y el renderizado ahora se puede elegir entre WebGL y WebGPU. El Workflow Designer incorpora un paquete de creación asistida (plantillas, validación del grafo, diálogos guiados, ayuda en línea) y el diseñador de dashboards un conjunto de mejoras de edición.


🤖 Chatbot RAG — configuración LLM unificada

La configuración del proveedor LLM del chatbot se ha consolidado en torno a una sola clave y una lista explícita de proveedores.

  • rag-llm-provider — anthropic / openai / openrouter / ollama, a configurar explícitamente (sin proveedor por defecto: si está vacío, el chatbot permanece en retrieval-only y no invoca ningún LLM). ollama es ahora un valor de primera clase: apunta a un runtime local vía rag-llm-base-url, con formato compatible con OpenAI.
  • rag-llm-api-key — la única fuente de la clave, independiente del proveedor elegido. Sustituye al anterior par llm-api-key / anthropic-api-key (aceptados solo como fallback de migración). El valor especial agent-sdk usa el Agent SDK (claude CLI) vía subscription en lugar de la API de pago, si está instalado.
  • rag-llm-base-url — override del endpoint; obligatorio para ollama (p. ej. http://HOST:11434/v1), opcional para los demás proveedores.
  • rag-llm-default-chat-model — id del modelo para el proveedor elegido.

Todas las claves siguen en hot-reload desde appsettings.json: cambiar de proveedor o modelo no requiere reinicio.

🧠 LLM local gratuito (Qwen vía Ollama), sin API key

El chatbot puede ahora ejecutarse por completo sobre un modelo local abierto y gratuito — por ejemplo Qwen (qwen2.5-coder:32b) servido por Ollama en la propia máquina o en la LAN — sin API key y sin coste por token. Configuración típica en appsettings.json -> AppSettings:

rag-llm-provider           = ollama
rag-llm-base-url           = http://HOST:11434/v1
rag-llm-api-key            = ollama
rag-llm-default-chat-model = qwen2.5-coder:32b

En el paquete se incluye una guía completa para montar el servidor Ollama (Windows/Linux, exposición en LAN, tuning del context, arranque persistente).

⚙️ Acciones del chatbot fiables incluso con modelos locales

El motor se ha hecho tolerante a las particularidades de los modelos locales, que — a diferencia de los modelos comerciales — a veces no respetan al pie de la letra el formato de las llamadas a herramienta. El chatbot ahora recupera correctamente la acción propuesta incluso cuando el modelo la emite como texto o con escapes JSON no estándar. En la práctica, las acciones sobre el diseñador y sobre los metadatos — botones de tabla (bulk), botones de fila, estilos condicionales, callbacks, inyección de componentes en el diseñador — se proponen y aplican de forma fiable incluso con un LLM local.

🧩 Asistente agéntico en VS Code — WUIC Assistant

El paquete incluye ahora un plugin para Visual Studio Code, WUIC Assistant (llm-workspace/plugin/wuic-assistant.vsix): un asistente que ya conoce las convenciones del framework y opera directamente sobre el proyecto abierto. Genera componentes Angular (cards, dashboards con tiles KPI, list-grids con navegación al formulario de edición), componentes alimentados por un endpoint .NET personalizado, y propone cambios de metadatos (estilos condicionales, acciones de tabla y de fila, lookups). Cada escritura pasa por una vista previa antes de la confirmación.

Usa el mismo RAG local de WUIC a través del servidor MCP wuic-rag (arrancado automáticamente) y el grounding ya presente en el proyecto, por lo que no requiere configuración manual del servidor MCP. El modelo LLM es a elección — local vía Ollama (Qwen, sin API key) o Anthropic.

Instalación desde el ZIP:

code --install-extension llm-workspace/plugin/wuic-assistant.vsix

Alternativamente lo instala install-llm-workspace.ps1. Luego Ctrl+Shift+P -> WUIC Assistant: Apri Chat; el proveedor se elige en los ajustes (wuicAssistant.provider = ollama o anthropic).

🧊 Scene3D Designer (novedad)

Un nuevo diseñador 3D visual en la ruta #/scene3d_designer, publicado en solo lectura a través del Scene3D Viewer (#/scene3d_viewer/:scene_key). Permite componer una escena tridimensional y vincular sus objetos a los datos de la aplicación.

  • Paleta e importación: primitivas (cubo, esfera, plano, cilindro, cono, toro), grupos, luces, cámara, texto 3D y Mesh Repeater (instancias generadas desde los datos). Importación de modelos externos en glTF/GLB, OBJ, FBX, STL y DAE. La paleta es extensible desde metadatos con tipos personalizados.
  • Materiales PBR: metalness, roughness, emisivo, opacidad, wireframe, flat shading y caras; para el material físico además transmission, IOR, grosor y absorción volumétrica (vidrio de color).
  • Efectos de shader: un efecto descrito en JSON (respaldado por esquema, con autocompletado y una vista "de estructura") se compila para el renderizador activo; como alternativa, shaders GLSL escritos a mano en el renderizador WebGL.
  • Iluminación: luces de escena con sombras suaves, baking de la iluminación estática en los colores de vértice (unlit) y — en el renderizador WebGL — un path tracer de vista previa fotorrealista.
  • Animación y física: controles de transporte para los clips de los activos importados; física opcional por objeto con simulación Play/Stop en el diseñador y autoplay en el visor.
  • Vinculación a datos: cada objeto se vincula a una ruta WUIC (con registro opcional) y mapea propiedades visuales (etiqueta, color, visibilidad) a columnas; al hacer doble clic en un objeto vinculado en el visor se abre el CRUD del registro.
  • Miniaturas automáticas: al guardar, la escena se captura desde el canvas y se muestra como vista previa en la lista "Cargar escena", sin configuración ni proceso externo.

Las rutas del diseñador y del visor requieren la función scene3d-designer. Las tablas de soporte se crean y actualizan automáticamente en el primer uso, en todas las bases de datos compatibles.

🖥️ Renderizador WebGPU (opt-in)

El renderizado de la escena y del visor ahora se puede elegir entre WebGL (por defecto) y WebGPU (activable desde la barra de herramientas). Cuando WebGPU no está disponible en el navegador, el diseñador permanece en WebGL automáticamente. El modo elegido se guarda con la escena y se restaura al abrir. Con el renderizador WebGPU activo, el baking de luces se ejecuta en la GPU (sombras incluidas), mucho más rápido en escenas densas; los shaders GLSL escritos a mano y el path tracing siguen disponibles en el renderizador WebGL.

🔀 Workflow Designer — creación asistida

El diseñador de workflows (#/workflow-designer) ahora acompaña la construcción de un proceso desde cero.

  • Plantillas de inicio: "Nuevo desde plantilla" genera un grafo listo para los patrones comunes (aprobación simple, cola claim/release, cadena por umbrales, tareas paralelas): se eligen la ruta principal y — donde haga falta — el campo de estado, y el grafo, las acciones y las transiciones nacen ya conectados.
  • Validación del grafo: "Validar grafo" señala los problemas antes de guardar (start sin salidas, nodos inalcanzables, acción sin objetivo, condición vacía, rama muerta, timer o split incompletos, permiso con un rol inexistente). Al hacer clic en un aviso, el canvas encuadra el nodo. Guardar nunca se bloquea: con problemas abiertos aparece un resumen con "Guardar de todos modos".
  • Configuraciones guiadas: los diálogos de timer y de tareas paralelas usan desplegables y un autocompletado de rutas en lugar de campos de texto libre escritos de memoria.
  • Incorporación y ayuda: una lista de primeros pasos en un canvas vacío, tooltips descriptivos en la paleta y una "Guía rápida" con una leyenda de las formas y un glosario de conceptos (transición, guarda, permiso, acción interna).

🎨 Diseñador de dashboards — edición más rápida

  • Ajuste a la cuadrícula: se activa desde el menú de acciones del diseñador, muestra la cuadrícula en el canvas y alinea automáticamente el arrastre, el redimensionado y los drops desde la paleta. Al activarlo, los elementos ya presentes en el canvas también se alinean a la cuadrícula.
  • Flujo normal / absoluto: nuevo flag en el menú de acciones (por defecto: flujo normal, sin cambios para los dashboards existentes). En modo absoluto los elementos soltados se posicionan en las coordenadas del drop, fuera del flujo: redimensionar uno no desplaza los demás. El drop dentro de un contenedor usa el contenedor como referencia de posición, y el runtime reconoce automáticamente los dashboards guardados en este modo.
  • Atajos de teclado: Supr/Backspace elimina el elemento seleccionado, las flechas lo desplazan, Ctrl+Z/Ctrl+Y deshace/rehace. Arrastrando un rectángulo de selección desde un área vacía del canvas se seleccionan varios elementos: las flechas y Supr actúan sobre toda la selección.
  • Importación/exportación de JSON y presets: el dashboard actual se exporta como archivo JSON re-importable (idéntico al contenido persistido), útil para llevar layouts entre entornos. Los presets guardan layouts reutilizables con un nombre y se reaplican con un clic.
  • Mover entre pestañas: desde el menú contextual de un elemento dentro de una pestaña, Mover a nueva pestaña crea una pestaña nueva y migra allí el elemento (bindings y estado preservados); Mover a otra pestaña — disponible cuando el tabview tiene varias pestañas — lo mueve a una pestaña existente a elección. La pestaña de destino se activa automáticamente, igual que una pestaña recién soltada.
  • Importar dashboard/preset en un elemento: desde el menú contextual de un contenedor se importa un dashboard guardado o un preset directamente dentro del elemento; los identificadores de los elementos importados se regeneran y las referencias internas (datasources incluidos) se remapean, sin colisiones con el contenido existente.

🐛 Correcciones de errores destacadas

  • Diseñador — layout multi-columna: la inyección de un layout de varias columnas/áreas (p. ej. "3 columnas, cada una con una grid") propuesta por el chatbot ahora rellena correctamente todas las áreas. Antes, tras la primera celda, las siguientes no se resolvían y los componentes quedaban vacíos.
  • Chatbot — whitelist de rutas: al pedir que se vincule un componente a una ruta con un nombre inexacto (p. ej. "provincie" por "stateprovinces"), el chatbot realiza ahora el match semántico y propone la acción, en lugar de responder erróneamente que la lista de rutas se está cargando.
  • Visor 3D — navegación entre escenas: al abrir escenas distintas en secuencia desde el mismo visor, ahora cada una carga su propia escena. Antes el visor podía seguir mostrando la primera escena abierta.
  • Editor JSON con esquema: el editor de código en modo JSON ofrece ahora una vista "de estructura" (activable con un interruptor) para añadir y quitar propiedades tipadas guiadas por el esquema, sin escribir JSON a mano.

🔧 Actualizaciones operativas recomendadas para quienes actualizan

  1. Para usar un LLM local gratuito, asignar en appsettings.json -> AppSettings: rag-llm-provider=ollama, rag-llm-base-url, rag-llm-api-key (valor de marcador, p. ej. ollama) y rag-llm-default-chat-model.
  2. Migrar la clave del chatbot a rag-llm-api-key: las anteriores llm-api-key y anthropic-api-key siguen funcionando como fallback, pero la configuración recomendada usa solo rag-llm-api-key.
  3. Para el asistente en VS Code, instalar el plugin desde el ZIP: code --install-extension llm-workspace/plugin/wuic-assistant.vsix (o dejar que lo instale install-llm-workspace.ps1).
  4. Para usar el Scene3D Designer, habilite la función scene3d-designer en la licencia activa. Las tablas de soporte se crean y migran automáticamente en el primer uso; el renderizador WebGPU es opt-in desde la barra de herramientas, con fallback automático a WebGL.

v1.3.2

Volver al índice

Versión publicada anterior: 1.3.0 (11 de junio de 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


Una versión de consolidación sobre el chatbot RAG introducido en 1.3.0: el modelo conversacional ya no está atado a Anthropic — cualquier endpoint compatible con OpenAI, incluidos runtimes locales como Ollama con modelos abiertos (Qwen), es ahora configurable y funciona sin API key. Junto a esto, una serie de correcciones en el instalador de first-run, en el paquete de fuentes y en el scaffolding de metadatos que aparecían en instalaciones nuevas, además de un workspace listo para los asistentes de IA de programación.


🤖 Chatbot RAG — proveedor de LLM flexible (incluido local y gratuito)

El modelo conversacional del chatbot es ahora independiente del proveedor. Además de Anthropic, se soportan endpoints compatibles con OpenAI, lo que incluye runtimes locales (p. ej. Ollama): se pueden ejecutar modelos abiertos y gratuitos como Qwen en la propia máquina, sin API key y sin coste por token.

  • rag-llm-provider — anthropic (por defecto) / openai / openrouter. Selecciona el dialecto wire del proveedor.
  • rag-llm-base-url — override del endpoint; al indicar la URL de un servidor local (p. ej. http://localhost:11434/v1 para Ollama) el chatbot habla con el modelo en local.
  • rag-llm-default-chat-model — id del modelo para el proveedor elegido (p. ej. un modelo Qwen en Ollama).
  • llm-api-key — clave del proveedor activo; para runtimes locales que no la validan basta un valor de marcador (p. ej. ollama). La histórica anthropic-api-key sigue siendo válida cuando rag-llm-provider=anthropic (sin migración).

Todas las claves se recargan en hot-reload desde appsettings.json: cambiar de proveedor o modelo no requiere reinicio.

Retrieval más preciso — se ha afinado el re-ranking de los resultados: el chatbot cita fuentes más pertinentes en las consultas en lenguaje natural.

Notificaciones de setup — en el primer uso el motor .NET descarga los modelos ONNX bajo demanda. El administrador recibe ahora en la campana las notificaciones de inicio / listo / error de la descarga, en los cuatro proveedores de BD, incluso cuando la inicialización la dispara una petición sin usuario autenticado.

Aceleración GPU automática — en una máquina con GPU NVIDIA el motor usa la GPU sin instalar CUDA: en el primer arranque, además de los modelos ONNX, descarga bajo demanda también el runtime CUDA 12 + cuDNN 9 necesario (~1,8 GB, una sola vez, solo si hay GPU) y lo configura por sí mismo. Sin GPU → CPU, sin descarga adicional. Override manual con rag-engine-cuda-path.


🧩 Workspace listo para asistentes de IA de programación

Las aplicaciones generadas con el framework incluyen ahora una colección de archivos markdown de contexto (descripción del proyecto, convenciones, reglas operativas) en la raíz del workspace. Estos archivos hacen que los asistentes de IA agénticos — Continue, Cline, Cursor y similares — conozcan de inmediato la estructura y las convenciones de WUIC, sin instalar ninguna extensión propietaria. Cualquier cliente que lea el contexto del workspace se comporta como un asistente "WUIC-native".


🐛 Correcciones destacadas

  • Instalador de first-run — modo no tutorial en todos los proveedores de BD: la instalación con scaffolding de una base de datos existente (sin los datos de ejemplo del tutorial) se ha corregido y unificado en todos los proveedores soportados — SQL Server, MySQL, PostgreSQL y Oracle. Resueltos los fallos por diferencias de dialecto SQL, selección de la base de datos/esquema de destino y gestión de conexiones que aparecían fuera del modo tutorial.

  • Instalador de first-run — ruta por script SQL (non-BAK): al aprovisionar la BD de metadatos mediante el script SQL incremental (alternativa al restore desde un .bak), el parser de los lotes separados por GO gestionaba mal algunos separadores, provocando el fallo de la creación del esquema en instalaciones nuevas. El splitter se ha corregido y las instalaciones por script se completan correctamente.

  • Paquete de fuentes — motor RAG .NET no encontrado en runtime: en el paquete de fuentes (-src-) el motor WuicRagEngine.dll se colocaba en la raíz del paquete, mientras que el ejecutable, arrancado desde bin/, lo buscaba junto a sí mismo — el chatbot RAG no arrancaba ("WuicRagEngine.dll no encontrado"). El loader busca ahora la carpeta rag-engine/ en varias ubicaciones (salida de build, content-root, working directory) y encuentra el motor en ambos layouts de deploy.

  • First-run — persistencia de la API key del chatbot: la clave LLM introducida en el asistente de primera instalación se escribe ahora en el appsettings.json canónico que realmente lee el runtime. Antes, en algunos layouts, podía acabar en una copia que el proceso nunca lee, dejando el chatbot sin clave justo tras la instalación.

  • Scaffolding de metadatos — diagnóstico y robustez: el scaffolding de los metadatos de ciertas tablas podía fallar con un mensaje genérico ("Unable to scaffold metadata table") que ocultaba la causa real. El error SQL efectivo se propaga ahora hasta el llamador, y el caso que lo provocaba está resuelto.

  • Paquete de fuentes — notificaciones en tiempo real en dev: en el paquete -src-, el proxy del dev-server (ng serve) no reenviaba las conexiones WebSocket al backend; el canal de notificaciones (/ws) entraba en timeout y las actualizaciones solo aparecían al recargar la página manualmente. El proxy ahora reenvía también los WebSocket: las notificaciones llegan en tiempo real.


📦 Paquetes actualizados

Paquete De A
WuicCore 1.3.0 1.3.2
Wuic.Webcore 1.3.0 1.3.2
WuicOData 1.3.0 1.3.2
RuntimeEfCore 1.3.0 1.3.2
Wuic.MySqlProvider 1.3.0 1.3.2
Wuic.PostgresProvider 1.3.0 1.3.2
Wuic.OracleProvider 1.3.0 1.3.2
wuic-framework-lib (NPM) 1.3.0 1.3.2

🔧 Acciones operativas recomendadas para quien actualiza

  1. Para ejecutar el chatbot con un modelo local y gratuito (p. ej. Qwen vía Ollama): poner rag-llm-provider=openai, rag-llm-base-url en el endpoint local (p. ej. http://localhost:11434/v1) y rag-llm-default-chat-model en el id del modelo; asignar a llm-api-key un marcador (p. ej. ollama) si el runtime no la valida. Sin reinicio: las claves son hot-reload.
  2. Para seguir en Anthropic no hay que hacer nada: anthropic-api-key sigue funcionando con rag-llm-provider=anthropic (por defecto).
  3. El paquete de fuentes (-src-) es más ligero: ya no incluye las DLL de framework redundantes en la raíz, que dotnet build vuelve a crear a partir de los paquetes NuGet. Descargar el nuevo -src- no requiere ninguna acción.
  4. En el primer uso del chatbot con el motor .NET, el administrador verá en la campana el progreso de la descarga de los modelos ONNX. Esperar la notificación "listo" antes del primer Ask.
  5. Las apps nuevas generadas incluyen automáticamente los archivos de contexto para asistentes de IA en la raíz del workspace; para las apps existentes pueden regenerarse.

v1.3.0

Volver al índice

Versión anterior publicada: 1.2.1 (31 de mayo de 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


Versión menor centrada en la integración del chatbot RAG en el lado del framework: historial de conversación persistente, gestión automática del contexto, configuración hot-reload desde appsettings.json y esquema cross-DBMS aplicado automáticamente al primer arranque. Junto a la feature principal, algunos fixes al scaffolder de metadatos y a la robustez del repositorio de chat sobre MySQL/Oracle que aparecían en escenarios de aprovisionamiento de DB nuevas.

El chatbot es el primer componente WUIC con estado en el servidor (_rag_chat_sessions + _rag_chat_messages) que se extiende a los cuatro providers soportados sin configuración manual del esquema. El primer Ask detecta el provider, aplica en orden los parches SQL incrementales y arranca. Con esta release el stack de serving puede además ejecutarse nativamente sobre .NET (motor ONNX in-process), haciendo el deploy al cliente independiente de Python.


🤖 Chatbot RAG — gestión del contexto end-to-end

El componente <wuic-rag-chatbot> ahora persiste múltiples sesiones por usuario, con historial completo de la conversación, summarization automática del contexto y configuración vía appsettings.json. La feature es opt-in: sin anthropic-api-key configurada el chatbot permanece inactivo.

Sesiones

  • Historial de conversación persistido por usuario. La sesión sobrevive a los reload del navegador y a los cambios de route.
  • Popup de selección de sesiones ordenadas por updated_at descendente, con título derivado del primer prompt (truncado a 100 caracteres + tooltip completo).
  • Renombre inline con persistencia inmediata.

Gestión automática del contexto

  • Visual cue % en el header del chatbot: un círculo de color que indica el consumo de la ventana de contexto del modelo (verde <60% / amarillo 60-80% / naranja 80-90% / rojo >90%). El valor proviene de los tokens realmente consumidos por la API de Anthropic y se persiste por turno, así sobrevive al reload.
  • Auto-compact pre-Ask: cuando la conversación supera el umbral configurable (default 30 turns) y hay al menos 10 turns aún no resumidos, el backend lanza un compact best-effort en background antes del siguiente Ask. El resumen actualizado se inyecta en el system prompt de los turns futuros.
  • Compact bajo demanda: el usuario puede forzar un compact vía slash command /compact o haciendo clic en el círculo cue.
  • Memory facts: el modelo mismo puede "pinear" hechos high-priority vía tool use (remember_fact/forget_fact). Los hechos permanecen en el system prompt incluso tras un compact (máx. 20, eviction FIFO).
  • Follow-up questions: el modelo sugiere hasta 3 preguntas de seguimiento, renderizadas como chips clicables debajo de la respuesta. Click = rellena el input box (no envía automáticamente).

Configuración appsettings.json

  • anthropic-api-key — API key de Anthropic, hot-reload. No hard-coded, nunca commitear al repo.
  • anthropic-default-chat-model — claude-haiku-4-5-20251001 (200k, default) / claude-sonnet-4-5-20250929 / claude-opus-4-5. Determina la ventana de contexto y el driver del visual cue.
  • anthropic-auto-compact-threshold — entero >=0, default 30. Poniendo 0 se deshabilita el auto-compact (sigue disponible el /compact manual).

Auto-migración cross-DBMS

El esquema del chat history (5 patches incrementales) se aplica de forma idempotente en el primer Ask, sobre el provider configurado (MSSQL / MySQL / PostgreSQL / Oracle). Ningún paso DBA requerido en instalaciones existentes.


🛠️ Acciones que el chatbot puede aplicar al proyecto

Además de responder en lenguaje natural, el chatbot puede proponer cambios concretos al proyecto como chips de acción con un botón "Aplicar". Cada chip muestra lo que hará (route objetivo, código generado, motivación) y el usuario decide si aplicarlo. Nada se ejecuta sin un clic explícito.

Tipos de acción soportados:

  • Acciones de toolbar y de fila — añade botones personalizados a la toolbar de una <wuic-list-grid> o a la acción de una sola fila, con callbacks JavaScript generados. Ejemplos: "añade una acción que exporte las filas seleccionadas a CSV", "pon un botón Aprobar en cada fila".
  • Estilos condicionales de fila y columna — aplica clases CSS a una fila o a una celda individual según una condición JS. Ejemplos: "resalta en rojo las filas con plazo vencido", "pon fondo verde a la celda estado cuando vale 'OK'".
  • Fórmula de visualización de columna — sustituye la representación de una columna en lista por una plantilla HTML/Angular personalizada (badge, icono, enlace, porcentaje coloreado). Ejemplo: "muestra prioridad como un badge verde/amarillo/rojo".
  • Fórmula del título del formulario — calcula dinámicamente el título del formulario de edición de un registro a partir de su contenido. Ejemplo: "el título debe ser Cliente {razón_social}".
  • Valor por defecto y validación personalizada — genera callbacks para valores por defecto al abrir el formulario (precarga de campos) o para validación compleja (cross-field, regex personalizados). Ejemplos: "default fecha_creación = hoy", "valida que email termine en @empresa.es".
  • Selection-changed y lifecycle callbacks — hooks en eventos del formulario (cambio de selección de registro, before-save, after-save, after-delete) para side-effects personalizados: refresh de datasources vinculados, notificaciones, audit log de aplicación.
  • Cambios de metadata — aplica modificaciones directas a los metadatos de tabla/columna (caption, ordenación, ocultar en list/edit, validaciones básicas) sin pasar por el editor manual de metadatos.
  • Snippets SQL en los metadatos (super-admin) — escribe fragmentos SQL directos en los campos de metadatos que se concatenan en tiempo de ejecución en las consultas autogeneradas: JOIN personalizado en la route, SELECT clause personalizado en una columna, fórmula de columna calculada, expresión de visualización de lookup. Ejemplos: "calcula total en orders como price × quantity", "añade join a payments en invoice_id". El chatbot conoce el dialecto del provider activo (mssql/mysql/postgres/oracle) y genera SQL con el quoting/sintaxis correctos. Operación gated D3: requiere privilegios super-admin en el backend, con audit log automático en _error__logs por cada aplicación.

🎨 Acción nueva: layout del designer desde lenguaje natural

Cuando el usuario está en la página Designer de un dashboard, el chatbot expone una nueva familia de acciones que actúa directamente sobre el canvas del designer (no sobre los metadatos persistidos).

Patrones de prompt soportados:

  • "añade una grid vinculada a la route cities" → inyecta DATASOURCE + DATAREPEATER configurados y vinculados;
  • "crea un layout tabular 2×2" → inyecta una <table> 2×2 con celdas listas para recibir otros componentes;
  • "pon un splitter vertical con 3 áreas" → inyecta un SPLITTER configurado;
  • "cambia el color del recuadro arriba a la derecha a rojo" → modifica la propiedad backgroundColor del componente identificado;
  • "añade una columna a la tabla" / "quita la fila 2" → modifica cols/rows del componente TABLE seleccionado;
  • "elimina el KPI de Facturación" → elimina un componente del canvas por su nombre.

El chatbot conoce el catálogo completo de las 31 herramientas del designer (grupos HTML, DATA, CONTAINER) y sus propiedades editables. Cuando el usuario menciona una route de metadatos con un nombre aproximado ("provincies" en lugar de "stateprovinces"), el chatbot hace fuzzy-match contra las routes disponibles en el proyecto y muestra el nombre real resuelto en el rationale de la acción.

Los cambios permanecen en el canvas del designer hasta que el usuario hace clic en "Guardar dashboard" — sin escrituras automáticas en BD, el resultado visual siempre se revisa antes del commit. El undo/redo del designer también cubre las acciones inyectadas por el chatbot.


⚙️ Motor RAG nativo .NET (deploy sin Python)

El stack de serving del chatbot RAG puede ahora ejecutarse enteramente sobre .NET, sin un servidor Python separado ni virtual environment en la máquina de destino. Los modelos de retrieval (embeddings + reranker) se cargan in-process mediante ONNX Runtime, con aceleración GPU (CUDA) detectada automáticamente y fallback transparente a CPU.

  • Activación vía appsettings.json: rag-use-dotnet-engine=true selecciona el motor .NET; el valor por defecto false mantiene el comportamiento anterior.
  • rag-engine-device (auto / cpu / cuda) elige el device de inferencia; rag-engine-profile controla el nivel de redacción de las fuentes citadas en las respuestas.
  • En el primer arranque los artefactos necesarios (modelos ONNX + índice) se descargan on-demand, así el paquete base se mantiene ligero.

Resultado práctico: el deploy al cliente es solo .NET — sin instalación de Python ni dependencias nativas adicionales más allá del runtime .NET. La llamada al modelo conversacional y la pipeline de retrieval y acciones son idénticas entre los dos motores.


🐛 Correcciones notables

  • Documentación de callbacks alineada con el runtime: el recetario de callbacks describía firmas que no correspondían al comportamiento real en dos casos. El default value callback escribe el valor en el record (record[field.mc_nome_colonna] = ...) y el return se ignora; la validación custom recibe (record, field, vr, wtoolbox) y comunica el resultado con un return booleano (false bloquea el guardado) más vr.message para el texto mostrado. Los ejemplos anteriores, basados en validateResult(...) y en un return para el default value, producían callbacks que no se aplicaban. Documentación corregida en los cinco idiomas.

  • Fiabilidad de las acciones propuestas por el chatbot: para las peticiones de acción el chatbot ahora emite de forma determinista la chip de acción correspondiente, y reintenta automáticamente ante un rate-limit transitorio del modelo conversacional en lugar de degradar silenciosamente a respuesta solo texto.

  • Scaffolder de metadatos — distinción date vs datetime consolidada: completado el follow-up del fix introducido en 1.2.1 sobre los tipos temporales generados. El parser de tipos origen cubre ahora también variantes DDL atípicas (MySQL DATETIME(0) sin precision, PostgreSQL timestamp desnudo sin time-zone qualifier, Oracle TIMESTAMP(n) con precision explícita) — todas siguen mapeando correctamente al UI type datetime preservando el componente time al guardar.

  • Suggest en campos metadata — mc_suggest_value_callback ahora normaliza el return value: el callback configurable desde DB podía devolver una promise o un valor síncrono, pero el parser runtime solo aceptaba el caso síncrono. Resultado: el suggest fallaba silenciosamente en callbacks async. La normalización ahora espera Promise.resolve(callback(...)) de forma uniforme.

  • Repositorio chat — Guid cross-driver: el driver MySQL.Data materializa una columna CHAR(36) como Guid cuando el flag OldGuids es false (default a partir de la versión 6.6 del connector), provocando InvalidCastException en GetString. Mismo riesgo en Oracle con storage RAW(16). La lectura del correlation id tiene ahora una cascada de fallback (GetGuid → GetString → GetValue con switch sobre runtime type) — robusta en los cuatro providers independientemente de la configuración del driver.

  • Repositorio chat — conexión MySQL no abierta: el gateway MySQL retornaba una new MySqlConnection(cs) sin llamar a Open(), asimétrico respecto a los gateways PostgreSQL y Oracle. El primer ExecuteNonQueryAsync del schema auto-apply fallaba con "Connection must be valid and open". Añadido un OpenConnectionToConnectionString simétrico, alineado con los otros providers.


📦 Paquetes actualizados

Package De A
WuicCore 1.2.1 1.3.0
Wuic.Webcore 1.2.1 1.3.0
WuicOData 1.2.1 1.3.0
RuntimeEfCore 1.2.1 1.3.0
Wuic.MySqlProvider 1.2.1 1.3.0
Wuic.PostgresProvider 1.2.1 1.3.0
Wuic.OracleProvider 1.2.1 1.3.0
wuic-framework-lib (NPM) 1.2.1 1.3.0

🔧 Actualizaciones operativas recomendadas

  1. Para habilitar el chatbot RAG, añadir a appsettings.json la clave anthropic-api-key (y opcionalmente anthropic-default-chat-model y anthropic-auto-compact-threshold). El backend relee las claves en hot-reload — no necesita restart.
  2. Ningún paso DBA requerido en instalaciones existentes: en el primer Ask del chatbot, el esquema del chat history (_rag_chat_sessions + _rag_chat_messages con todas las columnas) se aplica idempotente en el provider configurado en MetaDataSQLConnection. La auto-migración cubre instalaciones nuevas y parcialmente migradas.
  3. Si la instalación corre sobre MySQL / PostgreSQL / Oracle, verificar que la connection string apunta al provider correcto y que el usuario tiene privilegios ALTER TABLE sobre el schema de metadata (necesarios una sola vez, en el primer arranque).
  4. Para monitorear el consumo de la ventana de contexto, el círculo cue % en el header del chatbot es el driver visual inmediato. Por encima del 80% conviene un compact manual (/compact o click sobre el cue) para reducir la latencia de los turns siguientes.
  5. Para ejecutar el chatbot RAG sin Python en la máquina de destino, configurar rag-use-dotnet-engine=true en appsettings.json (opcionalmente rag-engine-device y rag-engine-profile). En el primer arranque los artefactos de inferencia se descargan automáticamente.

v1.2.1

Volver al índice

Versión publicada anteriormente: 1.2.0 (27 de mayo de 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


Versión de mantenimiento centrada en una clase de bugs latentes que afectaban a los campos datetime y decimal en escenarios cross-DBMS / cross-locale. La mayoría de los usuarios con workstation en locale italiana se han visto afectados al menos una vez — el componente time de las marcas temporales se truncaba a medianoche en INSERT y UPDATE, y los decimales con separador no invariante producían ORA-01722 en Oracle cuando la sesión ODP.NET heredaba la cultura italiana de Windows.

Los fixes son transversales a los 4 providers soportados (MSSQL, MySQL, PostgreSQL, Oracle) y todos los tests roundtrip end-to-end pasan tanto en locale de sesión DB inglesa (en-US) como italiana (Italiano dmy, lc_time=Italian_Italy.1252).


🐛 Correcciones de bugs destacadas

  • Componente time truncado en INSERT/UPDATE de campos DATETIME2 / DATETIME(n) / TIMESTAMP: el scaffolder de los metadatos colapsaba todos los tipos temporales del DB origen sobre el único tipo UI date. Resultado: una columna de SQL Server DATETIME2(3) (o MySQL DATETIME(3), PostgreSQL timestamp without time zone, Oracle TIMESTAMP(0)) era tratada como pura fecha y el framework emitía '20261231' en lugar de '20261231 23:59:58' en INSERT/UPDATE — la hora introducida en la UI se perdía al guardar. El scaffolder ahora distingue date (fecha pura) de datetime (fecha + hora) y el guardado preserva el componente time con precisión al segundo. La precisión sub-segundo (.fff) permanece truncada intencionadamente por coherencia con el date-time picker UI que no la expone.

  • Oracle ORA-01722: número no válido en campos NUMBER(p,s) desde workstation italiana: los providers emitían los valores numéricos quoted como string en las INSERT/UPDATE (ej. VALUES (..., '9876.4321', ...)). Oracle convertía la string en número usando NLS_NUMERIC_CHARACTERS de la sesión, que ODP.NET deriva del thread .NET CurrentCulture: en cultura italiana el decimal es , y . se convierte en separador de grupo → '9876.4321' se interpretaba como expresión de grupo inválida. Ahora los valores numéricos (decimal, float, double, numeric) se emiten como literales SQL sin quoting: los literales numéricos Oracle usan siempre . como punto decimal independientemente de NLS.

  • Oracle ORA-00904: identificador no válido en tablas con identificadores quoted-lowercase: una tabla creada con DDL CREATE TABLE "my_table" ("id" NUMBER, ...) (lowercase quoted, case-preserving) no era legible por el framework. La lógica de quoting reconocía los mixed-case y las reserved keywords pero trataba los all-lower como "safe identifier" y los emitía bare (Oracle los case-folda a UPPER), causando el mismatch con el físico "id". Ahora los identificadores all-lowercase se preservan con quoting explícito.

  • Parsing/formatting locale-invariante de fechas y timestamps en el server: el path de parsing/emit de DateTime en Oracle y PostgreSQL usaba el thread CurrentCulture. Ahora el parsing intenta primero InvariantCulture y hace fallback a CurrentCulture solo si es necesario; el formatting para las cláusulas SQL (TO_TIMESTAMP(...) / literal yyyy-MM-dd HH:mm:ss) usa siempre InvariantCulture. Efecto user-visible: el round-trip permanece bit-perfect independientemente del CultureInfo.CurrentCulture del proceso backend.

  • Oracle ORDER BY sobre PK lowercase: la cláusula ORDER BY añadida automáticamente sobre la clave primaria emitía el nombre de columna sin pasar por la lógica de quoting → producía ORA-00904 en tablas con PK "id" lowercase quoted. Ahora la PK pasa por el mismo quoting que todas las otras columnas.


🗄️ Compatibilidad DB cross-locale

Los tests de roundtrip end-to-end ahora cubren las siguientes combinaciones provider × sesión DB:

Provider Sesión DB probada Resultado
MSSQL @@LANGUAGE=Italian, date_format=dmy, Latin1_General_CI_AS OK
MySQL lc_time_names=en_US, utf8mb4_0900_ai_ci, time_zone=SYSTEM OK
PostgreSQL DateStyle=ISO,DMY, lc_time=Italian_Italy.1252 OK
Oracle NLS_LANGUAGE=AMERICAN, NLS_TERRITORY=AMERICA, NLS_NUMERIC_CHARACTERS=., OK

Las fechas se garantizan invariantes end-to-end (2026-12-31T23:59:58.000 permanece 2026-12-31T23:59:58.000 independientemente de la sesión DB y CurrentCulture del backend), al igual que los decimales (9876.4321 permanece 9876.4321).


📦 Paquetes actualizados

Package De A
WuicCore 1.2.0 1.2.1
Wuic.Webcore 1.2.0 1.2.1
WuicOData 1.2.0 1.2.1
RuntimeEfCore 1.2.0 1.2.1
Wuic.MySqlProvider 1.2.0 1.2.1
Wuic.PostgresProvider 1.2.0 1.2.1
Wuic.OracleProvider 1.2.0 1.2.1
wuic-framework-lib (NPM) 1.2.0 1.2.1

v1.2.0

Volver al índice

Versión publicada anterior: 1.1.0 (13 de mayo de 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


Esta versión extiende el framework a dos nuevos DBMS — PostgreSQL y Oracle — y corrige un bug del filtro de Spreadsheet que aparecía en rutas con server-side operations habilitadas cuando la columna era de tipo lookup.

  • Proveedor PostgreSQL y Proveedor Oracle: ambos instalables como drop-in (postgresql.dll / oracle.dll junto a WuicCore.dll), utilizables como data store o como metadata store, con paridad de features respecto a MSSQL y MySQL.
  • Filtro Spreadsheet en columnas lookup en modo server-side: el popup ahora muestra los descriptores de la lookup (p. ej., Woodgrove Bank Crandon Lakes) y aplica el filtro usando el ID de clave foránea, eliminando el error SQL que generaban los proveedores con tipado estricto.

🗄️ Proveedor PostgreSQL

Drop-in compatible con PostgreSQL 14+ (probado en 16). Instalación: colocar postgresql.dll junto a WuicCore.dll en el physical path del sitio IIS, o en el directorio de publish del binario Linux. El wizard de setup firstRun expone automáticamente "PostgreSQL" en el dropdown DBMS cuando detecta la DLL.

Cobertura funcional. Todas las superficies core del framework operan nativamente sobre PG con la misma semántica que las versiones MSSQL/MySQL: CRUD, server-side paging, sorting, grouping, agregaciones, lookup autocomplete, OData, scheduled jobs, audit, notificaciones, retry policy, concurrencia optimista, validations, callbacks/events, importación/exportación XLS, exportación PDF, multi-tenant.

Tipos PG-específicos soportados. boolean (mapeado automáticamente desde/hacia el almacenamiento interno smallint usado para paridad con MSSQL/MySQL), varchar/text, numeric, integer/bigint, timestamp, date, bytea (upload binario), geometry (PostGIS — visualización en mapas vía ST_AsText).

Archivos preconfigurados en el paquete.

  • appsettings.postgres.json / appsettings.linux.postgres.json / appsettings.multi-tenant.postgres.json — entornos self-contained listos, activables con ASPNETCORE_ENVIRONMENT=postgres.
  • dbms/scripts/first-run/*.postgres.sql — bootstrap de metadata + DDL/DML del tutorial WideWorldImporters.

🗄️ Proveedor Oracle

Drop-in compatible con Oracle 19c / 21c / Free 23c. Instalación oracle.dll con el mismo procedimiento del proveedor PostgreSQL; "Oracle" aparece automáticamente en el dropdown firstRun.

Cobertura funcional. Idéntica a PostgreSQL — todas las superficies core con la misma semántica que las versiones MSSQL/MySQL.

Longitud de identificadores. Oracle 11g/12.1 (máx. 30 caracteres) aún no está soportado — los alias lookup generados por el framework exceden el límite. Oracle 12.2+ (128 caracteres) es el mínimo soportado.

Archivos preconfigurados en el paquete.

  • appsettings.oracle.json / appsettings.linux.oracle.json / appsettings.multi-tenant.oracle.json.
  • dbms/scripts/first-run/*.oracle.sql — bootstrap de metadata + tutorial.

🐛 Bug fixes destacados

  • Filtro popup Spreadsheet en columnas lookup cuando md_server_side_operations=true: el popup de columna funnel de <wuic-list-spreadsheet> en una columna lookupByID mostraba IDs numéricos desnudos (p. ej., 1, 4, 5) en lugar de los descriptores (p. ej., Woodgrove Bank Crandon Lakes). En PG/Oracle la aplicación del filtro generaba un error SQL (42601 ilike %% en PostgreSQL, ORA-00904 en Oracle) porque el cliente transmitía la cadena descriptora contra la columna FK numérica. El servidor ahora emite el descriptor joinado (<entity>___<dataTextField>__<colName>) junto al FK ID y el cliente visualiza el descriptor en el popup pero transmite el ID raw como filter value: el WHERE col = <id> permanece numérico y cross-DBMS-safe. No se requiere acción del lado consumer.

📦 Paquetes actualizados

Package De A
WuicCore 1.1.0 1.2.0
Wuic.Webcore 1.1.0 1.2.0
WuicOData 1.1.0 1.2.0
RuntimeEfCore 1.1.0 1.2.0
Wuic.MySqlProvider 1.1.0 1.2.0
Wuic.PostgresProvider — 1.2.0
Wuic.OracleProvider — 1.2.0
wuic-framework-lib (NPM) 1.1.0 1.2.0

🔧 Actualizaciones operativas recomendadas para quien actualiza

  1. Para usuarios de MSSQL o MySQL: ninguna acción requerida. El fix del filtro Spreadsheet se aplica a todos los proveedores de forma transparente tras el primer refresh del cliente.
  2. Para activar PostgreSQL: copiar postgresql.dll (junto con sus dependencias de runtime — Npgsql.dll, Npgsql.EntityFrameworkCore.PostgreSQL.dll, Microsoft.Extensions.Logging.Abstractions.dll) al physical path del sitio IIS o al directorio de publish Linux, reiniciar el backend. Seleccionar PostgreSQL en el wizard firstRun, o apuntar ASPNETCORE_ENVIRONMENT=postgres para usar appsettings.postgres.json preconfigurado.
  3. Para activar Oracle: mismo procedimiento — oracle.dll + Oracle.EntityFrameworkCore.dll + Oracle.ManagedDataAccess.dll. Verificar que la versión del DB target sea ≥ 12.2 (constraint de longitud de identificadores).
  4. Cache del cliente: tras la actualización, un hard refresh del navegador (Ctrl+F5) es suficiente para alinear el cliente con el nuevo contrato del filtro popup. No se requiere invalidación de metadata en el servidor.

v1.1.0

Volver al índice

Versión publicada anteriormente: 1.0.20 (12 de mayo de 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


Salto a minor: esta versión introduce dos capacidades estructurales que cambian el modelo de despliegue del framework.

  • Multi-tenant: una única instancia del framework enruta datos y metadatos de N empresas hacia N conexiones de BD distintas. Configuración por tenant en las columnas Aziende.Connessione_DB_Dati / Aziende.CONNESSIONE_DB_Meta; enrutamiento transparente a nivel de aplicación mediante TenantContext (AsyncLocal, sobrevive a los límites de Task/scheduler).
  • Localización del menú por idioma: las entradas del menú (mm_display_string_menu) ya no contienen etiquetas italianas codificadas, sino claves estables con namespace menu.<scope>.<slug>, resueltas en tiempo de ejecución por la pipe translate de Angular contra _wuic_translations. Cambiar idioma desde el selector de usuario actualiza todas las entradas sin F5.

🌐 Gestión multi-tenant

Una sola instalación del framework puede ahora servir a varias empresas ("tenants") con datos y metadatos físicamente aislados en BD diferentes, sin necesidad de replicar la aplicación ni particionar reverse-proxies por host.

Modelo de datos. El enrutamiento tenant→conexiones se define sobre dos columnas de la BD de metadatos primaria:

  • Aziende.Connessione_DB_Dati — nombre de una entrada en ConnectionStrings para la BD de aplicación del tenant
  • Aziende.CONNESSIONE_DB_Meta — nombre de una entrada en ConnectionStrings para la BD de metadatos del tenant

Las columnas contienen el nombre de la entrada, no la cadena literal. La rotación de credenciales se hace editando appsettings.<env>.json, sin tocar la BD.

Activación. Flag en appsettings.json (sección AppSettings):

"multiConnectionEnabled": "true"

Con el flag false (por defecto) el comportamiento permanece single-tenant, idéntico a las versiones anteriores. Con el flag true cada petición HTTP autenticada resuelve el AziendaId desde el usuario autenticado y enruta GetOpenConnection hacia las connection strings del tenant correspondiente.

Enrutamiento transparente. Todos los puntos de acceso a BD del framework (MetaService.*, scheduler, scaffolding, AsmxProxy CRUD, callbacks personalizados) consultan TenantScope.CurrentAziendaId mediante AsyncLocal, propagado por el middleware HTTP tras la autenticación. Los jobs en background y los callbacks personalizados declaran el tenant explícitamente con using (TenantScope.Push(aziendaId)) { ... } cuando se ejecutan fuera del contexto de petición.

Caché tenant-aware. Las claves Application[] del lado servidor y las cachés locales de metadatos se sufijan automáticamente con AziendaId cuando el flag está activo, evitando el bleed de metadatos entre tenants.

Enrutamiento de login. La tabla _login_index(username_hash, id_azienda) en la BD primaria mapea username → tenant para el fallback de MetaService.login: tras la autenticación, la cookie k-user lleva azienda_id como parte del payload y el middleware crea el TenantScope correcto en cada petición posterior.

Propagación de scaffold. La acción "Scaffold tabla" propaga de forma idempotente los metadatos de la tabla a todos los tenants listados en Aziende. La propagación se ejecuta con un TenantScope explícito sobre cada destino y es idempotente: re-ejecutable, aplica solo los cambios faltantes.

Archivos preconfigurados en el paquete:

  • appsettings.multi-tenant.mssql.json / appsettings.multi-tenant.mysql.json — entorno self-contained con 6 connection strings de ejemplo (1 primary + 5 tenants) y multiConnectionEnabled=true. Activar con ASPNETCORE_ENVIRONMENT=multi-tenant.mssql.
  • dbms/scripts/multi_tenant_aziende_connessioni_mssql.sql / _mysql.sql — DDL para añadir las dos columnas a Aziende en BD existentes.

🗺️ Localización del menú por idioma

Las entradas del menú se traducen ahora dinámicamente según el idioma del usuario, sin necesidad de duplicar registros de _metadati__menu por locale.

Arquitectura. El campo mm_display_string_menu de _metadati__menu contiene una clave estable con namespace (menu.admin.roles, menu.crm.opportunities, menu.fleet.vehicles, ...). La plantilla del componente menú de Angular aplica la pipe translate sobre item.label y la clave se resuelve en tiempo de ejecución desde el diccionario _wuic_translations filtrado por el idioma actual.

Esquema de clave.

menu.<scope>.<slug>
   │       └── slug snake_case (p. ej. column_styles, opportunities)
   └── scope = root | admin | demo | crm | fleet | invoice
  • menu.root.* — parents top-level (Administración, Aplicación, Inicio, ...)
  • menu.admin.* — 36 entradas de sistema compartidas (Roles, Designer, Estilos de columna, Workflow Designer, ...)
  • menu.demo.* — contenido demo WideWorldImporters
  • menu.crm.* / menu.fleet.* / menu.invoice.* — entradas específicas del dominio del tenant

Ventaja respecto al modelo anterior.

  • El modelo antiguo usaba el texto italiano de la etiqueta como clave de traducción (Aziende, Customers, Ruoli). Esto causaba case-mismatches silenciosos (Ruoli vs ruoli, Stili Tabella vs Stili tabella) porque la pipe translate es case-sensitive mientras que _wuic_translations tiene una collation case-insensitive: el primer MERGE que entraba fijaba el casing para siempre, y los INSERTs posteriores con casing divergente se convertían en no-ops silenciosos.
  • El nuevo modelo con claves estables es case-determinado (todo en minúsculas por convención), con namespacing por scope, y ya no colisiona con otros recursos que pudieran usar el mismo texto italiano (p. ej. una etiqueta de botón "Ruoli" en un dropdown es una clave diferente de menu.admin.roles).

5 idiomas soportados. it-IT, en-US, fr-FR, es-ES, de-DE. Las traducciones viven en _wuic_translations (formato estándar: language, resource, translation). Cambiar idioma desde el dropdown de usuario arriba a la derecha relee el diccionario para el nuevo idioma y repinta el menú sin F5.

Fallback de runtime. Idioma actual → en-US → it-IT → clave raw. Si ves menu.admin.roles literal en pantalla significa que la clave no ha sido seedada en ninguno de los 5 idiomas.

Las claves italianas antiguas en _wuic_translations no se tocan con la actualización: pueden ser consumidas por otros puntos de la app (instant('Aziende') en code-behind, headers de list-grid, page titles) y siguen siendo válidas.


🐛 Correcciones de errores destacadas

  • Formularios de edición dinámicos — Tabs y widgets en plantillas md_edit_template en producción: en builds de producción las plantillas HTML personalizadas asociadas a una ruta vía md_edit_template no renderizaban correctamente los Tabs de PrimeNG 21 (las labels aparecían como texto plano concatenado sin el chrome del componente) y los field-editors mostraban solo placeholders <!----> en lugar de inputs. Causa: el compilador runtime usado por el framework para plantillas dinámicas requiere la enumeración explícita de los componentes standalone disponibles en la plantilla, y MetadataProviderService.widgetDefinition.dynamicFormImports estaba incompleto. Añadidos a la baseline TabsModule + Tabs/TabList/Tab/TabPanels/TabPanel, FieldsetModule, DataRepeaterComponent, DataSourceComponent, ImageWrapperComponent. No se requiere acción en las apps consumer una vez actualizado el paquete wuic-framework-lib.

🎁 Aplicaciones gratuitas ahora disponibles

A partir de esta versión, tres aplicaciones completas se distribuyen gratis sobre el framework — disponibles en la sección "Free apps" de la página Downloads:

  • CrmApp — CRM B2B autoalojado: registro de clientes, pipeline de oportunidades con kanban drag-and-drop, actividades (llamadas / reuniones / emails), dashboard por rol. (Leer el artículo)
  • FatturazioneElettronica — Facturación electrónica italiana: editor de facturas FatturaPA v1.2, firma CADES-BES, validación XSD, 4 proveedores SDI intercambiables (DirectPec gratuito vía PEC, ArubaPec / FatturePec / PecIt comerciales), conservación legal, registros IVA y liquidación. (Leer el artículo)
  • FlottaMezzi — Gestión de flotas: registro de vehículos / conductores, vencimientos automáticos (impuesto / ITV / seguro / mantenimiento / carnet), feed geolocalización OBD/GPS, mapa en vivo, agregación de costes €/km por vehículo y por conductor, reporting TCO. (Leer el artículo)

Cada aplicación se distribuye en tres formatos: ZIP IIS con DB tutorial (lista para restaurar), ZIP IIS sin DB, ZIP código fuente.

Modelo de licencia. Las apps gratuitas son GRATIS tal como se distribuyen — el binario <App>.dll del ZIP lleva un recurso host-binding-license embebido que autoriza el runtime framework sin claves externas. Solo si recompilas la aplicación desde el código fuente (por ejemplo para añadir un nuevo controlador o cambiar una signature pública) necesitas una licencia WUIC Developer o Professional: la recompilación produce un binario con identidad diferente, pierde el bundling, y el framework cae al control de licencia fingerprint estándar.

Extender las apps gratuitas sin recompilar el binario está cubierto por el bundling: añadir metadata vía SQL, componentes Angular en el wwwroot, jobs en la tabla scheduler, hooks personalizados vía appsettings.json:customCrudHookClass.


📦 Paquetes actualizados

Package De A
WuicCore 1.0.20 1.1.0
Wuic.Webcore 1.0.20 1.1.0
WuicOData 1.0.20 1.1.0
RuntimeEfCore 1.0.20 1.1.0
wuic-framework-lib (NPM) 1.0.20 1.1.0

🔧 Actualizaciones operativas recomendadas para quien actualiza

  1. Para quien quiere activar multi-tenant (opt-in): aplicar el script DDL dbms/scripts/multi_tenant_aziende_connessioni_mssql.sql (o _mysql.sql) para añadir las columnas Connessione_DB_Dati y CONNESSIONE_DB_Meta a Aziende. Poblar las filas de Aziende con los nombres de las entradas de ConnectionStrings de appsettings.json. Configurar AppSettings.multiConnectionEnabled = "true". Reiniciar el backend.
  2. Para quien permanece en single-tenant: ninguna acción requerida. Sin multiConnectionEnabled=true el routing tenant está desactivado y el comportamiento es bit-idéntico a la 1.0.20.
  3. Localización del menú — refresh de metadatos: tras la actualización, ejecutar una vez POST /api/Meta/AsmxProxy/MetaService.invalidateMetadataRuntime para recargar el diccionario del menú en el cliente. Alternativamente, cerrar sesión y volver a entrar.
  4. Localización del menú — migración de un proyecto existente: para proyectos que vienen de una versión anterior con etiquetas italianas en _metadati__menu.mm_display_string_menu, aplicar dos pasos SQL idempotentes: (a) UPDATE _metadati__menu SET mm_display_string_menu = '<menu.scope.slug>' WHERE mm_display_string_menu = '<etiqueta antigua>' para cada entrada, siguiendo el esquema menu.<scope>.<slug> documentado arriba; (b) INSERT/MERGE INTO _wuic_translations (language, resource, translation) 5 filas por nueva clave (una por idioma). Las filas antiguas en _wuic_translations con resource = texto italiano permanecen en BD y pueden ser consumidas por otros callers (instant(), headers de list-grid).
  5. Hot reload de backend en dev: si desarrollas con dotnet watch, el task backend: kill dll lockers requiere ahora pwsh 7+ (ya no Windows PowerShell 5.x). El script C# inline para Restart Manager usa sintaxis Dictionary<,> parseada correctamente solo en PS 7+.

v1.0.20

Volver al índice

Versión anterior publicada: 1.0.19 (4 de mayo de 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


Versión de consolidación tras la 1.0.19, centrada en correcciones de bugs con impacto directo en la edición y visualización (INSERT con triggers INSTEAD OF, campos numéricos que se reseteaban al blur, calendario vacío en la primera navegación, preservación del SQL custom en informes) y en una ronda de alineación del componente mapa con las nuevas API de Google Maps: finalización de las opciones del archetype map, migración a la Routes API para el snap-to-roads, eliminación de la dependencia de la drawing library deprecada.


🐛 Correcciones destacadas

  • INSERT con triggers INSTEAD OF: las tablas con triggers INSTEAD OF INSERT perdían el PK devuelto por la instrucción externa (OUTPUT INSERTED.<pk> devolvía 0 o NULL porque el trigger desviaba el INSERT). Fix: el INSERT generado por _Metadati_methods ahora usa una variable de tabla (@__inserted_pk con OUTPUT ... INTO) como canal principal y recurre a IDENT_CURRENT('<table>') cuando el trigger consume la instrucción externa. También resuelve el SQL Server msg 334 (OUTPUT INSERTED sin INTO no está permitido en tablas con triggers habilitados).
  • field-editor number — reset a 0 al blur: cuando la columna de metadatos tenía mc_min_value o mc_max_value definidos, el campo numérico se reseteaba a 0 en el blur en lugar de conservar el valor introducido. La verificación de rango se ejecutaba antes del roundtrip de parsing, leyendo un valor intermedio no numérico y colapsándolo a 0. Comportamiento correcto: el valor se confirma y se clampa a los límites solo si está realmente fuera de rango, de lo contrario se mantiene tal cual.
  • Archetype map — opciones completadas: el archetype del componente mapa gana tres propiedades que cierran lagunas comunes de UX:
    • polyline — overlay de polyline para el seguimiento de rutas (registros GPS historizados). Agrupación por campo (groupByField), ordenación (orderByField), color por registro/por grupo, snap-to-roads opcional, dots de waypoint distintos del path interpolado.
    • clickableIcons — pass-through a google.maps.MapOptions.clickableIcons. Cuando es false, Google Maps deja de abrir su info window built-in sobre los POIs (tiendas, paradas, direcciones), que en caso contrario interceptaba los clicks destinados a los marker custom.
    • markerColorField — color del PinElement leído desde un campo del registro (CSS #rrggbb). Se ignora si el registro ya tiene customMarkerImageSrcField definido (la imagen/SVG tiene prioridad).
  • Google Maps Directions API — deprecada: DirectionsService está deprecado desde el 2026-02-25. El snap-to-roads de las polylines ahora usa la nueva Routes API (google.maps.routes.Route.computeRoutes), con fallback automático al legacy DirectionsService (operativo hasta el 2027-02-25) para las keys aún no migradas. Mapeo legacy travel mode → routes sin cambios (DRIVING/WALKING/BICYCLING). Batching automático a 25 waypoints por llamada.
  • Google Maps Drawing API — eliminada: la drawing library (google.maps.drawing) está deprecada desde 2025-08 y eliminada en las versiones de Maps JavaScript API liberadas desde mayo de 2026. La lógica DrawingManager en MapListComponent eran solo stubs de console.log (sin feature de dibujo realmente persistida) y se ha eliminado. PointFilterComponent (filtro geo por área/círculo en list-grids) se ha reescrito con handlers manuales click+mousemove — misma UX (polígono mediante varios clicks, círculo via centro+radio, dblclick para cerrar), independiente de la librería deprecada.
  • Informes — preservación de SQL custom mediante sentinel __autogenerated: los informes con SQL custom que aliaseaban columnas no registradas en los metadatos perdían joins/columnas porque la dynamic query auto-generada sobrescribía la query del usuario. Fix cross-DBMS (MSSQL, MySQL, PostgreSQL, Oracle): cada SELECT auto-generado ahora inyecta 1 AS [__autogenerated] como primera columna; la pipeline de metadatos detecta el token en runtime y preserva la query custom cuando el sentinel no está presente. Permite layouts Stimulsoft que leen columnas no registradas como metadatos (típico en plantillas de facturación/PEC donde el SQL deriva columnas calculadas).
  • Calendario — eventos no visibles en la primera navegación: <wuic-scheduler-list> mostraba un calendario vacío cuando el usuario navegaba directamente a #/<route>/scheduler (FullCalendar se inicializaba con data=[] antes de que llegara la respuesta async; un F5 lo poblaba porque la caché de sesión entregaba los datos antes del mount). Fix: sincronización explícita de eventos via API (removeAllEvents() + addEvent()) tras el render del calendario, bypaseando el binding [events]="data" poco fiable del wrapper FullCalendar 6.x Angular en updates post-mount.

📦 Paquetes actualizados

Package De A
WuicCore 1.0.19 1.0.20
Wuic.Webcore 1.0.19 1.0.20
WuicOData 1.0.19 1.0.20
RuntimeEfCore 1.0.19 1.0.20
wuic-framework-lib (NPM) 1.0.19 1.0.20

🔧 Acciones operativas recomendadas para quien actualiza

  1. Ejecutar dotnet ef database update si se usan migraciones de EF.
  2. Si se usa el snap-to-roads en las polylines del mapa: verificar que la propia Google Maps API key tenga la Routes API habilitada además de la Directions API. Sin la Routes API el framework cae sobre el legacy DirectionsService, que sigue funcionando pero está en la ventana de deprecation (sunset 2027-02-25).
  3. Si se dependía de la drawing toolbar estándar de MapListComponent (sin use cases conocidos — los handlers eran stubs): la toolbar se ha eliminado. No se requiere ninguna acción para los filtros geo en list-grids — PointFilterComponent mantiene la misma UX con implementación interna.
  4. Para usar el nuevo overlay polyline en una route mapa: añadir la configuración { enabled: true, groupByField, orderByField, ... } a md_props_bag.archetypes.map.polyline via designer o patch de metadatos.

v1.0.19

Volver al índice

Versión publicada anterior: 1.0.7 (26 de abril de 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


En seis días de desarrollo intensivo, WUIC da un salto significativo: del único deploy en Windows IIS a una plataforma multi-runtime (Windows + Linux nativo), con un sistema unificado de gestión tipada de errores, crash reporting centralizado, autenticación LDAP y una ronda de hardening best-effort sobre la superficie aplicativa.


🛡️ Seguridad

Hardening best-effort sobre toda la superficie aplicativa: throttling de autenticación, refuerzo de las cabeceras HTTP estándar (HSTS, CSP, X-Frame-Options, X-Content-Type-Options, Referrer-Policy), gestión environment-aware de CORS y Swagger, reducción de info disclosure en las respuestas de error, gating granular de los endpoints administrativos, controles adicionales en la ruta SQL en runtime. Las configuraciones por defecto ahora son más conservadoras incluso para deploys demo/staging, con override explícito disponible vía AppSettings.


🚨 Crash Reporting (end-to-end)

Nuevo sistema de crash reporting auto-instalado que envía stack traces .NET + JavaScript a un receiver self-hosted.

  • Captura pasiva: las excepciones unhandled se recogen automáticamente, deduplicadas vía stack canonicalization y encoladas async — sin impacto en la latencia de las request.
  • Receiver privado: errors.wuic-framework.com acepta uploads firmados con RSA license signature (cero API keys que gestionar).
  • Consentimiento RGPD: opt-in explícito gestionado en AppSettings, configurable desde el editor de settings.
  • Activación: CrashReporting:Enabled=true en appsettings.json + consentimiento RGPD vía UI.

🐧 Linux deployment (nuevo)

WUIC ya es instalable en Ubuntu/Debian completamente automatizado, con stack soportado:

  • .NET runtime + MSSQL Server o MySQL/MariaDB.
  • Python 3.12 + entorno RAG.
  • Secretos vía systemd credentials.
  • nginx reverse proxy con TLS Let's Encrypt.
  • Smoke test post-instalación que valida backend, RAG y proxy.

El tarball Linux incluye appsettings.linux.mssql.json y appsettings.linux.mysql.json preconfigurados para los dos stacks soportados, más un README con el procedimiento paso a paso.


🔐 Autenticación LDAP

El login WUIC ahora soporta bind LDAP como alternativa al DB:

  • Configuración mediante la sección Authentication:Ldap:* en appsettings.json (server, base DN, bind template).
  • Auto-aprovisionamiento de usuarios: la fila local se crea/actualiza en el primer login con datos de LDAP.
  • Fallback DB: si LDAP no es alcanzable y Authentication:Ldap:FallbackToDbOnFailure=true, el login recae en el DB tradicional (admin/admin sigue siendo siempre alcanzable para recovery).

Compatible con Active Directory, OpenLDAP y directorios Novell.


🗄️ Provider MySQL (Wuic.MySqlProvider 0.8.3)

Soporte MySQL/MariaDB extendido a paridad con el primary MSSQL:

  • Cobertura completa de tests funcionales (audit, CRUD client-side, concurrency, conditional styling, import-export, OData, retry, stored procedures, traducciones, validaciones).
  • Fix de bugs específicos Linux: collation por defecto, quirks de JSON_TYPE, paging hints.

🚦 Sistema unificado de errores (typed exceptions)

Refactor completo de la gestión de errores aplicativos:

  • WuicException como tipo base para todas las excepciones aplicativas tipadas (parte de la API pública del framework).
  • WuicErrorCodes: catálogo de 27 códigos estables (errors.auth.unauthenticated, errors.metadata.props_bag.malformed, errors.db.sql_exception, errors.report.render_failed, etc.).
  • JSON envelope estable para todas las respuestas de error: { ok, errorCode, args, traceId, fallbackMessage }. Permite al cliente mostrar mensajes localizados en lugar de stack traces técnicos.
  • Traducciones built-in en IT/EN/DE/ES/FR/JA para todos los códigos conocidos.
  • Mapping automático de las excepciones runtime conocidas (SqlException, AuthenticationException, JsonException, etc.) a los códigos tipados.

📊 Exportación Excel

Reescritura del path de export bulk al formato .xlsx sobre pipeline producer/consumer y OpenXmlWriter streaming. El impacto se nota sobre todo en datasets grandes (decenas de miles de filas en adelante).

  • Streaming OpenXML en lugar del DOM-build incremental: típicamente 50× más rápido en exports bulk, footprint de memoria contenido incluso por encima del millón de filas.
  • Pipelining DB-read / xlsx-write sobre buffer limitado: las lecturas de DB ya no se bloquean en el tiempo de compresión de la hoja.
  • Notificaciones de progress agregadas vía canal dedicado: ya no una task por cada update, eliminado el storm WebSocket durante exports largos.
  • Split automático en varias hojas cuando se supera el límite Excel de 1.048.576 filas por hoja. El mensaje de finalización indica el número de hojas generadas.

Ninguna acción requerida: el path está activo por defecto para todos los exports .xlsx invocados desde la toolbar de list-grid (Export XLS) y desde APIs server-side.


🐛 Bug fix destacables

  • Gating isSuperAdmin: corregida la verificación de permisos en varios endpoints que previamente confundían isAdmin (rol per-user) con isSuperAdmin (rol source of truth).
  • OData CRUD: corregidas serializaciones edge case (Decimal→string, DateTime UTC roundtrip, navigation properties).
  • First-run wizard: el bootstrap inicial ahora consume correctamente IConfiguration (ya no depende del legacy app.config).
  • Crash reporting forwarding: bug del 2026-04-28 resuelto — las excepciones MVC handled ya no eluden el middleware de crash reporter.

📦 Paquetes actualizados

Paquete De A
WuicCore 1.0.13 1.0.19
Wuic.Webcore 1.0.13 1.0.19
WuicOData 1.0.13 1.0.19
RuntimeEfCore 1.0.13 1.0.19
Wuic.MySqlProvider 0.7.x 0.8.3
wuic-framework-lib (NPM) 1.0.11 1.0.19

🔧 Pasos operativos recomendados para quien actualiza

  1. Ejecutar dotnet ef database update si se está sobre EF migrations.
  2. Verificar appsettings.json: el sistema ahora también lee AppSettings:AllowedOrigins (array string) y AppSettings:registrationEnabled (boolean kill-switch). Defaults seguros si no se especifican.
  3. Si se usa LDAP, configurar la sección Authentication:Ldap:* en appsettings.json.
  4. Para deploy Linux: usar el tarball dedicado y seguir el README incluido.
  5. Para activar crash reporting outgoing: configurar CrashReporting:Enabled=true en appsettings.json + aceptar consentimiento RGPD vía UI.