Note di rilascio

Tutte le versioni pubblicate del WUIC Framework, dalla più recente alla prima, con le note complete di ciascuna.

Torna ai download

v1.7.21

Torna all'indice

Versione precedente pubblicata: 1.7.20 (1 ottobre 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


Versione dedicata alla sicurezza e all'accesso ai dati. Chiude i risultati di una revisione di sicurezza completa del framework e porta OData allo stesso livello di permessi del CRUD. In sintesi:

  • enableCookieAuthentication accetta un terzo valore, "signed": cookie firmato dal server, più sessioni per utente, logout per singola sessione;
  • OData applica i permessi di route e colonna, i vincoli di riga dell'utente e scrive passando dal CRUD del framework;
  • i token personali permettono di collegare Power BI, Excel e script agli endpoint OData;
  • il flag "secure upload" delle colonne di upload torna a proteggere i file della colonna;
  • modifica e cancellazione rispettano la restrizione per utente anche nel CRUD della UI;
  • gli errori mostrano all'utente un messaggio tradotto con un codice di tracciamento, i dettagli tecnici solo al superadmin.

Le modifiche allo schema dei metadati si applicano da sole all'avvio. Le funzionalità sono state verificate con i test end-to-end su SQL Server, MySQL, PostgreSQL e Oracle, nelle tre modalità di enableCookieAuthentication.


🔐 Autenticazione e sessioni

  • Tre modalità. enableCookieAuthentication vale false, true o "signed". Con false l'utente è quello dichiarato dal cookie del browser: solo per sviluppo. All'avvio un messaggio [security] lo segnala, l'editor AppSettings lo descrive e chiede conferma al salvataggio. Un valore non riconosciuto vale come "signed", con avviso nel log.
  • "signed". Il server firma il cookie k-user (HMAC-SHA256, scadenza dentro la firma): un cookie modificato o scaduto vale come assente. Lo stesso utente può avere più sessioni aperte, ognuna con il proprio identificativo.
  • Logout e revoca. Il logout chiude solo la sessione da cui parte, anche per le copie del cookie. Il logout di un utente fatto da un amministratore, il reset e il cambio della password chiudono tutte le sessioni di quell'utente nella sua azienda.
  • Durata massima. Con signedSessionMaxLifetimeHours (default 24, 0 = nessun limite) una sessione firmata scade a quell'età dal login, anche se usata di continuo.
  • Chiave di firma. cookie-signing-key si genera al primo avvio e si salva in appsettings.json. All'avvio il log mostra l'impronta della chiave (mai la chiave) e avvisa se la chiave non è stata salvata.
  • Chiamate verificate sul server. Con false il cookie non porta più privilegi forgiati (amministratore, ruolo, azienda): l'utente viene riletto dal database.

🔗 OData

  • Permessi. Ogni entity set richiede il permesso di lettura sulla route. Una colonna negata all'utente citata in $select, $filter, $orderby o $expand risponde 403; altrimenti torna vuota.
  • Vincoli di riga. La query parte dalla stessa SELECT del CRUD con la restrizione per utente, ruolo o azienda, il filtro di default e la cancellazione logica. $filter, $orderby, $skip, $top e $count si applicano fuori e possono solo restringere: or 1 eq 1 non allarga il risultato.
  • $expand. Ammesso verso route leggibili senza vincoli di riga né cancellazione logica; negli altri casi 403.
  • Scritture. POST, PATCH e DELETE passano da insertRecord, updateRecord e deleteRecord: permessi, colonne non modificabili, trigger, campi di logging, change log, workflow e cancellazione logica valgono come dalla UI. Una riga nascosta all'utente risponde 404.
  • Multi-azienda. La connessione dati è quella dell'azienda dell'utente, come nel CRUD.
  • Discovery. /odata, /odata/$metadata e /odata/openapi.json richiedono la sessione. Con odataPublicMetadata=true tornano pubblici; i dati restano protetti.
  • Token personali. Con apiTokensEnabled=true ogni utente crea dal menu utente ("Token API") token wuic_pat_… con nome, scadenza (default 90 giorni, massimo apiTokenMaxLifetimeDays) e permesso di sola lettura o anche scrittura. Valgono solo su /odata, con i permessi del proprietario. Power BI ed Excel li usano come password con credenziali "Basic"; gli script con Authorization: Bearer. Il token si vede una volta sola; il superadmin vede e revoca quelli di tutti.

🛡️ Sicurezza

Hardening best-effort su tutta la superficie: controlli sui valori che finiscono nelle query (ordinamenti, operatori, aggregati, chiavi, filtri numerici) allineati sui quattro provider; percorsi di upload e report confinati nelle loro cartelle; funzioni di amministrazione (report designer, rimozione e scaffolding dei report, riordino colonne, restart, scaffold OData) riservate al superadmin verificato sul database; email dei workflow solo a chi può eseguire il workflow; dati di esempio degli strumenti per assistenti AI solo al superadmin e mai con colonne di credenziali; guardie sugli utenti e sui ruoli legate alla tabella, non al nome della route; chiave pubblica della licenza incorporata nel pacchetto.

📎 Upload

  • "Secure upload" per colonna. I file di una colonna con upload_secure si leggono solo con una sessione valida e con la colonna visibile all'utente, sia da /upload sia da /api/UploadImage. I file delle altre colonne restano pubblici. Le colonne che salvano il file nel database sono protette da /api/UploadImage.
  • Nomi file. I nomi con punti interni (fattura-acme.com.pdf) sono accettati; restano rifiutati i nomi con estensioni eseguibili dal server anche in mezzo (foto.aspx.png).

🚦 Errori

All'utente arriva un messaggio tradotto con un codice di tracciamento (pulsante "Copia codice" nel dialog di errore). Lo stesso codice è registrato con lo stack completo in _error__logs. SQL, stack e messaggi interni arrivano solo al superadmin. Le traduzioni dei messaggi di errore nuovi si aggiungono da sole all'avvio.

🐛 Bug fix degni di nota

  • Restrizione per utente in modifica e cancellazione. La UPDATE e la DELETE del CRUD contenevano solo la chiave: conoscendo l'id, un utente poteva modificare la riga di un altro. Ora la riga deve essere fra quelle che l'utente vede, altrimenti 403 errors.auth.route_read_forbidden.
  • Filtro di default con filtri in OR. Con l'operatore OR il filtro di default della route spariva e la griglia mostrava le righe che doveva nascondere. Ora resta in AND.
  • Oracle. Booleani scritti come 1/0 anche su colonne con tipo UI booleano, nei filtri e nei parametri delle stored; funzioni distinte dalle procedure nello schema giusto; OData sullo schema dei dati anche con l'utente SYSTEM (prima errori ORA-00942 intermittenti).
  • PostgreSQL e Oracle. L'inserimento con chiave identity non inviata dal client non va più in errore; i report applicano permessi e filtri dell'utente come su SQL Server e MySQL.
  • Primo avvio sotto IIS. La configurazione iniziale non restituisce più un 500 a installazione riuscita: le migration si completano al riavvio del worker.
  • Spreadsheet e sincronizzazione. Con un filtro attivo modifica e cancellazione colpivano la riga sbagliata; la selezione oltre la pagina non raggiunge più i record delle pagine successive; il salvataggio batch del kanban e la sincronizzazione offline ritentano solo ciò che è fallito.
  • Menu. La barra compare con le etichette già tradotte, senza mostrare per un istante le chiavi.

📦 Pacchetti aggiornati

Package Da 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

🔧 Aggiornamenti operativi raccomandati per chi aggiorna

  1. Modalità del cookie: in produzione impostare enableCookieAuthentication a "signed" (o true); false è solo per sviluppo.
  2. Più istanze dietro un bilanciatore: copiare la stessa cookie-signing-key in tutte le istanze; con chiavi diverse una sessione vale solo sull'istanza che l'ha creata. Verificare nel log che l'impronta coincida.
  3. Client OData: i client che leggevano $metadata senza sessione devono autenticarsi, oppure impostare odataPublicMetadata=true. Le scritture OData ora eseguono trigger e logging del CRUD e, sulle route con cancellazione logica, impostano il flag invece di cancellare la riga.
  4. md_service_apply_default_filter: deprecato. Il filtro di default si applica sempre, anche via OData.
  5. Licenza: l'override dell'impronta della macchina si imposta solo con la variabile d'ambiente WUIC_LICENSE_MACHINE_FINGERPRINT; le chiavi license-machine-fingerprint-override e license-public-key-pem in appsettings.json sono ignorate.
  6. Token API: per collegare Power BI, Excel o script impostare apiTokensEnabled=true (ed eventualmente apiTokenMaxLifetimeDays) dall'editor AppSettings.

v1.7.20

Torna all'indice

Versione precedente pubblicata: 1.7.18 (1 ottobre 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


Versione di correzione: raccoglie i difetti emersi sviluppando un'applicazione con i cinque pattern di sviluppo documentati, a partire dal progetto di esempio dei pacchetti sorgenti, e accelera il motore RAG sulle macchine senza GPU. Comprende anche le correzioni della 1.7.19, uscita solo come pacchetti NuGet e npm: queste note coprono entrambe. In sintesi:

  • rieseguire lo scaffolding con "Create Menu" non duplica più la voce di menu;
  • su PostgreSQL e Oracle l'ordinamento lato server richiesto dalla griglia viene applicato, anche quando la lista porta in cima un record in evidenza;
  • con ng serve gli export si scaricano anche dal dev server;
  • le ricerche del motore RAG su CPU sono fino a circa tre volte più veloci sulle macchine con pochi core;
  • le pagine dei cinque pattern di sviluppo hanno esempi di codice che compilano, in tutte e cinque le lingue.

Nessuna modifica a metadati, traduzioni o schema del database: l'aggiornamento non richiede script.


🗄️ Provider PostgreSQL e Oracle

  • Ordinamento lato server. Con le operazioni lato server attive, l'ordinamento scelto in una colonna della griglia non arrivava alla query: i record tornavano sempre ordinati per chiave primaria, anche chiedendo l'ordine discendente su un altro campo. Ora l'ORDER BY usa le colonne richieste e aggiunge la chiave primaria solo come ultimo criterio, come su SQL Server e MySQL.
  • Ordinamento con un record in evidenza. Quando la lista porta in cima un record specifico, l'ordinamento richiesto veniva scartato anche nella 1.7.19. Ora l'ordine è: record in evidenza, colonne richieste, chiave primaria.

🤖 Motore RAG

  • Ricerche più veloci su CPU. Senza GPU, i thread di calcolo dei modelli restavano attivi in attesa fra un'operazione e l'altra, e il riscaldamento della cache in background lavorava in parallelo alla prima ricerca: sulle macchine con pochi core si contendevano la CPU. Ora i thread non restano in attesa attiva e i calcoli dei modelli si eseguono uno alla volta nel processo. Le ricerche (chat e strumenti MCP) sono fino a circa tre volte più veloci su macchine con pochi core, e la prima ricerca non rallenta più per il riscaldamento in corso. Sui PC con core liberi i tempi non cambiano.

🐛 Bug fix degni di nota

  • Voce di menu duplicata allo scaffolding. Rieseguire "Scaffold Table" o "Scaffold View" con "Create Menu" su una tabella o vista già scaffoldata aggiungeva una seconda voce di menu per la stessa route. Ora la voce si crea solo se la route non ne ha già una.
  • Export con il dev server. Nel progetto client dei pacchetti sorgenti il file proxy.conf.js non inoltrava al backend il percorso /Tmp_export: con ng serve il link del file esportato (Excel, CSV, PDF) restituiva la pagina dell'applicazione invece del file. Ora il percorso è inoltrato e il download funziona come nell'installazione pubblicata.

📚 Documentazione

Le pagine dei cinque pattern di sviluppo sono state corrette in tutte le lingue:

  • Framework + manuale: l'esempio passa la sorgente dati con [hardcodedDatasource] e imposta [autoload]="true"; senza autoload la lista carica solo lo schema, non i record.
  • Dati dal framework + componente custom: nuovo esempio di setCurrent, addNewRecord, syncData e fetchData chiamati dal componente custom.
  • Componente framework + dati custom: i filtri lato client costruiscono un filtro per colonna, come lo legge la list-grid.
  • Full custom: il componente dichiara gli imports necessari (TableModule, CheckboxModule, ButtonModule, FormsModule).
  • Full autogeneration: lo spreadsheet richiede la funzionalità a licenza (senza, la route si apre come lista); la dashboard non è un archetype di route e la pagina non la elenca più fra le pagine generate.

La documentazione è inclusa nella libreria npm e pubblicata sul sito.

📦 Pacchetti aggiornati

Package Da 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

Chi ha già aggiornato i pacchetti alla 1.7.19 trova nella 1.7.20 in più l'ordinamento con un record in evidenza, il motore RAG più veloce e la correzione della pagina del pattern full autogeneration.

🔧 Aggiornamenti operativi raccomandati per chi aggiorna

  1. Progetti nati dai pacchetti sorgenti: il proxy.conf.js del progetto non viene sovrascritto dall'aggiornamento dei pacchetti. Aggiungere la voce '/Tmp_export' con la stessa configurazione delle altre voci verso il backend (o copiarla dal proxy.conf.js del pacchetto), poi riavviare ng serve.
  2. Menu duplicati: se rieseguendo lo scaffolding con una versione precedente sono comparse voci di menu doppie, eliminare quelle in più dalla gestione del menu.
  3. PostgreSQL e Oracle: nessuna azione; dopo l'aggiornamento le griglie con operazioni lato server ordinano come richiesto.
  4. Motore RAG: nessuna azione; il motore aggiornato si trova nella cartella rag-engine del pacchetto e la correzione vale per l'esecuzione su CPU.

v1.7.18

Torna all'indice

Versione precedente pubblicata: 1.7.17 (30 settembre 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


Versione di correzione: raccoglie i difetti emersi installando la 1.7.17 da zero su macchine pulite, con i quattro database supportati. In sintesi:

  • gli strumenti MCP di ricerca non vanno più in timeout mentre il motore RAG si carica;
  • su PostgreSQL il motore RAG si carica di nuovo da solo dopo l'avvio;
  • su Oracle XE 21c lo scaffolding di tabelle e viste scrive di nuovo i metadati, anche al primo avvio;
  • gli stack trace inviati dal crash reporting si ricostruiscono per intero.

Nessuna modifica a metadati, traduzioni o schema del database: l'aggiornamento non richiede script.


⚠️ Comportamenti che cambiano

  • Strumenti MCP durante il caricamento del motore. wuic_codebase_search e wuic_ask aspettano fino a 30 secondi (prima 60) che il motore RAG sia pronto; se non lo è ancora rispondono con un errore che chiede di riprovare fra circa 60 secondi. Il caricamento prosegue sul backend, e la chiamata ripetuta trova il motore pronto.

🤖 Motore RAG

  • Timeout degli strumenti MCP. Mentre il motore si caricava, il server MCP lanciava una ricerca di riscaldamento che girava in parallelo alla ricerca vera: su una macchina senza GPU le due si rallentavano a vicenda e la chiamata superava i 120 secondi di attesa del client, anche su Windows. Ora il server MCP si limita ad avviare il caricamento e ad aspettarlo, e la ricerca vera ha tutto il tempo del client.
  • /api/Rag/Health avvia sempre il caricamento. L'endpoint avvia il caricamento del motore in background anche quando non trova un utente amministratore a cui notificarne l'avanzamento: in quel caso il motore si carica senza notifiche.
  • PostgreSQL. La ricerca dell'amministratore falliva su PostgreSQL, dove isAdmin è un campo boolean: il motore non partiva mai da /api/Rag/Health e gli strumenti MCP restavano "in caricamento". Ora l'amministratore si trova e il motore parte come sugli altri database.

🗄️ Provider Oracle

  • Scaffolding su Oracle XE 21c. Le versioni recenti del driver Oracle inviano i valori true/false come tipo BOOLEAN, che Oracle prima della 23 rifiuta (ORA-00932). Lo scaffolding di tabelle e viste (dall'interfaccia e al primo avvio) rispondeva con un errore e il primo avvio terminava senza i metadati delle tabelle applicative. Ora i flag dei metadati si scrivono come 0/1, che le colonne NUMBER delle tabelle di metadati accettano su ogni versione di Oracle.

🐛 Bug fix degni di nota

  • Crash reporting, stack trace illeggibili. Con CrashReporting:Enabled=true gli stack trace inviati dalle installazioni non si ricostruivano sul receiver: i nomi interni del framework restavano illeggibili e l'analisi dei crash ne risultava compromessa. Dalla 1.7.18 le segnalazioni si ricostruiscono per intero. Nessuna modifica alla configurazione né ai dati inviati.

📦 Pacchetti aggiornati

Package Da 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

🔧 Aggiornamenti operativi raccomandati per chi aggiorna

  1. Assistenti di codice con il server MCP WUIC: su un'installazione esistente il workspace contiene la copia precedente di scripts/mcp/wuic-rag-mcp.mjs. Sostituirla con quella del pacchetto (llm-workspace/templates/app-llm-workspace/scripts/mcp/) o rigenerare il workspace come descritto in llm-workspace/README.md, poi riavviare il client MCP.
  2. Oracle XE 21c: se un primo avvio con la 1.7.17 o precedenti è terminato senza i metadati delle tabelle applicative, ripetere lo scaffolding di quelle tabelle dall'interfaccia dopo l'aggiornamento.
  3. Crash reporting: chi lo usa non deve fare nulla; le segnalazioni delle versioni precedenti restano come sono, quelle nuove si leggono per intero.

v1.7.17

Torna all'indice

Versione precedente pubblicata: 1.7.16 (29 settembre 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


Versione di correzione: raccoglie i difetti emersi installando la 1.7.16 da zero su macchine pulite, Windows e Linux. In sintesi:

  • la mappa non carica più Google Maps con una chiave finta quando la chiave non è stata configurata;
  • il motore RAG si carica molto più in fretta al primo uso, e si può caricare all'avvio;
  • gli strumenti MCP di ricerca aspettano il motore invece di andare in timeout;
  • l'AppSettings Editor si apre in pochi secondi;
  • il row template della list-grid non si rompe più al primo caricamento diretto di una pagina.

Nessuna modifica a metadati, traduzioni o schema del database: l'aggiornamento non richiede script.


⚠️ Comportamenti che cambiano

  • Chiave Google Maps non configurata. Il valore di installazione __SET_GOOGLE_MAPS_API_KEY__, se non sostituito, ora vale come chiave assente: la mappa mostra l'avviso di chiave mancante. Prima il browser caricava Google Maps con quel testo come chiave (InvalidKeyMapError e errori interni di Google in console). Vale per ogni valore della forma __SET_...__ in GoogleMaps:ApiKey.
  • Strumenti MCP durante il caricamento del motore. wuic_codebase_search e wuic_ask aspettano fino a 60 secondi che il motore RAG sia pronto; se non lo è ancora rispondono con un errore che chiede di riprovare fra circa 60 secondi, invece di lasciare scadere la chiamata del client.

🤖 Motore RAG

  • Primo uso più rapido. Il riscaldamento del motore dopo il caricamento eseguiva una ricerca completa, circa 35 passaggi del reranker: su una macchina Linux senza GPU valeva circa 133 dei 139 secondi del caricamento a freddo. Ora fa un solo passaggio dell'embedder e uno del reranker su un testo corto. I risultati delle ricerche non cambiano.
  • Caricamento all'avvio, opzionale. Nuova chiave AppSettings:rag-engine-eager-load (default false). Con true, se i modelli sono già scaricati, il backend carica il motore in background all'avvio, senza notifiche, e la prima ricerca (chat o MCP) non paga il caricamento a freddo. Il costo è la RAM del motore, 4,5-6,5 GB, occupata anche se il RAG non si usa. Con false il motore si carica alla prima richiesta, come prima.
  • Server MCP. L'attesa del motore è nel server MCP che il primo avvio installa nel workspace per gli assistenti di codice (scripts/mcp/wuic-rag-mcp.mjs). Mentre aspetta, il server avvia da solo il caricamento del motore sul backend.

🐛 Bug fix degni di nota

  • AppSettings Editor lento ad aprirsi. Con molte chiavi l'editor poteva impiegare decine di secondi a comparire dopo la risposta del server, perché ogni carattere o aggiornamento di un campo di testo ricontrollava l'editor intero e ricalcolava tutte le etichette tradotte. Ora ogni campo di testo si aggiorna da solo e le etichette sono calcolate una volta: l'apertura scende a pochi secondi.
  • List-grid, row template al primo caricamento. Aprendo direttamente l'URL di una pagina con una list-grid alimentata da un datasource che risponde subito (endpoint custom, hardcodedDatasource), i dati potevano arrivare prima che l'applicazione pubblicasse gli import del row template (gridRowImports). Il template compilato senza quei pipe restava in cache e le righe non si mostravano (in produzione, errore onDestroy su undefined). Ora la griglia compila il row template dopo la pubblicazione degli import; se l'applicazione non li pubblica, compila senza dopo 10 secondi, come prima.

📦 Pacchetti aggiornati

Package Da 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

🔧 Aggiornamenti operativi raccomandati per chi aggiorna

  1. Mappe: verificare che GoogleMaps:ApiKey contenga una chiave vera. Se contiene ancora __SET_GOOGLE_MAPS_API_KEY__, dopo l'aggiornamento le mappe mostrano l'avviso di chiave mancante: è il comportamento atteso, finché non si imposta la chiave.
  2. RAG su server dedicati: chi usa la chat o gli strumenti MCP subito dopo ogni riavvio e ha RAM a sufficienza può impostare "rag-engine-eager-load": "true" in AppSettings. Sulle macchine condivise lasciare il default.
  3. Assistenti di codice con il server MCP WUIC: su un'installazione esistente il workspace contiene la copia precedente di scripts/mcp/wuic-rag-mcp.mjs. Per avere l'attesa del motore, sostituirla con quella del pacchetto (llm-workspace/templates/app-llm-workspace/scripts/mcp/) o rigenerare il workspace come descritto in llm-workspace/README.md. Un client che riceve la richiesta di riprovare deve semplicemente ripetere la chiamata.

v1.7.16

Torna all'indice

Versione precedente pubblicata: 1.7.15 (28 settembre 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


Questa versione corregge i difetti emersi da uno stress test a 100 utenti sui quattro database installati su Linux, e riduce il lavoro che il server fa per ogni richiesta. In sintesi:

  • colonne geografiche scritte correttamente su Oracle e PostgreSQL, con formati dei punti documentati e un errore 400 per i valori non validi;
  • un testo più lungo della colonna risponde 400 invece di 500;
  • Oracle molto più veloce sotto carico;
  • limite dei tentativi di login per IP configurabile.

Come è stata verificata. 100 utenti virtuali per 10 minuti (liste, filtri, ordinamenti, inserimenti, modifiche, cancellazioni, import, export, report) su SQL Server, MySQL, PostgreSQL e Oracle Free, ciascuno su Ubuntu 24.04 con nginx: tra 11.340 e 11.490 operazioni per database, 0 errori HTTP e nessuna riga nel log errori dell'applicazione. Dove una voce è verificata in modo diverso, lo dice.


⚠️ Comportamenti che cambiano

  • Limite di login per IP spento di default. Fino alla 1.7.15 era fisso a 30 tentativi al minuto per IP. Ora vale loginRateLimitPerIpPerMinute, default 0 (spento). Il limite per utente (5 password sbagliate in 5 minuti) resta sempre attivo. Sulle installazioni esposte a internet impostare 30.
  • Posizione non valida rifiutata. Un valore di una colonna point in un formato non riconosciuto ora risponde HTTP 400 errors.input.geo_point.invalid e il record non viene salvato. Prima SQL Server e MySQL salvavano NULL senza errore, Oracle e PostgreSQL rispondevano 500. Un valore vuoto salva NULL come prima.
  • Testo troppo lungo: 400. Un testo più lungo della colonna fisica risponde HTTP 400 errors.input.value_too_long (oppure errors.input.value_too_long.column con args.column, quando il database nomina la colonna) invece di 500 errors.db.sql_exception.
  • Ultima attività della sessione. LastActivityDate si aggiorna al massimo una volta al minuto per utente, non più a ogni richiesta. La scadenza della sessione può spostarsi al massimo di 60 secondi.
  • Cache di sys_info su tutti i database. Prima solo SQL Server teneva la riga in cache per 5 secondi; ora anche MySQL, PostgreSQL e Oracle. Una modifica fatta da fuori (SQL a mano, un altro nodo) si vede entro 5 secondi, e un aumento di project_metadata_version fatto da un altro nodo svuota le cache dei metadati anche su questi tre database.
  • Oracle, installazioni nuove. Il primo avvio crea in ogni schema caricato il trigger di logon WUIC_SESSION_CURSOR_SHARING (vedi sezione Oracle).

🛡️ Sicurezza

Best-effort hardening: limite dei tentativi di login per IP configurabile (loginRateLimitPerIpPerMinute, risposta HTTP 429 errors.auth.login_rate_limited con retryAfterSeconds) con una lista di IP esenti (loginRateLimitExemptIps, IP separati da virgola, trattati come il loopback: mai limitati né contati), entrambi letti a ogni login; su PostgreSQL e Oracle le query che leggono utente e ruoli per id, username o email passano i valori come parametri invece di concatenarli nel testo SQL.

🗺️ Colonne geografiche

  • Oracle: ogni inserimento o modifica con una colonna point o geometry valorizzata falliva (ORA-50028), perché il provider scriveva la sintassi di SQL Server. Ora il valore si converte in WKB (SRID 0, lo stesso formato dei dati del tutorial) e si passa come parametro.
  • PostgreSQL: stesso difetto, ogni inserimento o modifica con una posizione valorizzata falliva. Ora il valore si scrive con ST_GeomFromText (SRID 0).
  • Formati accettati per le colonne point: JSON {"lat": 45.4642, "lng": 9.19} (anche lon/long), coppia 45.4642, 9.19 (latitudine, longitudine), WKT POINT(9.19 45.4642) (longitudine, latitudine), testo Lat: 45.4642, Long: 9.19. Il separatore decimale è il punto. In lettura la posizione torna sempre come JSON.
  • Valori non validi: HTTP 400 errors.input.geo_point.invalid con colonna e valore ricevuto. Su Oracle le colonne geometry accettano WKT POINT, POLYGON e MULTIPOLYGON a due dimensioni; un WKT non valido risponde errors.input.geo_wkt.invalid. Messaggi tradotti nelle 5 lingue.

Verifica: un test end-to-end sui quattro database inserisce e modifica una posizione in ciascuno dei quattro formati e la rilegge con le coordinate attese, controlla che un valore non valido sia rifiutato con 400 senza toccare il dato e che un valore vuoto salvi NULL.

🗄️ Oracle sotto carico

  • Primo avvio: dopo il caricamento di ogni schema il framework crea il trigger di logon WUIC_SESSION_CURSOR_SHARING, che imposta CURSOR_SHARING = FORCE per le sessioni dell'applicazione, e raccoglie le statistiche dello schema (DBMS_STATS.GATHER_SCHEMA_STATS). Se uno dei due passi fallisce, l'errore finisce nel log e il primo avvio prosegue.
  • Autenticazione: l'id utente si confronta con la colonna senza TO_CHAR, quindi Oracle usa l'indice della chiave invece di leggere tutta la tabella utenti a ogni richiesta.
  • Lettura delle colonne spaziali: la conversione del BLOB in JSON o WKT avviene nel server applicativo dopo la lettura, non più con una funzione PL/SQL eseguita riga per riga.
  • Chiave MAX: con inserimenti contemporanei su tabelle padre e figlia, il blocco che calcola la chiave poteva chiudersi in deadlock (ORA-00060). Ora ritenta fino a 3 volte.

Misurato con lo stesso carico, prima e dopo queste modifiche (incluse quelle della sezione successiva), su un'installazione esistente a cui trigger e statistiche sono stati applicati a mano: tempo del database speso nelle istruzioni SQL da 794 a 61 secondi, hard parse da 73.719 a 7.379, CPU di Oracle al 95° percentile dal 26,5% al 6,4%. Al 95° percentile le liste passano da 1,6 s a 0,16 s, la lettura di un record da 1,28 s a 68 ms, getTableMetadata da 1,95 s a 0,32 s.

⚡ Meno lavoro per richiesta

  • sys_info: la riga veniva riletta circa 7 volte per richiesta su MySQL, PostgreSQL e Oracle (su MySQL il 23,7% del tempo del database nello stress test). Ora si legge al massimo una volta ogni 5 secondi per tenant, su tutti i database.
  • LastActivityDate: l'UPDATE a ogni richiesta autenticata valeva il 34,7% del tempo del database su MySQL. Ora si esegue al massimo una volta al minuto per utente, su tutti i database; i secondi dall'ultima attività li calcola il database, con il suo orologio.
  • PostgreSQL: al primo avvio, dopo il caricamento degli script, il framework esegue ANALYZE, così le prime query non pianificano senza statistiche. Lo fa anche l'installer Linux.
  • Report: ogni stampa scriveva una riga "report call" nel log errori (_error__logs). Non la scrive più.

🐛 Bug fix degni di nota

  • PostgreSQL, filtri su colonne boolean: un filtro su una colonna boolean nativa falliva con 42883: operator does not exist: boolean = integer.
  • PostgreSQL, errori SQL nelle liste: arrivano al client come errors.db.sql_exception con il codice SQLSTATE, invece di errors.server.unhandled.
  • Change log di cancellazioni e modifiche: su MySQL il change log delle cancellazioni non veniva mai scritto. Su MySQL e SQL Server la data passava come testo e la conversione dipendeva dalla lingua del server (su SQL Server su Linux falliva a ogni cancellazione). Ora la data è un parametro tipizzato.
  • Upload salvati nel database: modificare un record con una colonna di upload su database dal nome con maiuscole falliva su PostgreSQL (42703). Il nome della colonna ora è quotato, e lo stesso vale su MySQL e SQL Server.
  • MySQL, ordinamento predefinito: su una tabella senza chiave nei metadati la lista si ordinava per la prima colonna anche se spaziale o binaria, con Out of sort memory. Ora le colonne spaziali e binarie sono escluse.
  • MySQL, indici sui metadati: lo script che crea gli indici su route e colonne dei metadati falliva a ogni avvio e gli indici non venivano mai creati. Ora si creano all'avvio.
  • Lunghezza massima nei metadati: mc_max_length delle colonne nvarchar/nchar era registrata in byte, cioè il doppio dei caratteri: nei form si potevano digitare fino al doppio dei caratteri e il salvataggio falliva. Ora lo scaffolding registra i caratteri e negli script di primo avvio le lunghezze sono quelle fisiche: 127 colonne corrette nel tutorial SQL Server (comprese le viste del tutorial e tabelle di sistema come _mail_recipients, _mailing_lists, _notifications, _wuic_workflow_instance_log e scheduler_execution), 21 nel profilo minimale SQL Server, 41 su MySQL, 34 su PostgreSQL e 34 su Oracle. Il controllo della lunghezza massima nei form ora corrisponde alla colonna.
  • Tutorial, archivio temperature: su SQL Server la prima pagina della lista di Warehouse.ColdRoomTemperatures_Archive (3,65 milioni di righe) andava in timeout sotto carico. Due indici creati all'avvio la portano da 5,4 s a 6 ms (misurato su SQL Server su Linux). Su MySQL, PostgreSQL e Oracle all'avvio si crea un indice sulla chiave; lì il caso non è stato misurato.

🐧 Installer Linux

  • nginx: worker_connections 4096, worker_rlimit_nofile 16384, e connessioni keep-alive verso Kestrel invece di una connessione nuova per ogni richiesta (WebSocket invariati).
  • Database: MySQL e PostgreSQL con 300 connessioni e buffer al 25% della RAM (fra 128 MB e 8 GB), Oracle Free con PROCESSES 400 (un riavvio del container durante l'installazione). SQL Server resta Express.
  • Servono per alcune centinaia di utenti: a 100 utenti i default bastavano ancora (MySQL 59 connessioni su 151, Oracle 148 processi su 200). Lo stress test descritto sopra è stato eseguito con i valori precedenti; questi passi dell'installer non sono ancora stati provati su un'installazione da zero.
  • Un'installazione esistente mantiene i valori precedenti. I comandi per alzarli a mano sono nel README del tarball Linux, sezione "Capacity for hundreds of concurrent users".

📦 Pacchetti aggiornati

Package Da 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

🔧 Aggiornamenti operativi raccomandati per chi aggiorna

  1. Installazioni esposte a internet: impostare in AppSettings "loginRateLimitPerIpPerMinute": "30", il valore fisso della 1.7.15. Per gli stress test da un solo IP aggiungere quell'IP a loginRateLimitExemptIps.
  2. Client che gestiscono i codici di errore: un testo troppo lungo e una posizione non valida arrivano ora come HTTP 400 con i codici errors.input.value_too_long, errors.input.value_too_long.column e errors.input.geo_point.invalid. Su tutti i database le installazioni nuove hanno i messaggi dei quattro nuovi codici (errors.input.geo_point.invalid, errors.input.geo_wkt.invalid, errors.input.value_too_long, errors.input.value_too_long.column) tradotti nelle 5 lingue; su un'installazione esistente, finché le traduzioni non vengono aggiunte dalla gestione delle traduzioni dell'interfaccia, compare il messaggio di riserva.
  3. Oracle, installazioni esistenti: per avere trigger e statistiche delle installazioni nuove, eseguire come utente di ciascuno schema (dati e metadati):
    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;
    /
    
    Per tornare al comportamento precedente: DROP TRIGGER WUIC_SESSION_CURSOR_SHARING.
  4. Linux con molti utenti contemporanei: su un'installazione esistente alzare i limiti di nginx e del database con i comandi del README del tarball Linux.
  5. Tutorial su SQL Server: il primo avvio dopo l'aggiornamento costruisce due indici su Warehouse.ColdRoomTemperatures_Archive (15-25 secondi l'uno, misurati): quell'avvio dura di più, una volta sola.
  6. Più nodi sullo stesso database: le modifiche a sys_info fatte da un nodo arrivano agli altri entro 5 secondi.
  7. Lunghezze nei metadati, installazioni esistenti: i metadati già presenti non vengono corretti in automatico. Chi vuole allinearli può rilanciare lo scaffolding della tabella oppure impostare mc_max_length della colonna al numero di caratteri.

v1.7.15

Torna all'indice

Versione precedente pubblicata: 1.7.14 (25 settembre 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


Questa versione corregge i difetti emersi dal test di carico della 1.7.14 e da una campagna di test su installazioni pulite dei quattro database (SQL Server, MySQL, PostgreSQL, Oracle). In sintesi:

  • apertura delle route circa dieci volte più veloce sotto carico;
  • chiavi MAX senza duplicati con inserimenti contemporanei, ed export su SQL Server che non blocca più le scritture;
  • import ed export portabili fra database, con difetti corretti su Oracle e PostgreSQL;
  • logout su Oracle che ora chiude davvero la sessione.

🛡️ Sicurezza

Logout su Oracle. Su Oracle il logout non invalidava il token di sessione: dopo il logout, lo stesso cookie continuava a leggere i dati. Il logout ora chiude la sessione anche su Oracle. Chi usa Oracle dovrebbe aggiornare.

⚡ Prestazioni

Metadati all'apertura di una route. La lettura dei metadati di una route (getTableMetadata) è circa dieci volte più veloce. I permessi per utente, ruolo e azienda si valutano senza ricompilare un'espressione per ogni colonna, e la serializzazione riusa la configurazione invece di ricostruirla a ogni chiamata. Il risultato non cambia: stessi permessi, stesso JSON.

Sul server demo (SQL Server, 100 utenti contemporanei) il 95° percentile della chiamata è sceso da 2,4-4,5 s a 0,2-0,4 s, e il 95° percentile della CPU del processo dal 54% al 31%.

🔑 Chiave primaria MAX

Sulle route con md_primary_key_type = "MAX" la chiave di una riga nuova è il massimo + 1. Fino alla 1.7.14 il massimo veniva letto con una query separata dall'insert: due utenti che salvavano nello stesso istante potevano ricevere la stessa chiave, e il secondo salvataggio falliva con una violazione di chiave primaria.

  • Il massimo si calcola ora dentro l'insert, con un lock sulla tabella fino al commit: inserimenti contemporanei ricevono chiavi consecutive.
  • Vale anche per la "chiave dipendente" delle chiavi composte (massimo + 1 per ogni valore della chiave padre).
  • Vale per inserimento dal form, duplicazione di un record e import da Excel.
  • Il meccanismo del lock dipende dal database: UPDLOCK, HOLDLOCK su SQL Server, SELECT ... FOR UPDATE su MySQL, un advisory lock di transazione su PostgreSQL, LOCK TABLE ... IN EXCLUSIVE MODE su Oracle.

Un import che inserisce righe nuove in una tabella con chiave MAX tiene il lock fino alla fine del file: nel frattempo gli altri inserimenti sulla stessa tabella aspettano, e su Oracle anche modifiche e cancellazioni.

📤 Export su SQL Server

Un export legge la tabella per tutto il tempo in cui scrive il file. Con l'isolamento predefinito di SQL Server quella lettura bloccava inserimenti e modifiche sulla stessa tabella fino alla fine dell'export (misurato: un update in attesa per 5,5 s durante l'export di 70.000 righe).

  • Se il database dei dati ha ALLOW_SNAPSHOT_ISOLATION ON, l'export legge in isolamento snapshot e le scritture non aspettano più (stesso update: circa 100 ms). Il file contiene gli stessi dati.
  • L'opzione vale solo per l'export: le altre letture non cambiano comportamento. Convive con READ_COMMITTED_SNAPSHOT ON.
  • Senza l'opzione l'export funziona come prima.
  • Il database dati del tutorial nasce con READ_COMMITTED_SNAPSHOT ON, che toglie lo stesso blocco anche alle letture delle griglie.

📥 Import ed export fra database

  • Oracle, lookup nell'export. Nelle colonne lookup l'export scriveva la chiave al posto della descrizione (per esempio 16 invece del nome della persona). Il file non si reimportava: "no record of 'people' has this description". Ora l'export scrive la descrizione, e il giro export → modifica → import funziona su Oracle come sugli altri database.
  • PostgreSQL, import. Ogni import che cercava righe esistenti per chiave falliva con 42883: operator does not exist: integer = text. La chiave letta dal file viene ora convertita nel tipo della colonna.
  • Intestazioni portabili. La colonna chiave di una lookup (modalità chiave + descrizione) e le parentesi che distinguono due colonne con la stessa etichetta usano ora il nome della colonna nei metadati WUIC, uguale su ogni database, e non il nome fisico (su Oracle in maiuscolo, per esempio CONTACTPERSONID). Un file esportato da un database si reimporta su un altro. I file esportati prima, con il nome fisico, si reimportano come prima.

🌐 Pagina "Traduzioni dati"

La pagina di amministrazione delle traduzioni dei record (_record_field_translations) ora mostra le traduzioni salvate, con i nomi di tabella e utente, su tutti e quattro i database.

  • MySQL: la lista rispondeva con un errore del database.
  • Oracle: la lista falliva con ORA-00942, perché le tabelle degli utenti e dei metadati stanno in un altro schema. Il framework ora qualifica lo schema e concede all'utente dei dati il SELECT necessario al primo utilizzo.
  • PostgreSQL: la lista leggeva la tabella sbagliata e non mostrava le traduzioni salvate. Ora legge quella del database dati. Poiché PostgreSQL non unisce tabelle di database diversi, i nomi di utenti e tabelle si leggono con una query separata. Ordinamento e raggruppamento su queste colonne lavorano sulla chiave.

🗄️ Oracle

  • Reinstallazione su un database esistente. Nel primo avvio, la conferma di ricreare il database falliva con ORA-01940 se l'utente aveva ancora sessioni aperte. Ora le sessioni vengono chiuse e attese prima del DROP USER.
  • Metadati del tutorial. I metadati del tutorial Oracle sono allineati a quelli di SQL Server: descrizioni delle lookup e altre proprietà delle colonne. Vale per le installazioni nuove del tutorial.

🐛 Bug fix degni di nota

  • Editor di codice SQL: su MySQL, PostgreSQL e Oracle i suggerimenti di schemi, tabelle e colonne arrivavano vuoti. Ora sono completi.
  • Cache dei dati: con cacheDataMinutes attivo, il conteggio delle righe in cache non scadeva mai, e una voce scaduta non veniva più rimessa in cache. Righe e conteggi ora scadono dopo il tempo configurato.
  • Pivot: salvare una seconda volta la stessa configurazione pivot rispondeva 500.
  • Raggruppamento (SQL Server): raggruppare lato server senza aggregati rispondeva 500.
  • Installer Windows (IIS): in alcuni casi l'applicazione partiva prima che il sito fosse configurato e restava in errore fino al riciclo del pool. L'installer ora ricicla il pool prima di avviare il sito.

📦 Pacchetti aggiornati

Package Da 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

🔧 Aggiornamenti operativi raccomandati per chi aggiorna

  1. SQL Server, export senza blocchi: eseguire una volta ALTER DATABASE [<database dati>] SET ALLOW_SNAPSHOT_ISOLATION ON. L'opzione aumenta l'uso di tempdb finché ci sono transazioni aperte.
  2. Import grandi su tabelle a chiave MAX molto usate: mettere la chiave nel file, oppure passare la tabella a IDENTITY/SEQUENCE, per non tenere il lock per tutta la durata dell'import.
  3. Pagina "Traduzioni dati" su installazioni esistenti MySQL, PostgreSQL e Oracle: nei metadati tabelle, la route _record_field_translations deve avere connessione DataSQLConnection e non essere una route di sistema. Le installazioni nuove nascono già così.
  4. Oracle: aggiornare anche solo per il logout.

v1.7.14

Torna all'indice

Versione precedente pubblicata: 1.7.13 (24 settembre 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


Questa versione nasce da un test di carico con molti utenti contemporanei su un'installazione pubblica: export e import dello stesso file, filtri, ordinamenti, report. L'export è quattro volte più veloce e passa da una coda che protegge il server; l'import rilegge correttamente i file prodotti dall'export, anche con lookup dalla descrizione ripetuta. Sono corretti anche due difetti delle griglie con lookup e colonne geografiche.


📤 Export

  • Più veloce e più leggero. L'export XLSX di 230.000 righe passa da 28,5 s a 7,4 s e da 12,2 GB a 2,3 GB di memoria allocata. Il contenuto del file non cambia.
  • Coda degli export. Il server esegue al massimo maxConcurrentExports export insieme (default: metà dei core, almeno 1). Gli altri aspettano in ordine di arrivo, fino a maxQueuedExports (default 10). Oltre, la richiesta risponde 503 errors.metaservice.export.queue_full.
  • Attesa visibile. Finché l'export è in coda, il dialog di avanzamento e la campanella mostrano "In coda: posizione N". Un export in coda si può annullare.
  • Impostazioni con effetto immediato. Le due chiavi sono nell'editor delle impostazioni (sezione App Runtime) e si leggono a ogni export, senza riavvio.
  • Nome del file univoco. Due export della stessa route partiti nello stesso secondo non scrivono più lo stesso file (prima tutti tranne uno rispondevano 500).

📥 Import

Colonne lookup nel file: fkey_mode. Una route importabile sceglie come stanno nel file le colonne lookup, con import.fkey_mode nel props bag della route:

  • description (default): la descrizione, come nella griglia;
  • key: il valore della chiave;
  • both: entrambe, la descrizione sotto il titolo della colonna e la chiave sotto il nome fisico.

Il dialog di import mostra la scelta preselezionata e la lascia cambiare per il singolo import. L'export segue la stessa scelta, quindi un file esportato si reimporta così com'è. use_descriptive_fkey resta accettato dai client che non conoscono fkey_mode.

Intestazioni. Ogni colonna ha come intestazione il suo titolo. Solo quando due colonne dello stesso file hanno lo stesso titolo, il nome fisico della colonna compare tra parentesi.

Regole per le lookup lette dalla descrizione.

  • Descrizione unica: si usa la sua chiave.
  • Descrizione condivisa da più record: in aggiornamento resta la chiave attuale del record, se è una di quelle possibili; negli altri casi la riga viene rifiutata con l'elenco delle chiavi candidate.
  • Chiave e descrizione nello stesso file che non corrispondono: la riga viene rifiutata.

Altre correzioni.

  • Le celle data di Excel vengono lette come date: un file esportato e reimportato senza modifiche non viene più rifiutato.
  • Una chiave primaria che è anche lookup viene risolta prima del controllo di esistenza del record.
  • Il controllo di esistenza usa parametri SQL invece di concatenare i valori del file.

🐛 Bug fix degni di nota

  • Due lookup verso la stessa tabella: la seconda colonna mostrava la descrizione vuota. Ogni chiave esterna ha ora il proprio alias nella query, su tutti i database.
  • Colonne geografiche: ordinare la griglia per una colonna geography falliva su SQL Server (errore 249). Negli script di primo avvio le colonne geografiche hanno mc_disable_sorting attivo, quindi la griglia non offre l'ordinamento.
  • Lingue disponibili: GetSupportedLanguages restituisce le lingue della tabella lingue.
  • Report: reportQueryTimeout è facoltativo, con 120 secondi se manca; la chiave è negli appsettings.json dei pacchetti.
  • Script di primo avvio: sequence e identity partono dopo i dati caricati, quindi il primo inserimento non va in conflitto con una chiave esistente. Nel tutorial, Countries, DeliveryMethods, People, StateProvinces, Customers e Invoices generano la chiave da sole invece di chiederla nel form.
  • Oracle: le identity vengono riallineate all'avvio.

📦 Pacchetti aggiornati

Package Da 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

🔧 Aggiornamenti operativi raccomandati per chi aggiorna

  1. Dimensionare la coda degli export: ogni export completo di una tabella grande usa circa un core e 300 MB durante la scrittura. Su un server condiviso con altre applicazioni impostate maxConcurrentExports sotto il default (per esempio 2).
  2. Route importabili: se i vostri file contengono chiavi e non descrizioni, impostate "import": { "fkey_mode": "key" } nel props bag della route; con both l'export produce anche le colonne chiave.
  3. Installazioni con il tutorial già caricato: gli script di primo avvio valgono solo per le nuove installazioni. Per togliere l'ordinamento dalle colonne geografiche esistenti eseguite sul database dei metadati UPDATE _metadati__colonne SET mcdisablesorting = 1 WHERE LOWER(mc_db_column_type) IN ('point', 'geography', 'geometry') e svuotate la cache dei metadati.
  4. Client che leggono l'avanzamento dal WebSocket delle notifiche: il messaggio di avanzamento dell'export ha il nuovo campo queuePosition, presente finché l'export aspetta in coda.

v1.7.13

Torna all'indice

Versione precedente pubblicata: 1.7.12 (20 settembre 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


Questa versione è soprattutto un rilascio di sicurezza. Un audit dell'intera superficie delle API ha trovato metodi e controller raggiungibili senza login, oppure da un utente senza diritti di amministrazione, e dati di sessione presi dalla richiesta invece che dal server. Sono stati chiusi tutti, con un test automatico per ogni caso. Insieme arrivano le correzioni emerse dalle celle di test su PostgreSQL, MySQL e Oracle e il completamento del multi-tenant.

Si consiglia l'aggiornamento a tutte le installazioni. Leggete la sezione finale "Aggiornamenti operativi": un paio di comportamenti cambiano.


🛡️ Sicurezza

Chiamate AsmxProxy chiuse per default. Ogni metodo raggiungibile da /api/Meta/AsmxProxy/{servizio}.{metodo} richiede ora una sessione valida, salvo quelli dichiarati anonimi. Tre attributi del namespace WEB_UI_CRAFTER.Helpers governano l'accesso:

  • [AsmxAnonymous]: metodo chiamabile senza login (login, me, traduzioni, registrazione, reset password);
  • [AsmxAdmin]: riservato agli amministratori (ruolo superadmin);
  • [AsmxFirstRun]: anonimo solo durante il primo avvio, poi riservato agli amministratori.

Il proxy invoca inoltre solo le classi di servizio (MetaService, scaffolding, i servizi dell'applicazione in WEB_UI_CRAFTER.ProjectData.Servizi): un nome di classe completo di altri namespace viene rifiutato.

Sessione verificata ovunque. Hardening best-effort su tutta la gestione della sessione:

  • il cookie k-user è validato sul server anche con i provider PostgreSQL e Oracle (token, scadenza, sessione sostituita da un nuovo login);
  • l'utente di impostazioni personali, menu e pivot è quello della sessione, non quello indicato nella richiesta;
  • il logout chiude solo la propria sessione;
  • in multi-tenant, il flag superadmin del cookie vale solo se il database lo conferma;
  • la lista utenti non restituisce più token e IP di sessione.

Anche gli endpoint dei controller sono allineati:

  • editor di appsettings.json, OData, upload e report verificano sessione e ruolo sul server;
  • l'upload resta nella cartella del record;
  • il designer accetta solo fogli .css del progetto;
  • le funzioni di amministrazione di webhook, metriche e licenza sono riservate agli amministratori.

Notifiche. Endpoint REST e WebSocket delle notifiche sono legati all'utente della sessione: una richiesta per un altro utente riceve 403 errors.auth.notification_forbidden. Il WebSocket funziona anche dietro un reverse proxy, grazie a X-Forwarded-For.

Registrazione spenta per default. Si accende solo con registrationEnabled=true in appsettings.json e non assegna mai un ruolo admin o superadmin: default-role-id deve indicare un ruolo esistente senza diritti di amministrazione.

Primo avvio.

  • La password scelta nel wizard per l'amministratore viene applicata anche se il nome coincide con un utente già presente.
  • Gli script di primo avvio MySQL e Oracle non contengono più gli utenti dei test automatici.
  • L'utente dedicato wuic_assistant (WUIC Assistant, server MCP) viene creato con una password generata per ogni installazione, salvata in scripts/mcp/wuic-assistant.credentials.json (escluso da git).

🤖 RAG e WUIC Assistant

  • /api/Rag/Chat richiede il login; /api/Rag/Query resta senza login.
  • I dettagli di /api/Rag/MetadataDetail che restituiscono dati (sample_records, lookup_value, db_*) sono riservati agli amministratori.
  • La chiave LLM configurata sul server non viene mai inviata a un provider o a un indirizzo scelti da chi chiama.
  • Il server MCP wuic-rag apre da solo la sessione quando serve, con WUIC_USER/WUIC_PASSWORD o con il file credenziali dell'utente wuic_assistant.

🏢 Multi-tenant

  • Cache separate per tenant per menu, permessi di tabella e colonna, stili, route disponibili e cache dati: un tenant non vede più le voci di un altro.
  • La propagazione di una tabella ai tenant invalida la cache di ogni tenant di destinazione, così la nuova voce compare subito nei menu.
  • Notifiche per tenant.
  • Supporto PostgreSQL.

🗄️ Provider di database

  • PostgreSQL: paginazione, cache dati, filtri many-to-many vuoti, temi, date con qualunque host.
  • MySQL: conteggi sulle select distinte, vincoli di sistema, caricamento dei provider su Linux.
  • Oracle:
    • paginazione, filtri geografici (area e distanza), restrizione dei record per utente e ruolo, nomi delle stored procedure, booleani su colonne numeriche, raggruppamento su testo lungo, cache dati;
    • traduzioni molto più veloci: da 3-4,6 s a 0,3-0,7 s;
    • numero corretto di righe aggiornate e cancellate;
    • dati geografici completi negli script di primo avvio (tutti gli stati e i paesi);
    • demo del workflow di approvazione ordini;
    • nomi delle colonne timeline allineati agli altri database.
  • Tutti: errore di concorrenza ottimistica tipizzato (409 errors.validation.optimistic_concurrency), percorso di upload unico, date di creazione delle notifiche in UTC (migrazione automatica), restrizioni per ruolo corrette per gli utenti con più ruoli.

🐛 Bug fix degni di nota

  • Navigazione tra record via URL: passando da un record all'altro in modifica o in dettaglio, il dialog ricarica il record nuovo invece di mostrare quello precedente.
  • data-record-loaded torna a false quando il dialog ricarica il record, così i test automatici non leggono dati vecchi.
  • Filtro geografico attende il caricamento di Google Maps prima di disegnare.
  • Lista scheduler applica il template prima di ricaricare i dati.

📦 Pacchetti aggiornati

Package Da 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

🔧 Aggiornamenti operativi raccomandati per chi aggiorna

  1. Servizi custom chiamati prima del login: i metodi dei vostri servizi in WEB_UI_CRAFTER.ProjectData.Servizi che devono rispondere senza sessione vanno marcati [AsmxAnonymous]; senza, rispondono 401 errors.auth.unauthenticated.
  2. Registrazione: se la usate, impostate registrationEnabled=true e verificate che default-role-id indichi un ruolo senza diritti di amministrazione.
  3. Utente wuic_assistant su installazioni esistenti: la vecchia password predefinita non è più accettata. Impostatene una nuova da un amministratore e scrivetela in scripts/mcp/wuic-assistant.credentials.json (oppure nelle impostazioni dell'estensione WUIC Assistant).
  4. Installazioni Oracle e MySQL con tutorial fino alla 1.7.12: controllate la tabella utenti ed eliminate gli utenti wuic_e2e_admin, wuic_e2e_admin_2, wuic_e2e_admin_3 e guest_1, se presenti.
  5. Strumenti che leggevano dati da /api/Rag/MetadataDetail o usavano /api/Rag/Chat senza login: devono ora autenticarsi (per i dati, con un amministratore).

v1.7.12

Torna all'indice

Versione precedente pubblicata: 1.7.11 (20 settembre 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


Questa versione chiude per davvero i report che stampavano una pagina vuota su MySQL e PostgreSQL. Le due versioni precedenti dichiaravano risolto quel difetto correggendo la query: la query non era il problema, e il report continuava a uscire con l'intestazione e nessuna riga. La causa vera è stata trovata confrontando, sulla stessa installazione, un report del pacchetto e uno costruito sul momento con le colonne di quell'installazione: stampavano vuoti tutti e due, quindi il problema non era nel file del report.


📊 I report stampano i loro dati su MySQL e PostgreSQL

Un report Stimulsoft tiene nel suo dizionario due cose distinte: la connessione al database e il tipo della sorgente dati. Quando si apre un report, il framework sostituiva la connessione con quella del motore in uso — StiMySqlDatabase, StiPostgreSQLDatabase — ma lasciava la sorgente dati del tipo con cui era stata creata, StiSqlSource, che per Stimulsoft significa SQL Server.

Una sorgente SQL Server appoggiata a un database MySQL non solleva nessun errore: restituisce semplicemente un insieme di dati vuoto. Il report veniva disegnato correttamente — intestazione, cornice, "pagina 1 di 1" — e non stampava una riga.

La conversione della sorgente al tipo del motore esisteva già nel prodotto, ma solo per Oracle, in due punti distinti (il visualizzatore e il designer). Ora vale anche per MySQL e PostgreSQL, in entrambi. Chi ha report che stampavano in bianco non deve rigenerare niente: basta riaprirli.

🔑 Indici dei metadati su MySQL

Sulle installazioni MySQL create dal primo avvio guidato, la migrazione che crea gli indici sui percorsi caldi dei metadati falliva con Fatal error encountered during command execution.

Il motivo sta nella stringa di connessione scritta dal wizard: senza Allow User Variables=True il driver MySQL interpreta ogni @nome presente in uno script come un parametro invece che come variabile del server. Le query normali del framework usano davvero i parametri, quindi funzionavano; quella migrazione usa le variabili del server, e moriva. La chiave viene ora aggiunta alla connessione dei metadati, sia quando la compone il wizard sia quando la riscrive il backend.

🧩 Query dinamica su PostgreSQL

Il gateway PostgreSQL chiamava la funzione che costruisce le query dinamiche passandole 19 argomenti, mentre il satellite PostgreSQL ne accetta 15: la chiamata falliva sempre, con MissingMethodException. Ora gli argomenti sono quelli giusti, e il messaggio d'errore di quel gateway dice anche quanti argomenti sono stati passati e quante versioni del metodo esistono — perché "metodo non trovato", da solo, manda a cercare un metodo che invece c'è.

📦 Pacchetti aggiornati

Package Da 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

🔧 Aggiornamenti operativi raccomandati per chi aggiorna

  1. Nessuna modifica di configurazione richiesta: le chiavi di appsettings.json non cambiano.
  2. Se avete report che stampavano vuoto su MySQL o PostgreSQL, riapriteli: non c'è niente da rigenerare.
  3. Su installazioni MySQL già in servizio, se volete che la migrazione degli indici vada a buon fine, aggiungete Allow User Variables=True alla MetaDataSQLConnection in appsettings.json. Le installazioni nuove la ricevono dal primo avvio guidato. Su MySQL l'impatto è contenuto: due dei tre indici sono già coperti dal vincolo di unicità della route e dall'indice che InnoDB crea da sé per le chiavi esterne.

v1.7.11

Torna all'indice

Versione precedente pubblicata: 1.7.10 (19 settembre 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


Questa versione chiude due difetti che la 1.7.10 dichiarava risolti e che invece continuavano a presentarsi: i report scaffoldati che stampano una pagina vuota, e lo scaffolding di una tabella dall'interfaccia che risponde con un errore. Li ha ritrovati la stessa serie di installazioni su macchine pulite che aveva prodotto la versione precedente, questa volta ripetuta sul prodotto pubblicato per verificare le correzioni. Riguardano ancora chi non usa SQL Server.


📊 I report scaffoldati stampano davvero i loro dati su MySQL e PostgreSQL

La 1.7.10 introduceva la riscrittura della query dei report generati dal framework, perché il .mrt che viaggia nel pacchetto porta gli identificatori del motore su cui è stato creato. La riscrittura però non entrava mai in funzione: cercava la tabella dei metadati usando il nome del database del dizionario — che vale sempre Connessione — invece del nome del data source, che è la route. Non trovando nessuna tabella con quel nome usciva in silenzio, senza riscrivere niente e senza lasciare traccia, e il report continuava a stampare la pagina con l'intestazione e nessuna riga.

Ora la route viene letta dal posto giusto, e ogni caso in cui la riscrittura non può avvenire — nessuna tabella con quel nome, tabella senza colonne — lascia una riga nel log del backend. Un report vuoto senza una spiegazione è esattamente ciò che ha reso questo difetto difficile da vedere.

Chi ha report generati che stampavano in bianco su MySQL o PostgreSQL non deve rigenerare niente: basta riaprirli.

🧱 Scaffolding di una tabella dall'interfaccia su Oracle

Su Oracle, generare una tabella dall'interfaccia rispondeva HTTP 500 con ORA-00001: unique constraint ... violated sulla tabella dei menu, e la route non veniva creata.

È lo stesso difetto corretto per PostgreSQL nella versione precedente, che su Oracle era rimasto scoperto. Lo schema dichiara la chiave del menu come GENERATED BY DEFAULT AS IDENTITY, ma il framework inserisce le proprie voci di sistema con la chiave calcolata a mano: il generatore non avanza, e la prima riga che si affida a lui chiede una chiave già occupata. Il riallineamento del generatore ora vale per entrambi i motori.

📦 Pacchetti aggiornati

Package Da 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

🔧 Aggiornamenti operativi raccomandati per chi aggiorna

  1. Nessuna modifica di configurazione: le chiavi di appsettings.json non cambiano.
  2. Se avete report generati su MySQL o PostgreSQL che stampavano vuoto, riapriteli: la query viene riscritta al momento del rendering, non c'è niente da rigenerare.
  3. Su Oracle, se lo scaffolding di una tabella dall'interfaccia vi rispondeva con un errore di chiave duplicata, riprovate: il generatore di chiavi del menu viene riallineato dopo ogni inserimento con chiave esplicita.

v1.7.10

Torna all'indice

Versione precedente pubblicata: 1.7.9 (18 settembre 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


Questa versione nasce da una tornata completa di installazioni end-to-end su macchine pulite: sedici combinazioni, i quattro pacchetti di distribuzione per i quattro motori supportati, partendo ogni volta dallo zip pubblicato e seguendo la documentazione come farebbe chi installa per la prima volta. Quello che ne è uscito riguarda quasi tutto chi non usa SQL Server: report che stampavano una pagina vuota, uno scaffolding che falliva, indici che non nascevano mai. Tutti difetti silenziosi — nessun messaggio a schermo, solo una funzione che non funzionava.


📊 I report tornano a stampare i dati su MySQL e PostgreSQL

Aprendo un report del tutorial su MySQL o PostgreSQL il visualizzatore disegnava la pagina — intestazione, cornice, "pagina 1 di 1" — e non stampava nemmeno una riga. Su SQL Server lo stesso report funzionava.

Il motivo è che un report scaffoldato dal framework porta dentro di sé la query che lo alimenta, e quella query è scritta con gli identificatori del motore su cui il report è stato generato. Il file .mrt però viaggia nel pacchetto ed è lo stesso per tutti e quattro i motori: quello dei tutorial contiene identificatori non quotati in maiuscolo. Su SQL Server passa, perché lì il confronto è insensibile al caso; su PostgreSQL un identificatore non quotato viene ripiegato in minuscolo e non trova più le colonne, che il tutorial crea quotate in PascalCase.

Ora, prima di renderizzare, i report generati dal framework — riconoscibili dal marcatore che portano nella SELECT — si fanno rigenerare la query dai metadati per il motore dell'installazione corrente, con le regole di quotatura giuste. I report scritti a mano nel designer non vengono toccati: la loro query resta quella che avete scritto voi.

🧱 Scaffolding di una tabella dall'interfaccia su PostgreSQL

Su PostgreSQL, scaffoldare una tabella dall'interfaccia rispondeva HTTP 500 con una violazione di chiave esterna su _metadati__colonne, e la route generata restava senza righe.

Il difetto vero era a monte, ed era doppio. La sequenza identity della tabella dei menu resta indietro quando qualcuno inserisce righe con la chiave esplicita — cosa che il framework fa quando aggiunge le proprie voci di sistema: da lì in avanti il primo inserimento che si affida alla sequenza chiede una chiave già occupata. E quando la creazione della voce di menu falliva, il codice cancellava la tabella di metadato appena inserita, lasciando le colonne senza il loro padre: l'errore che arrivava all'utente parlava quindi di chiavi esterne e di una tabella che non c'entrava.

Ora la sequenza viene riallineata dopo ogni inserimento con chiave esplicita, e un menu che non si crea non porta più via il metadato della tabella: al massimo la voce di menu si aggiunge dal designer.

⚡ Gli indici dei metadati adesso nascono davvero

Le migrazioni di schema che creano gli indici sui percorsi caldi dei metadati — nome della route, colonne per tabella, scheduler — non venivano applicate su un'installazione nuova, per due motivi diversi.

Il primo: all'avvio di un'applicazione appena installata le connection string non ci sono ancora, quindi le migrazioni fallivano; e siccome il tentativo veniva considerato consumato, non venivano più riprovate nel processo. Su un'installazione nuova, dove nessuno riavvia il servizio subito dopo, quegli indici non nascevano mai. Ora la condizione "database non ancora configurato" non consuma il tentativo, e le migrazioni girano appena il primo avvio guidato ha scritto le connection string.

Il secondo, solo su Oracle: lo script degli indici citava le colonne quotate in minuscolo mentre lo schema le crea in maiuscolo, quindi rispondeva ORA-00904 e la migrazione si fermava lì.

L'effetto per chi usa il prodotto è sulle pagine che dipendono da quegli indici: apertura di una lista dal menu, rientro in una lista già visitata, prima voce del menu Amministrazione. Senza indici quelle operazioni arrivavano a decine di secondi su PostgreSQL.

🤖 L'assistente in VS Code risponde alle domande invece di scrivere codice

Chiedendo all'assistente "quali colonne ha la route X?" — anche aggiungendo "non modificare file" — l'assistente scaffoldava un componente e rispondeva descrivendo quello che aveva scritto. La domanda restava senza risposta e il progetto veniva modificato contro istruzione.

Ora una richiesta che è una domanda, o che vieta esplicitamente le modifiche, mette l'assistente in sola lettura: gli strumenti che toccano il progetto vengono rifiutati, e la risposta si costruisce con i tool di interrogazione (colonne e metadati della route, ricerca nel codice e nella documentazione).

🔧 Installazioni più tolleranti agli intoppi transitori

  • Windows: quando winget risponde che un'altra installazione è già in corso — il caso tipico è Windows Update appena dopo l'avvio — l'installer non si ferma più dicendo "installalo a mano": riprova tre volte con attesa crescente. Quella condizione si libera da sola in qualche decina di secondi.
  • Linux, Oracle: il container Oracle dichiara il listener pronto mentre il primo avvio sta ancora applicando la password dell'utente system. L'installer usciva in errore su ORA-01017; ora attende che le credenziali diventino valide, e se non lo diventano lo dice in chiaro invece di lasciare che l'errore ricompaia più avanti travestito da altro.

📚 Documentazione

  • Pattern "Framework component + Custom data": una sezione nuova spiega che su Oracle, quando aprite voi la connessione con DataSQLConnection, dovete portare la sessione sullo schema (ALTER SESSION SET CURRENT_SCHEMA) oppure qualificare le tabelle — altrimenti la prima query risponde ORA-00942 anche se la tabella esiste. Sugli altri motori non serve, perché il database sta nella stringa di connessione.
  • Getting started: la strada VS Code (file di workspace, avvio con F5, launcher Fullstack) ora è nel testo della pagina e non solo dentro un blocco di codice.
  • FIRST_STEPS del pacchetto (inglese, francese, spagnolo, tedesco): aggiunta la sezione su come aprire il progetto in VS Code e quale script npm serve il frontend. Prima c'era solo nella versione italiana.
  • README del kit sorgenti Linux: aggiunta la sezione sulla rinomina del progetto, che finora era documentata solo per Windows.

📦 Pacchetti aggiornati

Package Da 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

🔧 Aggiornamenti operativi raccomandati

  1. Nessuna modifica di configurazione: le chiavi di appsettings.json non cambiano.
  2. Su installazioni PostgreSQL e Oracle già in esercizio, gli indici mancanti vengono creati al primo avvio con la 1.7.10: il primo avvio può durare qualche secondo in più, una volta sola.
  3. Se avete report scaffoldati su MySQL, PostgreSQL o Oracle che stampavano vuoto, riapriteli: non serve rigenerarli, la query viene riscritta al momento del render.
  4. Se un vostro controller apre connessioni proprie su Oracle, verificate che porti la sessione sullo schema dei dati o che qualifichi le tabelle: vedi la nota nella pagina dei pattern.

v1.7.9

Torna all'indice

Versione precedente pubblicata: 1.7.8 (18 settembre 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


Una versione corta e mirata: l'indicatore di caricamento diceva il falso. Su una route lenta la pagina restava vuota per tutta la durata della query, e quando qualcosa compariva l'indicatore si era già spento a metà strada. Chi provava il prodotto su una tabella grande vedeva una schermata bianca e concludeva che fosse bloccata.


⏳ La griglia compare subito, e l'attesa si vede

Il difetto era doppio, e le due parti si nascondevano a vicenda.

La griglia non esisteva ancora. La tabella — e con lei l'indicatore di caricamento, che è un suo sovrapposto — veniva costruita solo quando arrivavano i dati: il componente riceveva i metadati insieme al risultato della query, non prima. Su una route lenta questo voleva dire nessuna intestazione, nessuna barra dei comandi, nessun segnale di attesa: solo il titolo della pagina, per tutti i secondi della query. Ora i metadati vengono pubblicati prima di lanciare la lettura dei dati: la griglia si monta vuota e l'indicatore gira per tutta l'attesa. Misurato su una route che risponde in 4 secondi: la tabella è a schermo dopo 330 ms invece di 4.300.

L'indicatore si spegneva a metà. Ogni chiamata al server accendeva e spegneva lo stato "occupato" senza contare quante operazioni fossero in corso. Aprendo una route con colonne lookup, il framework lancia in parallelo una dozzina di letture di metadata insieme alla query dei dati: la prima che rispondeva — dopo mezzo secondo — spegneva l'indicatore di tutti, mentre la query vera continuava per altri tre secondi.

Ora le operazioni in volo sono contate, e lo stato torna libero solo quando finisce l'ultima. Sulla stessa route l'indicatore copre l'intera attesa invece di 600 millisecondi.

La correzione è stata verificata su tutti gli archetipi — list, map, scheduler, chart, carousel, kanban, timeline, tree, spreadsheet — misurando per ciascuno il momento in cui l'indicatore si accende, quello in cui si spegne e quello in cui i dati compaiono: in nessuno l'indicatore si spegne prima dei dati.

Un effetto da conoscere: su route con molte colonne lookup l'indicatore ora resta acceso qualche secondo dopo che le righe sono leggibili, perché quelle letture di metadata proseguono davvero in sottofondo. Prima spariva prima, ma mentendo.

🧩 Il suggeritore del props bag accende davvero il flag

Nel pannello Suggerisci md_props_bag dell'editor dei metadati, spuntare una voce booleana — per esempio archetypes.list.advancedFilter, quella che sostituisce i filtri sulle colonne con la barra filtri — inseriva nel JSON "advancedFilter": false. La spunta creava la chiave ma ci copiava il valore di esempio, che per quei flag è false: bisognava accorgersene e correggere a mano.

Ora una voce booleana spuntata entra a true. Chi non vuole il flag semplicemente non lo spunta: il valore predefinito a runtime è già false. Le voci non booleane continuano a portare il valore di esempio, che lì serve come traccia da compilare. Vale per entrambi i suggeritori, quello della tabella e quello della colonna.

📦 Pacchetti aggiornati

Package Da 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

🔧 Aggiornamenti operativi raccomandati

  1. Nessuna modifica di configurazione: le chiavi di appsettings.json non cambiano.
  2. Aggiornata la libreria npm, ricostruire il frontend: entrambe le correzioni vivono nei componenti, non nei metadata.
  3. Se la vostra applicazione legge lo stato "occupato" del framework per pilotare una propria interfaccia, verificatela: ora quello stato resta attivo finché non finisce l'ultima operazione in volo, quindi dura più a lungo di prima. È il comportamento corretto, ma è un cambiamento osservabile.
  4. Se un vostro codice spegneva lo stato "occupato" scrivendoci direttamente, passate ai metodi beginBusy / endBusy del toolbox, oppure a resetBusy se si tratta di un percorso di recupero da errore: una scrittura diretta spegne l'indicatore anche alle operazioni degli altri.

v1.7.8

Torna all'indice

Versione precedente pubblicata: 1.7.7 (17 settembre 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


Una versione nata usando il prodotto invece che leggendolo: un gesto che mancava nelle liste, un esempio che esisteva su tre database su quattro, testi che restavano in italiano su installazioni che italiane non erano, e pagine di documentazione che descrivevano schermate diverse da quelle vere.


🖱️ Doppio clic su una riga: si apre la modifica

Fino a ieri il form di modifica di un record si apriva solo dalla voce Modifica del menu azioni della riga. Ora lo apre anche il doppio clic sulla riga.

Non è una scorciatoia parallela che riscrive la stessa logica: il framework risale dalla riga colpita al suo menu azioni e ne esegue quello stesso comando. Quindi valgono gli stessi permessi (md_editable) e la stessa regola condizionale valutata su quel record (md_conditional_update_rule): dove la matita non c'è o è disabilitata, il doppio clic non fa niente. È una garanzia strutturale, non una promessa: se domani cambiano le regole di chi può modificare, cambiano per entrambi insieme.

Il gesto viene ignorato quando è rivolto a qualcos'altro: doppio clic su un pulsante, un link o un campo di testo (stai usando quel controllo, o stai selezionando del testo), oppure riga già aperta in modifica inline.

Vale anche sul layout mobile a card, dove la lista riconosce due tocchi ravvicinati sulla stessa card. Serviva perché quando il gesto nasce da un tocco il browser non consegna sempre l'evento di doppio clic: due tap restano due clic separati.

🗓️ Il tutorial su SQL Server ha la pagina Timeline / Gantt

La documentazione descrive l'archetype timeline/gantt e il database del tutorial porta già i dati di esempio, ma su SQL Server mancavano la route e la voce di menu che li aprono: c'erano solo su MySQL, PostgreSQL e Oracle. Chi installava il tutorial sul motore predefinito non aveva modo di vedere quella vista, e la pagina di documentazione restava non verificabile.

Il tutorial SQL Server ora ha Esempi → Timeline (Gantt): nove attività su due progetti, con dipendenze fra attività, milestone, avanzamento e raggruppamento per progetto. È un esempio completo e funzionante di md_props_bag.archetypes.timeline da cui copiare la configurazione, comprese le due parti che si sbagliano più spesso — i predecessori su colonna multiselect con tabella ponte auto-referenziale, e il raggruppamento su lookup invece che su testo libero.

🌍 Testi che restavano in italiano

  • Chatbot RAG. Mentre il motore si avvia, la chat risponde che non è ancora pronta. Quel messaggio era scritto a mano in italiano nel codice e arrivava tale e quale a un'installazione inglese, francese, spagnola o tedesca. Ora è una chiave tradotta in cinque lingue. Non parla nemmeno più di "download dei modelli": da quando l'installazione li prescarica, l'attesa è il caricamento in memoria, non lo scaricamento — il messaggio diceva una cosa che non stava succedendo.
  • Workflow designer. Sei comandi del menu (Riapri, Nuovo grafo, Salva grafo, Elimina, Re-layout automatico, Apri runner in nuova tab) erano letterali italiani nel codice: su un'installazione in un'altra lingua il menu usciva metà tradotto e metà no.
  • Avviso della mappa senza chiave Google. Esisteva in due lingue e solo nei pacchetti SQL Server; sugli altri motori al posto del messaggio compariva la chiave grezza. Ora sono cinque lingue su tutti e quattro i motori.

🧹 Tutorial più pulito

Dal menu del tutorial spariscono le venti voci Cline Prompt Tests, residui di prove interne che non avevano motivo di essere in un database di esempio.

📚 Documentazione

Le pagine qui sotto descrivevano il prodotto in modo impreciso. Non sono ritocchi di forma: erano istruzioni che portavano fuori strada.

  • Primo avvio. Il wizard non era descritto affatto. Ora la guida introduttiva spiega le due modalità di setup (DB esistente e Tutorial WideWorldImporters, la seconda presente solo se il pacchetto porta con sé il tutorial), il campo DataSQLConnection e il pulsante di test da cui dipende tutto il resto — finché non lo premi, l'elenco dei database resta disabilitato —, l'utente admin iniziale, e quanto dura il provisioning: 30 s – 2 min in modalità tutorial, 1–4 min su un database esistente con lo scaffold automatico attivo.
  • Non esiste una password predefinita. La stessa pagina dichiarava admin / admin come credenziali dopo il primo avvio. È falso: la password è quella scelta nel wizard, e non ce n'è un'altra.
  • Licenza. La procedura diceva di scrivere i valori nel file di configurazione e riavviare il backend, e non menzionava che l'interfaccia esiste. Incollando la licenza da Amministrazione → Editor AppSettings, sezione License, il backend ricarica da sé la validazione e la licenza vale dalla richiesta successiva. Il riavvio serve solo nell'altro caso, quando i valori vengono scritti a mano nel file.
  • Scaffolding iniziale. Non diceva che nei pacchetti tutorial non c'è niente da scaffoldare: il database dei metadati arriva già popolato, e la casella che registra le tabelle esiste soltanto in modalità DB esistente.
  • List Grid. Nuova sezione con i pulsanti che la toolbar mostra davvero all'apertura di una route, e la condizione di ciascuno. La pagina nominava solo comandi opzionali o transitori — quelli della finestra di avanzamento di import/export, che esiste solo mentre un import o un export è in corso — e nessuno di quelli che si vedono appena si apre una lista.
  • Designer. L'elenco della palette nominava cinque voci, di cui tre inesistenti con quel nome, e taceva sulle altre. Ora ci sono i tre gruppi reali e i nomi veri dei componenti.
  • Modalità Trial. Un'installazione senza licenza limita ogni query a 20 record: una lista che dichiara "20 di 20" su una tabella da migliaia di righe sta girando in Trial, non è un guasto. Ora è scritto dove serve, cioè nella pagina dei download e nella guida introduttiva, non solo nel listino.

📦 Pacchetti aggiornati

Package Da 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

🔧 Aggiornamenti operativi raccomandati

  1. Nessuna modifica di configurazione: le chiavi di appsettings.json non cambiano.
  2. Aggiornata la libreria npm, ricostruire il frontend: il doppio clic vive nel componente lista, non nei metadata.
  3. Se la vostra applicazione aveva già un comportamento legato al doppio clic su una riga di lista, verificatelo: ora il framework apre il form di modifica sullo stesso gesto.
  4. La voce Timeline (Gantt) compare nelle installazioni tutorial nuove su SQL Server. Un'installazione già fatta non va rifatta: i dati di esempio ci sono già, mancano solo route e voce di menu, che si aggiungono dall'interfaccia.

v1.7.7

Torna all'indice

Versione precedente pubblicata: 1.7.6 (16 settembre 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


Questa versione corregge cinque difetti trovati installando il framework su macchine pulite, uno per ogni combinazione di sistema operativo e database. Il più importante riguarda Oracle e PostgreSQL, dove una pagina generata dal framework poteva non aprirsi a seconda di come ne scrivevi il nome nell'indirizzo. Gli altri riguardano Oracle XE e il pacchetto sorgenti per Linux.


🔤 Le route ora si aprono a prescindere dalle maiuscole

Il nome di una route nasce minuscolo: una tabella Supplier diventa la route supplier. Chi apriva /Supplier/List — cioè scriveva il nome della propria tabella — la trovava su SQL Server e MySQL, dove il confronto del motore ignora le maiuscole, ma non su Oracle e PostgreSQL, che rispondevano Route 'Supplier' non trovata nei metadata.

Lo stesso indirizzo, lo stesso scaffolding, un esito diverso a seconda del database sotto. Su Oracle l'effetto si moltiplicava: la lista generata dallo scaffolding iniziale, la pagina creata dall'interfaccia, i componenti che montano un widget del framework e le API dei metadata sbagliavano tutti per la stessa ragione, e sembravano quattro guasti distinti.

La risoluzione di una route ora ripiega su un confronto che ignora le maiuscole quando quello esatto fallisce: il percorso normale non cambia e i nomi fisici di tabelle e colonne restano quelli scritti nello schema.

Se in un'installazione esistessero due route che si distinguono solo per il maiuscolo, il framework non può sceglierne una: adesso lo dice con un messaggio esplicito (HTTP 409, errors.metadata.route.ambiguous_case) che elenca le route in conflitto, invece di rispondere "non trovata".

🗄️ Oracle XE: lo scaffolding dall'interfaccia

Generare una pagina da una tabella dal menu di amministrazione rispondeva 500 su Oracle XE:

ORA-00932: inconsistent datatypes: expected NUMBER got BOOLEAN

Le colonne dei metadata che rappresentano un interruttore sono numeriche, ma il provider vi scriveva un booleano: un tipo che in SQL Oracle esiste solo dalla 23ai. Su 23ai la conversione implicita nascondeva il problema, su XE — l'edizione più diffusa — il server rifiutava l'inserimento e lo scaffolding si fermava. Ora vengono scritti 1 e 0, che vanno bene su ogni versione.

🐧 Pacchetto sorgenti per Linux

  • Il chatbot RAG era spento. Il pacchetto dichiarava il motore .NET attivo nella propria configurazione ma non lo distribuiva: /api/Rag/Health rispondeva per sempre not-initialized con WuicRagEngine.dll non trovato. Il motore c'è ora anche qui, come già nel pacchetto Windows.
  • I modelli si scaricano durante l'installazione. Alla prima domanda il chatbot doveva scaricare 4,4 GB fra modelli e indice, e per qualche minuto rispondeva solo "sto completando l'inizializzazione". Ora install.sh li prende mentre installa, in parallelo al resto: la prima domanda risponde subito. Il download si salta con --skip-prefetch, e in quel caso resta il comportamento di prima. Il passo non interrompe mai l'installazione: se la rete non collabora, il chatbot se li prenderà al primo uso.
  • I file per gli assistenti di codice non venivano generati. Su Linux il primo avvio non scriveva AGENTS.md, CLAUDE.md, .mcp.json né le skill: il modello che li produce non era nel pacchetto, e la generazione veniva saltata in silenzio. Ora ci sono in entrambi i pacchetti Linux.
  • Rinominare il progetto. rename-project.sh cercava il progetto solo nella propria cartella e in quella superiore, mentre nel pacchetto sta un livello più sotto: lanciato come indicato usciva con non trovo WuicTest.csproj. Ora cerca anche lì e, se proprio non trova nulla, elenca i percorsi che ha provato.
  • Il pacchetto non porta più i resti del vecchio motore RAG in Python (codebase_embeddings/, rag-setup.ps1, rag-start.ps1), sostituito dal motore .NET a giugno.

📦 Pacchetti aggiornati

Package Da 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

🔧 Aggiornamenti operativi raccomandati

  1. Su Oracle e PostgreSQL: se avevate segnato come non funzionanti delle pagine generate dallo scaffolding, riprovatele dopo l'aggiornamento — è probabile che fosse questo.
  2. Su Oracle XE: lo scaffolding dall'interfaccia è utilizzabile da questa versione; le tabelle esposte prima non vanno rifatte.
  3. Chi installa da sorgenti su Linux metta in conto 4,4 GB di download in più durante l'installazione, oppure aggiunga --skip-prefetch per rimandarli al primo uso del chatbot.
  4. Nessuna modifica di configurazione è richiesta: le chiavi di appsettings.json non cambiano.

v1.7.6

Torna all'indice

Versione precedente pubblicata: 1.7.4 (16 settembre 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


Questa versione esce lo stesso giorno della 1.7.4 e ne corregge tre cose trovate rieseguendo l'installazione su macchine pulite subito dopo la pubblicazione. La più importante riguarda Oracle: il primo avvio su un database già esistente arrivava in fondo dichiarando successo, ma lasciava l'applicazione senza le tabelle dell'utente. Le altre due riguardano il pacchetto Linux.


🗄️ Oracle: il primo avvio su un database esistente

Chi sceglieva la modalità "database esistente", indicava il proprio schema e chiedeva lo scaffolding automatico, arrivava al login con il menu senza nessuna delle proprie tabelle, e senza nessun errore a schermo. Il motivo era scritto solo in firstrun-scaffold-error.log, accanto all'applicazione:

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

Su Oracle il "database dei dati" è lo schema, e il framework costruiva la connessione mettendo come utente lo schema scelto ma tenendo la password scritta nel wizard, che è quella di chi sta configurando: una credenziale che nessuno ha digitato e che in generale non esiste. Lo scaffolding, che usava quella stessa connessione, non riusciva ad autenticarsi; l'errore finiva in un blocco tollerante e il wizard dichiarava comunque successo.

Ora la connessione conserva l'utente indicato nel wizard — come già avviene su PostgreSQL, dove scegliere il database non cambia l'identità — e lo schema di lavoro viene impostato sulla sessione con ALTER SESSION SET CURRENT_SCHEMA, che è il modo previsto da Oracle per operare in uno schema senza esserne l'utente. Le installazioni in cui chi configura è lo schema (fra cui tutte quelle del tutorial) non cambiano comportamento.

Effetto pratico: dal wizard allo scaffolding al login, le tabelle compaiono nel menu e le liste mostrano i dati.

🐧 Pacchetto Linux

  • La chat RAG era spenta su tutti e quattro i motori. Il motore .NET viene installato correttamente, ma i profili appsettings.linux.*.json non contenevano nessuna chiave rag-*: il backend ripiegava su un server Python che il pacchetto Linux non distribuisce, e ogni richiesta rispondeva 503. Le chiavi ci sono ora in tutti e quattro i profili.
  • I modelli di report non venivano distribuiti. La cartella Reports/ non finiva nel tarball, quindi su Linux nessuna rotta mostrava la voce Report. Ora è inclusa.
  • Rinominare il progetto su Linux. Il pacchetto sorgenti dava un solo modo di fare proprio il template, ed era uno script PowerShell: su una Ubuntu pulita pwsh non c'e', non lo installa l'installer e i prerequisiti non lo chiedono. Accanto a rename-project.ps1 c'e' ora rename-project.sh, che fa gli stessi passi — rinomina .csproj, controller e workspace di VS Code, aggiorna i contenuti, allinea il nome in package.json — con --name, --in-place e --backend-port. Di default clona in una cartella nuova e lascia intatta quella di partenza.
  • Lo smoke test bocciava installazioni sane. Al termine dell'installazione lo script tentava un login amministrativo anche quando l'applicazione resta in primo avvio — condizione normale su Oracle dalla 1.7.4, dove utenti e metadati li crea il wizard. L'installazione si chiudeva con "Install completed but smoke tests failed" pur essendo a posto. Ora il controllo viene saltato con un avviso che spiega come completarlo.

🔧 Aggiornamenti operativi raccomandati

  1. Chi ha scaricato il tarball Linux della 1.7.4 nelle prime ore: scaricatelo di nuovo. La prima copia pubblicata conteneva assembly di versioni disallineate e il servizio non si avviava (Could not load file or assembly 'WuicOData'); la copia corrente è corretta, e questa versione la sostituisce comunque.
  2. Su Oracle, un'installazione già completata con la 1.7.4 e rimasta senza tabelle nel menu non si ripara da sola: conviene rifare il primo avvio su un database dei metadati vuoto.
  3. Nessuna modifica di configurazione è richiesta: le chiavi di appsettings.json non cambiano.

v1.7.4

Torna all'indice

Versione precedente pubblicata: 1.7.3 (14 settembre 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


Questa versione è quasi tutta Oracle. Ripetendo installazione e primo avvio su macchine pulite — su Windows con IIS e su Linux con nginx — sono emersi quattro punti in cui il percorso si interrompeva prima di arrivare a un'applicazione funzionante: il caricamento dei dati del tutorial, la creazione degli utenti, la chat RAG e, su Linux, la generazione stessa della password del database. Nessuno dei quattro si vedeva sugli altri motori.

Il resto sono correzioni al primo avvio che valgono per tutti i motori, più due alla diagnostica degli errori SQL.


🗄️ Oracle: dati del tutorial e primo avvio

Il caricamento dei dati iniziali su Oracle riusciva su 472 istruzioni su 18.141. Le altre fallivano con ORA-01843: not a valid month, perché gli script di primo avvio contengono date e numeri nella convenzione italiana mentre la sessione Oracle usava le impostazioni predefinite del server. L'esecuzione degli script imposta ora NLS_DATE_LANGUAGE e NLS_NUMERIC_CHARACTERS prima del primo statement: 17.889 istruzioni su 17.889, su Windows e su Linux indifferentemente. Se avete provato Oracle con la 1.7.3 e avete trovato le tabelle del tutorial semivuote, è questo.

Sempre su Oracle, tre correzioni all'installazione Linux:

  • la password generata per il database poteva contenere il carattere @, che rompe la stringa di connessione easy-connect di sqlplus: l'installazione si fermava con ORA-12262 in circa un caso su tre, e il carattere colpevole non compariva in nessun messaggio;
  • la creazione dei database del tutorial e quella degli utenti di autenticazione sono ora affidate al wizard di primo avvio, che è il percorso che ogni altra piattaforma già seguiva. Gli script di installazione preparavano invece uno schema che il wizard avrebbe comunque rifatto;
  • appsettings.linux.oracle.json viene consegnato con firstRun attivo, così la prima apertura del browser porta al wizard invece che a un'applicazione senza metadati.

💬 Chat RAG su Oracle

La chat rispondeva 500 alla prima domanda, con ORA-00933: SQL command not properly ended. Le query della chat terminano con il punto e virgola — corretto in SQL*Plus e negli altri motori, ma per il driver Oracle fa parte del testo dello statement. Il punto e virgola finale viene ora rimosso prima dell'esecuzione, con l'eccezione dei blocchi PL/SQL, dove END; è legittimo.

🚀 Primo avvio (tutti i motori)

  • Il wizard si ferma con un messaggio se il database dati indicato non esiste fra quelli letti dal server. Prima proseguiva: l'installazione si completava e il menu si apriva, ma ogni griglia restava vuota perché i metadati puntavano a un database inesistente. Il messaggio è tradotto nelle 5 lingue.
  • Su Linux appsettings.json nella cartella dell'applicazione è un collegamento simbolico a /etc/wuiccore/appsettings.json. La scrittura atomica della configurazione risolve ora il collegamento prima di scrivere: senza, il wizard scriveva un file nuovo al posto del link, l'applicazione continuava a leggere quello vecchio e il primo avvio non si chiudeva mai.
  • I file di configurazione scritti dall'installer restano scrivibili dal servizio (modo 0660, gruppo del servizio). Il wizard falliva il salvataggio finale su un'installazione appena creata.

🔎 Diagnostica degli errori SQL

L'envelope di errore che il dialogo mostra a un amministratore diceva due cose non vere:

  • sqlProvider riportava mssql per qualunque errore che non fosse MySQL — quindi anche per le eccezioni Oracle e PostgreSQL. Ora il valore deriva dal tipo dell'eccezione, e i provider non riconosciuti dichiarano unknown invece di un nome sbagliato;
  • query restava vuota sui percorsi che usano ADO.NET direttamente invece del livello Dapper (fra questi la chat RAG), anche con la diagnostica attiva. La cattura del comando ora copre entrambi i percorsi, con lo stesso mascheramento dei parametri sensibili.

🐛 Bug fix degni di nota

  • Elenco dei modelli LLM senza chiave API: l'endpoint contattava il provider anche quando la chiave non era configurata, e la pagina delle impostazioni restava in attesa della risposta di rete. Senza chiave viene ora restituito subito l'elenco curato locale.

🔧 Aggiornamenti operativi raccomandati per chi aggiorna

  1. Chi usa Oracle aggiorni a questa versione prima di rifare un'installazione: le correzioni sopra riguardano il percorso di primo avvio e non hanno effetto retroattivo su un database già popolato a metà. Su un'installazione già rovinata conviene ripartire da un database vuoto.
  2. Su Linux verificare, dopo l'aggiornamento, che appsettings.json nella cartella dell'applicazione sia ancora il collegamento a /etc/wuiccore/appsettings.json e non un file autonomo lasciato da un primo avvio della 1.7.3.
  3. Nessuna modifica di configurazione è richiesta: le chiavi di appsettings.json non cambiano.

v1.7.3

Torna all'indice

Versione precedente pubblicata: 1.7.0 (14 agosto 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


Il fronte nuovo è l'installazione in un comando su Windows. Il resto sono correzioni all'installazione e al primo avvio, trovate rieseguendo l'intera procedura su macchine pulite, su Windows e su Linux, con SQL Server, MySQL e PostgreSQL. Due di queste impedivano di arrivare al wizard: su Linux con MySQL il caricamento del database si fermava alla prima istruzione, e lo scaffolding automatico del wizard non generava i metadati, lasciando l'applicazione con il menu vuoto.


💾 Installazione su Windows in un comando

Da una finestra PowerShell:

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

Lo script fa da solo tutto quello che prima era una lista di passaggi manuali: verifica il runtime ASP.NET Core 10 e lo installa se manca, cerca un'istanza SQL Server raggiungibile e, se non ne trova, installa SQL Server 2022 Express, scarica l'ultimo pacchetto pubblicato, lo estrae e apre il browser sul wizard di primo avvio. È il gemello per Windows di install.sh, ed è compatibile con Windows PowerShell 5.1, quindi non richiede di installare PowerShell 7.

L'applicazione viene pubblicata in IIS: lo script abilita le funzionalità IIS se mancano, installa l'ASP.NET Core Hosting Bundle, crea l'application pool e il sito sulla porta scelta, e concede all'identità del pool i permessi sulla cartella e il login su SQL Server. Serve un'elevazione: lo script la richiede una volta sola, con il normale prompt di Windows.

Con -Kestrel non viene toccato nulla di IIS e l'applicazione gira in una finestra di console, riavviabile con start-wuic.cmd. È la scelta giusta quando non si hanno diritti di amministratore, quando IIS è disabilitato da criteri aziendali, o per una prova usa e getta.

Le opzioni più usate: -WithTutorial scarica il pacchetto con il database dimostrativo WideWorldImporters, -Port cambia la porta, -ListenAll mette in ascolto tutte le interfacce invece della sola localhost, -SqlServer indica un'istanza già esistente, -Dbms mysql|postgres installa e configura un motore diverso da SQL Server.

Requisito da conoscere prima di scegliere il pacchetto: la variante con il tutorial in formato .bak contiene un backup nativo di SQL Server 2022 e richiede quindi SQL Server 2022 o superiore, perché il ripristino non è compatibile all'indietro. Su SQL Server 2019 va usata la variante con gli script SQL, che è supportata da 2019 in poi; l'installer se ne accorge da solo e sceglie la variante giusta per l'istanza che trova.

Rispetto alla prima versione dello script sono state corrette tre cose che si incontravano subito:

  • con -Dbms mysql o -Dbms postgres l'installer scriveva i propri segreti nella cartella di installazione e poi rifiutava quella stessa cartella come "non vuota", uscendo con codice 2 dodici secondi dopo averla riempita lui; l'estrazione, inoltre, cancellava la password di root appena generata. Ora i file dell'installer non contano nel controllo e i segreti sopravvivono all'estrazione;
  • rieseguire il comando su una macchina dove l'installazione era già presente non finisce più in un vicolo cieco;
  • con -Dbms postgres il tutorial richiede l'estensione PostGIS, che su Windows non viene posata insieme a PostgreSQL: il caricamento moriva a metà con extension "postgis" is not available, un errore che sembrava un difetto degli script SQL. L'installer ora verifica le estensioni disponibili e, se manca, installa il bundle per la versione di PostgreSQL che ha trovato.

L'installer ora racconta cosa sta facendo anche durante le fasi lunghe: l'installazione di SQL Server Express e npm install possono restare minuti senza stampare una riga, e finora la finestra sembrava bloccata. Ogni dieci secondi di silenzio compare da quanto sta lavorando e qual è stata l'ultima riga utile.

🐧 Installazione su Linux

Tre correzioni, tutte sulla strada che porta al primo avvio.

Il framework non partiva sui pacchetti offuscati. La protezione anti-tamper applicata in fase di rilascio impediva l'avvio su Linux. È stata rimossa: l'offuscamento dei simboli resta, la protezione che bloccava l'esecuzione no.

Il caricamento del database MySQL si fermava alla prima istruzione. Lo script di bootstrap dava per scontato un database già selezionato, mentre i dump non contengono più la direttiva USE, e il caricamento moriva con ERROR 1046 (3D000): No database selected. Chi ha installato con MySQL usando il pacchetto precedente incontra ancora questo errore: è la ragione principale per cui questa release va installata.

Il profilo di configurazione non veniva copiato nel progetto. L'appsettings.json del pacchetto sorgenti punta a un'istanza SQL Server nominata, che su Linux non esiste: seguendo la documentazione, dotnet run moriva dopo quarantacinque secondi con error: 26 - Error Locating Server/Instance Specified e il wizard non compariva mai. Ora le chiavi che dipendono dal motore vengono copiate automaticamente nel progetto.

Documentate le release Ubuntu effettivamente supportate: 22.04 e 24.04 LTS. Su 24.04 SQL Server richiede un avvio in compatibilità; la 26.04 non è supportata da Microsoft per SQL Server.

🌍 Wizard di primo avvio in cinque lingue

Il wizard di primo avvio parlava solo italiano, indipendentemente dal browser. Ora si presenta nella lingua del browser fra le cinque gestite (italiano, inglese, francese, spagnolo, tedesco) e, scegliendo la lingua dell'utente amministratore, l'intera pagina passa a quella lingua immediatamente. Per una lingua non gestita il ripiego è l'inglese.

Sono tradotti anche i messaggi che il wizard produce durante la configurazione: esito del test di connessione, errori di validazione della stringa di connessione e conferma di ricreazione del database dei metadati.

🐛 Bug fix degni di nota

  • Lo scaffolding automatico del wizard non generava i metadati. Al primo avvio, con la casella "Esegui scaffold automatico delle tabelle del DB selezionato" spuntata, l'applicazione partiva con il menu vuoto e nessuna route: lo scaffolding girava contro una connessione diversa da quella appena scelta nel wizard. Ora le connessioni scelte nel wizard vengono usate davvero, e al primo accesso il menu contiene le tabelle del proprio schema.
  • Modifica o cancellazione senza chiave: ora rifiutata. Se il payload di un aggiornamento o di una cancellazione non conteneva nessuna colonna riconosciuta dai metadati, la clausola WHERE generata risultava vuota e l'istruzione colpiva tutte le righe della tabella, restituendo per giunta un esito positivo. È il caso di una chiave primaria inviata con maiuscole e minuscole diverse da quelle dello schema. Ora l'operazione viene respinta con HTTP 400 e il codice errors.metaservice.crud.missing_key_predicate, e il messaggio elenca le chiavi ricevute per far capire subito la causa.
  • Senza chiave Google Maps l'applicazione restava bloccata. La mancanza della chiave in GoogleMaps:ApiKey produceva un errore JavaScript che risaliva fino al dialogo di errore applicativo e rendeva inutilizzabile l'intera interfaccia, non solo la mappa. Ora il componente mappa mostra un avviso non invasivo dentro la propria vista e il resto dell'applicazione continua a funzionare.
  • Scene 3D nel piano Professional. Le route del visualizzatore e del designer Scene 3D dichiarano la funzione scene3d-designer come richiesta, ma nessun piano la includeva: su qualunque installazione Professional il controllo rimandava alla pagina di accesso negato. La funzione è ora inclusa nel piano Professional.
  • Script di primo avvio più leggeri di due ordini di grandezza. Gli script di primo avvio contenevano i dati delle tabelle di log, delle conversazioni del chatbot e dei contenuti di dashboard: log di errore e chat di sviluppo spediti dentro ogni pacchetto. Ora quelle tabelle viaggiano con la sola struttura. Lo script dei metadati di primo avvio passa da 468 MB a 3,7 MB nel profilo minimale e a 14 MB in quello con il tutorial (i dati dimostrativi WideWorldImporters restano a parte, e pesano quanto prima).
  • Documentazione del chatbot allineata al motore reale. Le pagine di installazione indicavano ancora Python e un servizio separato per il chatbot RAG. Il motore è nativo .NET/ONNX e gira nel processo dell'applicazione dalla 1.3.0: non serve Python, non serve installare nulla a parte. È stata corretta anche la dimensione dei modelli scaricati al primo uso, che è di circa 4,5 GB.
  • Quattro pagine di documentazione vuote (chatbot RAG, licenze, liste di distribuzione, tabelle pivot) sono state scritte, in tutte e cinque le lingue.

🔧 Aggiornamenti operativi raccomandati per chi aggiorna

  1. Chi ha installato con MySQL su Linux partendo dal pacchetto precedente deve reinstallare con questa versione: il caricamento del database si interrompeva e l'installazione non era completa.
  2. Verificare le integrazioni che scrivono tramite le API CRUD: una chiamata che finora aggiornava l'intera tabella senza accorgersene ora riceve HTTP 400. Il messaggio di errore elenca le chiavi ricevute, e la correzione è quasi sempre allineare il nome della chiave primaria alle maiuscole e minuscole dello schema.
  3. Se si usa Scene 3D con una licenza Professional emessa prima di questa versione, richiedere una licenza aggiornata: la funzione scene3d-designer va inclusa nel piano.
  4. Per una nuova installazione su Windows, usare il comando in un solo passaggio invece della procedura manuale. Su un'istanza SQL Server 2019 scegliere la variante del tutorial con gli script SQL.
  5. Se si usa il componente mappa, configurare GoogleMaps:ApiKey in appsettings.json: senza chiave la mappa mostra un avviso, ma il resto dell'applicazione resta utilizzabile.

v1.7.1

Torna all'indice

Versione precedente pubblicata: 1.7.0 (15 agosto 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


Una release di consolidamento, con un fronte nuovo — l'installazione su Windows in un comando — e una serie di correzioni nate installando il prodotto da zero su macchine pulite, seguendo la documentazione alla lettera. Diverse riguardano Linux, dove alcune cose non funzionavano affatto: il chatbot mancava dal pacchetto, i report non si aprivano, e chi partiva dai sorgenti non riusciva ad avviare l'applicazione.


💾 Installazione su Windows in un comando

Da una finestra PowerShell:

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

Lo script fa da solo tutto quello che prima era una lista di passaggi manuali: verifica il runtime ASP.NET Core 10 e lo installa se manca, cerca un'istanza SQL Server raggiungibile e, se non ne trova, installa SQL Server Express, scarica l'ultimo pacchetto pubblicato, lo estrae e apre il browser sul wizard di primo avvio. È il gemello per Windows di install.sh, ed è compatibile con Windows PowerShell 5.1, quindi non richiede di installare PowerShell 7.

L'applicazione viene pubblicata in IIS: lo script abilita le funzionalità IIS se mancano, installa l'ASP.NET Core Hosting Bundle, crea l'application pool e il sito sulla porta scelta, e concede all'identità del pool i permessi sulla cartella e il login su SQL Server. Serve un'elevazione: lo script la richiede una volta sola, con il normale prompt di Windows.

Con -Kestrel non viene toccato nulla di IIS e l'applicazione gira in una finestra di console, riavviabile con start-wuic.cmd. È la scelta giusta quando non si hanno diritti di amministratore, quando IIS è disabilitato da criteri aziendali, o per una prova usa e getta.

Le opzioni più usate: -WithTutorial scarica il pacchetto con il database dimostrativo WideWorldImporters, -Port cambia la porta, -ListenAll mette in ascolto tutte le interfacce invece della sola localhost, -SqlServer indica un'istanza già esistente, -Dbms sceglie un motore diverso da SQL Server.

Requisito da conoscere prima di scegliere il pacchetto: la variante con il tutorial in formato .bak contiene un backup nativo di SQL Server 2022 e richiede quindi SQL Server 2022 o superiore, perché il ripristino non è compatibile all'indietro. Su SQL Server 2019 va usata la variante con gli script SQL, che è supportata da 2019 in poi; l'installer se ne accorge da solo e sceglie la variante giusta per l'istanza che trova.

Su Windows Server il motore di database va installato prima. Il comando si procura i componenti mancanti tramite winget, che su Windows Server non è presente: senza un'istanza già raggiungibile l'installazione si ferma e lo dice. Vale per tutti i motori, non solo SQL Server.

🐧 Linux: il pacchetto è finalmente completo

Chi installa su Linux trovava tre cose rotte, tutte corrette in questa versione.

Il chatbot RAG non c'era. Il motore di ricerca semantica .NET/ONNX veniva incluso solo nei pacchetti Windows: ogni tarball Linux usciva senza, e GET /api/Rag/Health rispondeva 503 rag-server-unreachable per sempre. Ora il tarball lo contiene, con le librerie native linux-x64 complete: su una macchina con CUDA 12 e cuDNN 9 va in GPU senza interventi manuali, altrimenti ricade su CPU.

Il motore semantico non trovava le proprie librerie native. Le cercava in PATH, separate da ;, che è la convenzione di Windows; su Linux il caricatore usa LD_LIBRARY_PATH e i due punti.

I report non si aprivano. Il percorso della cache veniva costruito con le barre rovesciate di Windows e con uno slash iniziale, quindi su Linux finiva nella radice del filesystem invece che sotto la cartella dell'applicazione. Il visualizzatore restituiva un errore che sembrava un problema di configurazione.

E per chi parte dai sorgenti: l'applicazione non si avviava affatto. Il pacchetto NuGet WuicCore conteneva una protezione anti-manomissione il cui codice di inizializzazione non è compatibile con il runtime .NET su Linux, e falliva prima di eseguire una sola riga dell'applicazione. Su Windows la stessa identica libreria partiva senza problemi, motivo per cui il difetto è rimasto a lungo invisibile. La protezione è stata rimossa; il resto dell'offuscamento resta invariato.

📦 Kit sorgenti: compila su una macchina pulita

Il pacchetto per sviluppatori conteneva alcune assunzioni che valevano solo sulla macchina di chi lo costruiva.

  • Il lock delle dipendenze viaggia nel pacchetto. Senza, npm install con npm 10.9.x — la versione fornita con Node.js 22 LTS, cioè quella che la documentazione stessa richiede — si interrompe risolvendo le dipendenze peer. Ora il lock è incluso, l'installazione è riproducibile e due sviluppatori ottengono lo stesso albero.
  • Le librerie 3D sono dichiarate. three, three-gpu-pathtracer, three-mesh-bvh e @dimforge/rapier3d-compat venivano importate senza comparire fra le dipendenze: sulla macchina di chi sviluppa il framework erano presenti per altre strade, su una macchina pulita la compilazione si fermava su un import irrisolto. Sono peer dependency opzionali: chi non usa le scene 3D non se le porta dietro.
  • I percorsi degli asset Angular puntavano fuori dal pacchetto e la build falliva su file inesistenti.
  • Il workspace per assistenti LLM veniva generato senza le proprie impostazioni.

🌍 Wizard di primo avvio

Il wizard parlava solo italiano, indipendentemente dal browser. Ora si presenta nella lingua del browser fra le cinque gestite (italiano, inglese, francese, spagnolo, tedesco) e, scegliendo la lingua dell'utente amministratore, l'intera pagina passa a quella lingua immediatamente. Per una lingua non gestita il ripiego è l'inglese. Sono tradotti anche i messaggi prodotti durante la configurazione: esito del test di connessione, errori di validazione della stringa di connessione e conferma di ricreazione del database dei metadati.

Lo scaffolding di un database esistente è ora attivo per impostazione predefinita. Chi indicava un proprio database e accettava i valori proposti otteneva un'applicazione senza nessuna route, con le tabelle ignorate. La modalità tutorial non è interessata.

🐛 Bug fix degni di nota

  • Modifica o cancellazione senza chiave: ora rifiutata. Se il payload di un aggiornamento o di una cancellazione non conteneva nessuna colonna riconosciuta dai metadati, la clausola WHERE generata risultava vuota e l'istruzione colpiva tutte le righe della tabella, restituendo per giunta un esito positivo. È il caso di una chiave primaria inviata con maiuscole e minuscole diverse da quelle dello schema. Ora l'operazione viene respinta con HTTP 400 e il codice errors.metaservice.crud.missing_key_predicate, e il messaggio elenca le chiavi ricevute per far capire subito la causa.
  • Mappe senza chiave Google: avviso al posto del blocco. Quando la Maps JavaScript API non è caricata — tipicamente perché la chiave non è stata configurata — il componente mostrava un dialogo modale che fermava l'intera pagina. Ora al posto della mappa compare un riquadro che spiega cosa manca, e il resto della pagina resta utilizzabile.
  • Reinstallazione su MySQL: niente più vicolo cieco. La password del motore la genera l'installer stesso; rieseguendo il comando sulla stessa macchina non riusciva a rileggerla, sondava con la password vuota e concludeva che il database non rispondeva, mentre rispondeva benissimo. Corretto anche il controllo della versione minima, che non veniva mai eseguito perché l'avviso di MySQL sulla password in chiaro finiva nell'output analizzato.
  • Scene 3D nel piano Professional. Le route del visualizzatore e del designer Scene 3D dichiarano la funzione scene3d-designer come richiesta, ma nessun piano la includeva: su qualunque installazione Professional il controllo rimandava alla pagina di accesso negato. La funzione è ora inclusa nel piano Professional.
  • Gli appsettings di esempio non contengono più una password reale.
  • Documentazione del chatbot allineata al motore reale. Le pagine di installazione indicavano ancora Python e un servizio separato per il chatbot RAG. Il motore è nativo .NET/ONNX e gira nel processo dell'applicazione dalla 1.3.0: non serve Python, non serve installare nulla a parte. È stata corretta anche la dimensione dei modelli scaricati al primo uso, che è di circa 4,5 GB.
  • Quattro pagine di documentazione vuote (chatbot RAG, licenze, liste di distribuzione, tabelle pivot) sono state scritte, in tutte e cinque le lingue.

📚 Prerequisiti corretti nella documentazione

Le pagine di avvio riportavano requisiti che non corrispondevano a quanto misurato installando su macchine pulite:

  • Node.js 22 LTS, non "20 o superiore": è la versione con cui il pacchetto è testato.
  • PowerShell 5.1 è sufficiente. Gli script inclusi girano sulla PowerShell preinstallata su Windows; PowerShell 7 è consigliata, non richiesta.
  • Su Windows Server il database va installato prima del comando di installazione.

📦 Pacchetti aggiornati

Package Da A
WuicCore (NuGet) 1.7.0 1.7.1
wuic-framework-lib (npm) 1.7.0 1.7.1

🔧 Aggiornamenti operativi raccomandati per chi aggiorna

  1. Verificare le integrazioni che scrivono tramite le API CRUD: una chiamata che finora aggiornava l'intera tabella senza accorgersene ora riceve HTTP 400. Il messaggio di errore elenca le chiavi ricevute, e la correzione è quasi sempre allineare il nome della chiave primaria alle maiuscole e minuscole dello schema.
  2. Su Linux, sostituire il pacchetto con quello di questa versione anche se l'applicazione sembra funzionare: il chatbot RAG e il visualizzatore di report non erano operativi nelle versioni precedenti.
  3. Se si usa Scene 3D con una licenza Professional emessa prima di questa versione, richiedere una licenza aggiornata: la funzione scene3d-designer va inclusa nel piano.
  4. Chi parte dal kit sorgenti può eseguire npm install senza opzioni aggiuntive: il lock incluso rende l'installazione riproducibile.
  5. Per una nuova installazione su Windows, usare il comando in un solo passaggio invece della procedura manuale. Su un'istanza SQL Server 2019 scegliere la variante del tutorial con gli script SQL; su Windows Server installare prima il motore di database.

v1.7.0

Torna all'indice

Versione precedente pubblicata: 1.5.0 (21 luglio 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


Pacchetti sostituiti il 15 agosto 2026. Gli archivi pubblicati inizialmente contenevano un appsettings.json con autoGeneratedQueryTimeout a 1: con quel valore ogni interrogazione che supera un secondo termina con un errore del server. Insieme erano rimaste alcune impostazioni dell'intestazione (logo, orientamento del menu, selettore dei temi, notifiche) lasciate da una sessione di test. Gli archivi sono stati ricostruiti e le somme di controllo aggiornate.

Se hai scaricato prima del 15 agosto: riscarica il pacchetto, oppure apri appsettings.json e riporta autoGeneratedQueryTimeout a 30, eliminando le chiavi header-logo, header-logo-position, header-menu-orientation, header-show-theme-selector, header-menu-multicolumn-submenu e header-show-notifications se non le hai impostate tu. Nessuna delle due impostazioni tocca i dati: l'installazione si corregge modificando il file e riavviando.


Tre settimane di lavoro concentrate su due fronti. Il primo è l'aspetto: arriva il Theme Builder, una pagina da cui comporre temi su misura — colori, tipografia, sfondo, densità, resa della griglia — che valgono per tutti gli utenti dell'installazione, e l'intestazione dell'applicazione è stata ridisegnata e resa configurabile. Il secondo è l'integrazione e l'osservabilità: il nuovo Webhook Hub per ricevere e inviare eventi con firma e ritentativi, e il Performance Inspector che misura fetch e render per route. Il chatbot impara ad agire su altre tre superfici dell'applicazione e a interrogare lo schema del database.


🎨 Theme Builder

Una nuova pagina sotto Amministrazione permette di comporre temi personalizzati senza toccare il codice. Ogni tema salvato compare nel selettore dei temi di tutti gli utenti dell'installazione, accanto a quelli predefiniti.

Cosa si può impostare:

  • Colore principale, da cui viene generata l'intera scala a 11 tonalità: la scala resta cliccabile, e scegliere una tonalità più scura la promuove a colore principale. Un badge indica il rapporto di contrasto WCAG raggiunto (AAA / AA / AA-large / fail).
  • Superfici chiare e scure, raggio degli angoli e densità (comoda o compatta).
  • Tipografia: famiglia di caratteri da un catalogo di font di sistema oppure stack libero, e dimensione di base che scala l'intera interfaccia.
  • Sfondo pagina: tinta unita, gradiente o immagine. Il gradiente può avere una deriva lenta opzionale, che fa oscillare l'inclinazione nel tempo; l'immagine si configura con adattamento, ripetizione, posizione e velo scuro per non compromettere la leggibilità del testo.
  • Griglia: righe alternate e riga selezionata non sono più colori fissi ma mescole fra la superficie e un accento, con due sole manopole di intensità e la possibilità di usare un accento diverso dal colore principale.
  • Modalità chiaro/scuro libera oppure imposta dal tema.

L'anteprima è live e applica il tema a tutta la pagina mentre lo si compone, senza toccare le preferenze dell'utente: uscendo, ricaricando o chiudendo il browser il proprio tema torna quello di prima.

L'export Excel segue il tema: un file esportato con un tema personalizzato attivo esce con i colori di quel tema — intestazione, righe alternate, bordi — invece dei grigi generici. Per tutte le famiglie di preset sono stati aggiunti gli stili di ripiego, così anche un tema non ancora campionato eredita l'aspetto della propria famiglia.

Il catalogo dei temi predefiniti si allarga con nuove varianti, e il tema attivo viene applicato già al primo fotogramma dopo un ricaricamento, senza il lampeggio del tema precedente.

🖥️ Intestazione ridisegnata e configurabile

L'intestazione dell'applicazione è ora un componente del framework: le installazioni la ereditano invece di mantenerne una copia. Il blocco in alto a destra è stato compattato — selettore temi, chiaro/scuro, lingua, notifiche e area utente stanno in una card che si espande al passaggio del mouse — e l'area utente mostra nome, ruolo, licenza e uscita.

Una nuova sezione Header & Menu nelle impostazioni permette di scegliere l'orientamento del menu (orizzontale sopra o sotto, verticale a sinistra o a destra), di caricare un logo e posizionarlo, e di attivare o disattivare selettore lingua, selettore temi e notifiche. È inoltre possibile disattivare l'affiancamento automatico delle voci di sottomenu: in quel caso i sottomenu lunghi diventano scorrevoli invece di essere troncati.

🔗 Webhook Hub

Nuovo sistema per integrare l'applicazione con servizi esterni, in entrambe le direzioni.

In uscita: gli eventi vengono accodati e consegnati in modo asincrono, con firma HMAC del payload, ritentativi a intervallo fisso o esponenziale, coda di dead letter per le consegne definitivamente fallite e possibilità di rigiocare una consegna. Ogni tentativo è tracciato nei log.

In entrata: l'endpoint POST /api/webhooks/inbound accetta chiamate esterne e le instrada in base a una configurazione di metadati — esecuzione SQL, chiamata HTTP o invocazione di un metodo — con protezione anti-replay.

Sono incluse le politiche di notifica con periodo di silenzio configurabile, una API amministrativa per la gestione degli endpoint e un job dello scheduler per lo smaltimento della coda. Tutta la configurazione — endpoint, eventi, sottoscrizioni, regole di ingresso — vive su tabelle di metadati: aggiungere una integrazione non richiede né codice dedicato né un nuovo deploy. La pagina «Webhook Hub» della documentazione in-app riporta la procedura completa in 5 lingue.

📈 Performance Inspector

Il framework può raccogliere metriche di fetch e render per ogni route, aggregarle e mostrarle in una dashboard amministrativa: media, p95, massimo e conteggio, con ritenzione a 7 giorni e possibilità di attivare la raccolta route per route.

La funzione è disattivata per impostazione predefinita e si abilita con AppSettings:enablePerformanceInspector, in hot-reload. Accanto alle metriche è disponibile un ispettore della qualità del dato, attivabile per singola route dal props bag (extraProps.qualityInspector).

🤖 Chatbot: nuove azioni e lettura dello schema

Il chatbot RAG guadagna dieci nuovi tipi di azione e la capacità di interrogare la struttura del progetto.

  • Tre nuove superfici contestuali: pivot builder, editor delle impostazioni e report designer. Il chatbot propone azioni sulla pagina in cui ci si trova. Sull'editor delle impostazioni le modifiche vengono solo preparate: il salvataggio resta un gesto esplicito dell'utente. Nel dump inviato al modello i valori riservati — stringhe di connessione, password, chiavi, licenza — sono mascherati, e una lista di esclusione impedisce di scriverli. Sul report designer viene sempre generato un file nuovo con data e ora, senza toccare il report aperto.
  • Operazioni sui metadati: creazione di tabella, scaffolding di tabelle, viste e colonne, spostamento di voci di menu. Le due operazioni non reversibili — eliminazione di una colonna e di una voce di menu — richiedono una conferma esplicita verificata anche lato server, quindi anche quando la richiesta arriva da un client senza interfaccia.
  • Introspezione: il chatbot può elencare connessioni (solo i nomi, mai le stringhe di connessione), database, tabelle, colonne e l'albero del menu. Senza queste letture non poteva conoscere gli identificativi reali su cui operare.

Una nuova pagina di documentazione elenca i prompt supportati, verificata rispetto ai test automatici.

📊 Spreadsheet: visibilità delle colonne allineata alla griglia

Lo spreadsheet rispetta ora gli stessi flag di visibilità della list-grid: mc_hide_in_list, mc_hide_in_edit e mc_show_in_filters. Una colonna nascosta in elenco non compare più nel foglio, e una colonna nascosta in modifica non è più editabile nelle celle.

🛡️ Sicurezza

Hardening best-effort sulla creazione guidata dei report: il nome del file richiesto viene ora validato rifiutando percorsi assoluti e caratteri non ammessi, con un controllo che si comporta allo stesso modo su Windows e su Linux — in precedenza si appoggiava a una normalizzazione che sui due sistemi filtrava in modo diverso. L'errore restituito distingue una configurazione non valida da un fallimento della generazione, così chi integra il framework non cerca il problema nel posto sbagliato.

🐛 Bug fix degni di nota

  • Calendario, primo caricamento: la vista mostrava dati non filtrati per l'intervallo visualizzato — tipicamente nessun evento nel mese corrente, anche con appuntamenti presenti. Il primo caricamento partiva prima che i campi di inizio e fine configurati per l'archetipo fossero disponibili, e nessuna richiesta successiva correggeva il tiro. Ora i campi vengono risolti prima di comporre il filtro e, se arrivano dopo, i dati vengono richiesti di nuovo una sola volta.
  • Scene 3D con licenza professional: le pagine del designer e del visualizzatore 3D rimandavano alla schermata di accesso negato, perché la funzionalità non risultava inclusa in nessun profilo di licenza. Ora fa parte del profilo professional.
  • Report su Linux: la creazione guidata di un report falliva perché i caratteri venivano gestiti tramite una libreria grafica disponibile solo su Windows.
  • Performance Inspector, aggregazione: due esecuzioni sovrapposte del job di aggregazione — la dashboard lo richiama al proprio ricaricamento, mentre può essere lanciato anche a mano — terminavano con un errore per chiave duplicata. Inoltre la finestra dei dati grezzi non era allineata al confine del bucket giornaliero, e il bucket più vecchio veniva ricostruito da un sottoinsieme degli eventi.
  • Linux dietro reverse proxy: gli URL assoluti generati dal backend perdevano la porta e usavano lo schema sbagliato quando l'installazione è servita su una porta non standard o solo in HTTP.
  • Oracle, salvataggio delle scene 3D: il salvataggio falliva per l'uso di un nome di parametro riservato e per la conversione dei valori numerici. Corretti entrambi, insieme alla gestione delle colonne con nome minuscolo quotato.
  • Oracle, esposizione OData: le colonne venivano forzate in maiuscolo invece di usare il nome fisico dichiarato nei metadati, rendendo irraggiungibili le entità con nomi misti.
  • PostgreSQL e Oracle, lookup nei grafici e nei raggruppamenti: il campo descrittivo di un lookup non veniva risolto dal nome logico a quello fisico, e il raggruppamento mostrava valori vuoti o errati.
  • Chatbot, conferme mancanti: in quattro punti la richiesta di conferma non compariva mai a causa di una chiamata malformata; in due di quei punti la cancellazione (cronologia e sessioni della chat) avveniva senza chiedere nulla. Ora ogni conferma passa dallo stesso percorso e in caso di errore la risposta è "annulla".
  • Importazione metadati: le route il cui campo database è vuoto — cioè quelle che usano il database predefinito dell'applicazione — non potevano essere importate, e l'errore suggeriva un problema di permessi o di database sbagliato.
  • Visualizzatore 3D: la scena occupava una fascia orizzontale invece dell'altezza piena della pagina.
  • Interfaccia, griglia con sfondo a tema: l'area sotto l'ultima riga lasciava trasparire lo sfondo della pagina, facendo sembrare la griglia bucata. Ora la superficie della griglia segue il tema, in chiaro e in scuro.

🔧 Aggiornamenti operativi raccomandati per chi aggiorna

  1. Verificare appsettings.json dopo l'aggiornamento: le chiavi nuove hanno valori predefiniti prudenti e non richiedono intervento, ma è il momento giusto per rivederle.
  2. Performance Inspector: impostare AppSettings:enablePerformanceInspector a true per attivarlo; resta disattivo se la chiave è assente.
  3. Webhook Hub: non serve alcun intervento per renderlo raggiungibile. Tabelle, route amministrative e voci di menu — raccolte in un sottomenu «Webhook Hub» sotto Amministrazione — vengono create al primo caricamento del menu, sia su installazione nuova sia aggiornando da una versione precedente. Resta da configurare l'integrazione: in uscita servono tre righe (l'endpoint con URL di destinazione, segreto condiviso, timeout e politica di ritentativo; l'evento; la sottoscrizione che li collega), in entrata un endpoint con direzione inbound e una regola di instradamento. La firma viaggia nell'header X-Wuic-Signature; la procedura completa è nella pagina «Webhook Hub» della documentazione in-app.
  4. Theme Builder: la tabella dei temi viene creata al primo salvataggio. Se si usano temi personalizzati, verificare l'export Excel di una griglia per confermare che i colori siano quelli attesi.
  5. Chatbot: le nuove azioni sono disponibili dopo il riavvio del motore RAG; le operazioni non reversibili richiedono conferma e non possono essere applicate senza.
  6. Linux dietro reverse proxy: se l'installazione risponde su una porta non standard o solo in HTTP, rigenerare la configurazione nginx oppure allineare a mano il vhost esistente a proxy_set_header Host $http_host; e proxy_set_header X-Forwarded-Proto $scheme;. Gli aggiornamenti non riscrivono un vhost già presente.

v1.5.0

Torna all'indice

Versione precedente pubblicata: 1.3.2 (18 giugno 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


Release ampia, che raccoglie il lavoro su più fronti. Il chatbot RAG ha una configurazione del modello LLM semplificata e unificata, con l'uso di un modello locale gratuito (Qwen via Ollama) ora di prima classe e un motore robusto verso le particolarità dei modelli locali; è incluso un nuovo plugin per Visual Studio Code, WUIC Assistant, che porta lo stesso approccio agentico dentro l'editor. Arriva il nuovo Scene3D Designer per l'authoring di scene 3D dentro l'app — con materiali PBR, effetti shader, luci con bake, fisica e un viewer che lega gli oggetti ai dati — e il rendering è ora selezionabile tra WebGL e WebGPU. Il Workflow Designer riceve un pacchetto di authoring assistito (template, validazione del grafo, dialog guidati, guida in linea), e il Dashboard Designer un pacchetto di miglioramenti all'editing.


🤖 RAG Chatbot — configurazione LLM unificata

La configurazione del provider LLM del chatbot è stata consolidata attorno a una sola chiave e a un elenco esplicito di provider.

  • rag-llm-provider — anthropic / openai / openrouter / ollama, da impostare esplicitamente (nessun provider di default: se vuoto il chatbot resta in retrieval-only, senza invocare alcun LLM). ollama è ora un valore di prima classe: punta a un runtime locale via rag-llm-base-url, con formato OpenAI-compatibile.
  • rag-llm-api-key — unica fonte della chiave, indipendente dal provider scelto. Sostituisce la precedente coppia llm-api-key / anthropic-api-key (che restano accettate solo come fallback di migrazione). Il valore speciale agent-sdk usa l'Agent SDK (claude CLI) via subscription invece dell'API a consumo, se installato.
  • rag-llm-base-url — override dell'endpoint; obbligatorio per ollama (es. http://HOST:11434/v1), opzionale per gli altri provider.
  • rag-llm-default-chat-model — id del modello per il provider scelto.

Tutte le chiavi restano in hot-reload da appsettings.json: cambiare provider o modello non richiede restart.

🧠 LLM locale gratuito (Qwen via Ollama), zero API key

Il chatbot può ora girare interamente su un modello locale open — ad esempio Qwen (qwen2.5-coder:32b) servito da Ollama sulla propria macchina o sulla LAN — senza API key e senza costi per token. Configurazione tipica in 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

Una guida completa per montare il server Ollama (Windows/Linux, esposizione in LAN, tuning del context, avvio persistente) è inclusa nel pacchetto.

⚙️ Azioni del chatbot affidabili anche con modelli locali

Il motore è stato reso tollerante alle particolarità dei modelli locali, che — a differenza dei modelli commerciali — a volte non rispettano alla lettera il formato delle chiamate strumento. Il chatbot ora recupera correttamente l'azione proposta anche quando il modello la emette come testo o con escape JSON non standard. In pratica, le azioni sul designer e sui metadati — pulsanti di tabella (bulk), pulsanti di riga, stili condizionali, callback, iniezione di componenti nel designer — vengono proposte e applicate in modo affidabile anche con un LLM locale.

🧩 Assistente agentico in VS Code — WUIC Assistant

Il pacchetto include ora un plugin per Visual Studio Code, WUIC Assistant (llm-workspace/plugin/wuic-assistant.vsix): un assistente che conosce già le convenzioni del framework e opera direttamente sul progetto aperto. Genera componenti Angular (card, dashboard con tile KPI, list-grid con navigazione al form di modifica), componenti alimentati da un endpoint .NET personalizzato, e propone le modifiche ai metadati (stili condizionali, azioni di tabella e di riga, lookup). Ogni scrittura passa da un'anteprima prima della conferma.

Usa lo stesso RAG locale WUIC tramite il server MCP wuic-rag (avviato automaticamente) e il grounding già presente nel progetto: non richiede configurazione manuale del server MCP. Il modello LLM è a scelta — locale via Ollama (Qwen, zero API key) oppure Anthropic.

Installazione dallo ZIP:

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

In alternativa lo installa install-llm-workspace.ps1. Poi Ctrl+Shift+P → WUIC Assistant: Apri Chat; il provider si sceglie nelle impostazioni (wuicAssistant.provider = ollama o anthropic).

🧊 Scene3D Designer (novità)

Nuovo designer 3D visuale su route #/scene3d_designer, con pubblicazione read-only tramite lo Scene3D Viewer (#/scene3d_viewer/:scene_key). Consente di comporre una scena tridimensionale e di legarne gli oggetti ai dati dell'app.

  • Palette e import: primitive (cubo, sfera, piano, cilindro, cono, toro), gruppi, luci, camera, testo 3D e Mesh Repeater (istanze generate dai dati). Import di modelli esterni in glTF/GLB, OBJ, FBX, STL e DAE. La palette è estendibile da metadata con tipi custom.
  • Materiali PBR: metalness, roughness, emissivo, opacità, wireframe, flat shading e facce; per il materiale fisico anche transmission, IOR, spessore e assorbimento volumetrico (vetro colorato).
  • Effetti shader: un effetto descritto in JSON (con schema, autocompletamento e vista "a struttura") viene compilato per il renderer attivo; in alternativa, shader GLSL scritti a mano sul renderer WebGL.
  • Illuminazione: luci di scena con ombre morbide, bake dell'illuminazione statica nei vertex color (unlit) e — sul renderer WebGL — un path tracing di anteprima fotorealistica.
  • Animazioni e fisica: transport per le clip degli asset importati; fisica per-oggetto opzionale con simulazione Play/Stop nel designer e autoplay nel viewer.
  • Binding ai dati: ogni oggetto si lega a una route WUIC (con record opzionale) e mappa proprietà visive (etichetta, colore, visibilità) sulle colonne; doppio click su un oggetto bindato nel viewer apre la CRUD del record.
  • Anteprime automatiche: al salvataggio la scena viene fotografata dal canvas e mostrata come anteprima nell'elenco "Carica scena", senza configurazione né processi esterni.

Le route del designer e del viewer richiedono la feature scene3d-designer. Le tabelle di supporto vengono create e aggiornate automaticamente al primo utilizzo, su tutti i database supportati.

🖥️ Renderer WebGPU (opt-in)

Il rendering di scene e viewer è ora selezionabile tra WebGL (default) e WebGPU (attivabile dalla toolbar). Quando WebGPU non è disponibile nel browser, il designer resta automaticamente su WebGL senza alcun intervento. La modalità scelta viene salvata con la scena e ripristinata all'apertura. Con il renderer WebGPU attivo, il bake delle luci gira su GPU (ombre incluse), molto più rapido sulle scene dense; gli shader GLSL scritti a mano e il path tracing restano disponibili sul renderer WebGL.

🔀 Workflow Designer — authoring assistito

Il designer di workflow (#/workflow-designer) accompagna ora la costruzione di un processo da zero.

  • Template di partenza: "Nuovo da template" genera un grafo pronto per i pattern comuni (approvazione semplice, coda claim/release, catena a soglie, task paralleli): si scelgono la route principale e — dove serve — il campo di stato, e grafo, azioni e transizioni nascono già collegati.
  • Validazione del grafo: "Valida grafo" segnala i problemi prima del salvataggio (start senza sbocchi, nodi irraggiungibili, azione senza target, condition vuota, ramo morto, timer o split incompleti, permesso con ruolo inesistente). Cliccando un rilievo il canvas inquadra il nodo. Il salvataggio non è mai bloccato: con problemi aperti compare un riepilogo con "Salva comunque".
  • Configurazioni guidate: i dialog di timer e task paralleli usano dropdown e un autocompletamento delle route, invece di campi liberi da digitare a memoria.
  • Onboarding e guida: checklist dei primi passi su un canvas nuovo, tooltip descrittivi sulla palette e una "Guida rapida" con la legenda delle forme e un glossario dei concetti (transizione, guardia, permesso, azione interna).

🎨 Dashboard Designer — editing più rapido

  • Snap alla griglia: attivabile dal menu azioni del designer, mostra la griglia sul canvas e allinea automaticamente trascinamento, ridimensionamento e drop dalla palette. All'attivazione anche gli elementi già presenti nel canvas vengono allineati alla griglia.
  • Flusso normale / assoluto: nuovo flag nel menu azioni (default: flusso normale, nessun cambiamento per le dashboard esistenti). In modalità assoluta gli elementi droppati si posizionano alle coordinate del drop, fuori dal flusso: ridimensionarne uno non sposta gli altri. Il drop dentro un contenitore usa il contenitore come riferimento di posizione, e il runtime riconosce automaticamente le dashboard salvate in questa modalità.
  • Scorciatoie da tastiera: Canc/Backspace elimina l'elemento selezionato, le frecce lo spostano, Ctrl+Z/Ctrl+Y annulla/ripete. Trascinando un rettangolo di selezione da un'area vuota del canvas si selezionano più elementi: frecce e Canc agiscono sull'intera selezione.
  • Import/Export JSON e preset: la dashboard corrente si esporta come file JSON re-importabile (identico al contenuto persistito), utile per portare layout tra ambienti. I preset salvano layout riusabili con un nome e si riapplicano in un click.
  • Sposta nei tab: dal menu contestuale di un elemento dentro un tab, Sposta in nuovo Tab crea un nuovo tab e ci migra l'elemento (binding e stato preservati); Sposta in altro tab — disponibile quando il tabview ha più tab — lo sposta in un tab esistente a scelta. Il tab di destinazione viene attivato automaticamente, così come un tab appena droppato.
  • Importa dashboard/preset in un elemento: dal menu contestuale di un contenitore si importa una dashboard salvata o un preset direttamente dentro l'elemento; gli identificativi degli elementi importati vengono rigenerati e i riferimenti interni (datasource inclusi) rimappati, senza collisioni con il contenuto esistente.

🐛 Bug fix degni di nota

  • Designer — layout multi-colonna: l'iniezione di un layout a più colonne/aree (es. "3 colonne, ognuna con una griglia") proposta dal chatbot ora popola correttamente tutte le aree. In precedenza, dopo la prima cella, le successive non venivano risolte e i componenti restavano vuoti.
  • Chatbot — whitelist delle route: quando si chiede di bindare un componente a una route con un nome non esatto (es. "provincie" per "stateprovinces"), il chatbot effettua ora il match semantico e propone l'azione, invece di rispondere erroneamente che l'elenco delle route è in caricamento.
  • Viewer 3D — navigazione tra scene: aprendo in sequenza scene diverse dallo stesso viewer, ora ciascuna carica la propria scena. In precedenza il viewer poteva continuare a mostrare la prima scena aperta.
  • Editor JSON con schema: l'editor di codice in modalità JSON offre ora una vista "a struttura" (attivabile con un interruttore) per aggiungere e rimuovere proprietà tipizzate guidate dallo schema, senza scrivere JSON a mano.

🔧 Aggiornamenti operativi raccomandati per chi aggiorna

  1. Per usare un LLM locale gratuito, valorizzare in appsettings.json → AppSettings: rag-llm-provider=ollama, rag-llm-base-url, rag-llm-api-key (valore segnaposto, es. ollama) e rag-llm-default-chat-model.
  2. Migrare la chiave del chatbot su rag-llm-api-key: le precedenti llm-api-key e anthropic-api-key continuano a funzionare come fallback, ma la configurazione consigliata usa solo rag-llm-api-key.
  3. Per l'assistente in VS Code, installare il plugin dallo ZIP: code --install-extension llm-workspace/plugin/wuic-assistant.vsix (oppure lasciarlo installare da install-llm-workspace.ps1).
  4. Per usare lo Scene3D Designer, abilitare la feature scene3d-designer nella licenza attiva. Le tabelle di supporto vengono create e migrate automaticamente al primo utilizzo; il renderer WebGPU è opt-in dalla toolbar, con fallback automatico a WebGL.

v1.3.2

Torna all'indice

Versione precedente pubblicata: 1.3.0 (11 giugno 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


Release di consolidamento sul chatbot RAG introdotto in 1.3.0: il modello conversazionale non è più legato ad Anthropic — qualunque endpoint OpenAI-compatibile, inclusi runtime locali come Ollama con modelli open (Qwen), è ora configurabile e gira senza API key. Accanto a questo, una serie di fix su first-run installer, pacchetto sorgente e scaffolding metadata che si manifestavano su installazioni fresche, e un workspace pronto per gli assistenti AI di coding.


🤖 RAG Chatbot — provider LLM flessibile (incluso locale e gratuito)

Il modello conversazionale del chatbot è ora provider-agnostico. Oltre ad Anthropic sono supportati gli endpoint OpenAI-compatibili, il che include i runtime locali (es. Ollama): è possibile far girare modelli open e gratuiti come Qwen sulla propria macchina, senza API key e senza costi per token.

  • rag-llm-provider — anthropic (default) / openai / openrouter. Seleziona il dialetto wire del provider.
  • rag-llm-base-url — override dell'endpoint; valorizzandolo con l'URL di un server locale (es. http://localhost:11434/v1 per Ollama) il chatbot parla con il modello in locale.
  • rag-llm-default-chat-model — id del modello per il provider scelto (es. un modello Qwen su Ollama).
  • llm-api-key — chiave del provider attivo; per i runtime locali che non la validano basta un valore segnaposto (es. ollama). La storica anthropic-api-key resta valida quando rag-llm-provider=anthropic (zero migrazione).

Tutte le chiavi sono in hot-reload da appsettings.json: cambiare provider o modello non richiede restart.

Retrieval più accurato — il re-ranking dei risultati è stato affinato: il chatbot cita fonti più pertinenti sulle query in linguaggio naturale.

Notifiche di setup — al primo utilizzo il motore .NET scarica on-demand i modelli ONNX. Ora l'amministratore riceve nel campanello le notifiche di inizio / pronto / errore del download, su tutti e quattro i provider DB, anche quando l'inizializzazione è innescata da una richiesta priva di utente loggato.

Accelerazione GPU automatica — su una macchina con GPU NVIDIA l'engine usa la GPU senza installare CUDA: al primo avvio, oltre ai modelli ONNX, scarica on-demand anche il runtime CUDA 12 + cuDNN 9 necessario (~1.8 GB, una volta sola, solo se la GPU è presente) e lo configura da solo. Senza GPU → CPU, nessun download aggiuntivo. Override manuale con rag-engine-cuda-path.


🧩 Workspace pronto per assistenti AI di coding

Le applicazioni generate con il framework includono ora una raccolta di file markdown di contesto (descrizione del progetto, convenzioni, regole operative) nella root del workspace. Questi file rendono gli assistenti AI agentici — Continue, Cline, Cursor e simili — immediatamente consapevoli della struttura e delle convenzioni WUIC, senza installare estensioni proprietarie. Qualunque client che legge il contesto del workspace si comporta come un assistente "WUIC-native".


🐛 Bug fix degni di nota

  • First-run installer — modalità non-tutorial su tutti i provider DB: l'installazione con scaffolding di un database esistente (senza i dati di esempio del tutorial) è stata corretta e uniformata su tutti i provider supportati — SQL Server, MySQL, PostgreSQL e Oracle. Risolti i fallimenti dovuti a differenze di dialetto SQL, selezione del database/schema di destinazione e gestione delle connessioni che emergevano fuori dalla modalità tutorial.

  • First-run installer — percorso a script SQL (non-BAK): nel provisioning del metadata DB tramite script SQL incrementale (alternativa al restore da .bak), il parser dei batch separati da GO non gestiva correttamente alcuni separatori, facendo fallire la creazione dello schema su installazioni fresche. Lo splitter è stato corretto e l'install via script completa regolarmente.

  • Pacchetto sorgente — motore RAG .NET non trovato a runtime: nel pacchetto sorgente (-src-) il motore WuicRagEngine.dll veniva posizionato nella root del pacchetto, mentre l'eseguibile, avviato da bin/, lo cercava accanto a sé — il chatbot RAG non partiva ("WuicRagEngine.dll non trovato"). Il loader ora cerca la cartella rag-engine/ in più posizioni (output di build, content-root, working directory) e trova il motore in entrambi i layout di deploy.

  • First-run — persistenza della API key del chatbot: la chiave LLM inserita nel wizard di prima installazione viene ora scritta nell'appsettings.json canonico effettivamente letto dal runtime. In precedenza, in alcuni layout, poteva finire in una copia non letta dal processo, lasciando il chatbot senza chiave subito dopo l'installazione.

  • Scaffolding metadata — diagnostica e robustezza: la generazione dei metadata di alcune tabelle poteva fallire con un messaggio generico ("Unable to scaffold metadata table") che mascherava la causa reale. L'errore SQL effettivo ora risale fino al chiamante, e il caso che lo provocava è risolto.

  • Pacchetto sorgente — notifiche in tempo reale in dev: nel pacchetto -src-, il proxy del dev-server (ng serve) non inoltrava le connessioni WebSocket al backend; il canale delle notifiche (/ws) andava in timeout e gli aggiornamenti comparivano solo ricaricando la pagina. Il proxy ora inoltra anche i WebSocket: le notifiche arrivano in tempo reale.


📦 Pacchetti aggiornati

Package Da 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

🔧 Aggiornamenti operativi raccomandati per chi aggiorna

  1. Per far girare il chatbot con un modello locale e gratuito (es. Qwen via Ollama): impostare rag-llm-provider=openai, rag-llm-base-url all'endpoint locale (es. http://localhost:11434/v1) e rag-llm-default-chat-model all'id del modello; valorizzare llm-api-key con un segnaposto (es. ollama) se il runtime non la valida. Nessun restart: le chiavi sono in hot-reload.
  2. Per restare su Anthropic non serve alcuna azione: anthropic-api-key continua a funzionare con rag-llm-provider=anthropic (default).
  3. Il pacchetto sorgente (-src-) è più leggero: non include più le DLL framework ridondanti nella root, che vengono ricreate da dotnet build a partire dai pacchetti NuGet. Scaricando la nuova -src- non è richiesta alcuna azione.
  4. Al primo utilizzo del chatbot con motore .NET, l'amministratore vedrà nel campanello l'avanzamento del download dei modelli ONNX. Attendere la notifica "pronto" prima del primo Ask.
  5. Le nuove app generate includono automaticamente i file di contesto per assistenti AI nella root del workspace; per le app esistenti possono essere rigenerati.

v1.3.0

Torna all'indice

Versione precedente pubblicata: 1.2.1 (31 maggio 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


Release minor focalizzata sull'integrazione del chatbot RAG lato framework: cronologia conversazionale persistita, context management automatico, configurazione hot-reload da appsettings.json e schema cross-DBMS auto-applicato al primo avvio. Accanto alla feature principale, alcuni fix di scaffolding metadata e robustezza del repository chat su MySQL/Oracle che si manifestavano in scenari di provisioning DB freschi.

Il chatbot è il primo componente WUIC con stato lato server (_rag_chat_sessions + _rag_chat_messages) che si estende su tutti e quattro i provider supportati senza configurazione manuale dello schema. Il primo Ask rileva il provider, applica in ordine le patch SQL incrementali e parte. Con questa release lo stack di serving può inoltre girare nativamente su .NET (motore ONNX in-process), rendendo il deploy al cliente indipendente da Python.


🤖 RAG Chatbot — gestione contesto end-to-end

Il componente <wuic-rag-chatbot> ora persiste sessioni multiple per utente, con storia conversazionale completa, context summarization automatica e configurazione via appsettings.json. La feature è opt-in: senza anthropic-api-key configurata il chatbot resta inattivo.

Sessioni

  • Storia conversazionale persistita per utente. La sessione rimane attiva tra reload del browser e cambi di route.
  • Popup di selezione sessioni ordinate per updated_at decrescente, con titolo derivato dal primo prompt (troncato a 100 char + tooltip full).
  • Rinomina inline con persistenza immediata.

Context management automatico

  • Visual cue % nel header del chatbot: cerchio colorato che indica il consumo della finestra di contesto del modello (verde <60% / giallo 60-80% / arancio 80-90% / rosso >90%). Il valore è calcolato dai token effettivamente consumati dall'API Anthropic ed è persistito per turno, così sopravvive al reload.
  • Auto-compact pre-Ask: quando la cronologia supera la soglia configurabile (default 30 turn) e ci sono almeno 10 turn non ancora riassunti, il backend lancia un compact best-effort in background prima dell'Ask successivo. Il summary aggiornato viene iniettato nel system prompt dei turn futuri.
  • Compact on-demand: l'utente può forzare un compact via slash command /compact o cliccando il cerchio cue.
  • Memory facts: il modello stesso può "pinnare" fatti high-priority via tool-use (remember_fact/forget_fact). I fatti restano nel system prompt anche dopo compact (max 20, eviction FIFO).
  • Follow-up questions: il modello suggerisce fino a 3 domande di approfondimento, renderizzate come chip cliccabili sotto la risposta. Click = popola l'input box (non invia automaticamente).

Configurazione appsettings.json

  • anthropic-api-key — chiave API Anthropic, hot-reload. Non hard-coded, non committare in repo.
  • anthropic-default-chat-model — claude-haiku-4-5-20251001 (200k, default) / claude-sonnet-4-5-20250929 / claude-opus-4-5. Determina la finestra di contesto e il driver del visual cue.
  • anthropic-auto-compact-threshold — intero >=0, default 30. Settando 0 si disabilita l'auto-compact (resta disponibile /compact manuale).

Cross-DBMS auto-migration

Lo schema chat history (5 patch incrementali) viene applicato in modo idempotente al primo Ask, sul provider configurato (MSSQL / MySQL / PostgreSQL / Oracle). Nessuno step DBA richiesto sull'installazione esistente.


🛠️ Azioni che il chatbot può applicare al progetto

Oltre a rispondere in linguaggio naturale, il chatbot può proporre modifiche concrete al progetto come chip d'azione con bottone "Applica". Ogni chip mostra cosa farà (route target, codice generato, motivazione) e l'utente decide se applicare. Niente azione viene eseguita senza il click esplicito.

Le tipologie di azione supportate:

  • Azioni toolbar e row — aggiunge bottoni custom alla toolbar di una <wuic-list-grid> o all'azione di singola riga, con callback JavaScript generato. Pattern: "aggiungi un'azione che esporta le righe selezionate in CSV", "metti un bottone Approva sulla riga".
  • Stili condizionali tabella e colonna — applica classi CSS alla riga o alla singola cella in base a una condizione JS. Pattern: "evidenzia in rosso le righe con scadenza superata", "metti sfondo verde alla cella stato quando vale 'OK'".
  • Formula display di colonna — sostituisce la rappresentazione di una colonna in lista con un template HTML/Angular custom (badge, icona, link, percentuale colorata). Pattern: "mostra priorità come badge colorato verde/giallo/rosso".
  • Formula titolo del form — calcola dinamicamente il titolo dell'edit-form di un record dal contenuto del record stesso. Pattern: "il titolo deve essere Cliente {ragione_sociale}".
  • Default value e validazione custom — genera callback per default value all'apertura del form (precompilazione campi) o per validazione complessa (cross-field, regex personalizzati). Pattern: "default data_creazione = oggi", "valida che email finisca per @azienda.it".
  • Selection-changed e lifecycle callback — hook su eventi del form (cambio selezione record, before-save, after-save, after-delete) per side-effect personalizzati: refresh datasource collegati, notifiche, audit log applicativo.
  • Modifiche metadata — applica modifiche dirette ai metadata di tabella/colonna (caption, ordinamento, nascondi in list/edit, validazioni di base) senza passare per il metadata editor manuale.
  • Snippet SQL nei metadata (super-admin) — scrive frammenti SQL diretti nei campi metadata che vengono concatenati a runtime nelle query autogenerate: custom JOIN sulla route, custom SELECT clause su colonna, formula colonna calcolata, espressione display di lookup. Pattern: "sulla colonna total di orders calcola somma price × quantity", "aggiungi join a payments su invoice_id". Il chatbot conosce il dialetto del provider attivo (mssql/mysql/postgres/oracle) e genera SQL nel quoting/syntax corretto. Operazione gated D3: richiede privilegi super-admin lato backend, con audit log automatico su _error__logs per ogni applicazione.

🎨 Azione nuova: layout designer da linguaggio naturale

Quando l'utente si trova sulla pagina Designer di una dashboard, il chatbot espone una nuova famiglia di azioni che agisce direttamente sul canvas del designer (non sui metadata persistiti).

Esempi di prompt supportati:

  • "aggiungi una grid bindata alla route cities" → inietta DATASOURCE + DATAREPEATER configurati e bindati;
  • "crea un layout tabellare 2×2" → inietta una <table> 2×2 con celle pronte a ricevere altri componenti;
  • "metti uno splitter verticale con 3 aree" → inietta SPLITTER configurato;
  • "cambia il colore del riquadro in alto a destra in rosso" → modifica la property backgroundColor del componente individuato;
  • "aggiungi una colonna alla tabella" / "rimuovi la riga 2" → modifica cols/rows del componente TABLE selezionato;
  • "rimuovi il KPI Fatturato" → elimina un componente dal canvas tramite il suo nome.

Il chatbot conosce il catalogo completo dei 31 tool del designer (gruppo HTML, DATA, CONTAINER) e le loro proprietà editabili. Quando l'utente menziona una route metadata con nome approssimato ("provincie" invece di "stateprovinces"), il chatbot fa fuzzy-match sulla lista di route disponibili nel progetto e mostra il nome reale risolto nel rationale dell'azione.

Le modifiche restano sul canvas del designer fino al click su "Salva dashboard" — nessuna scrittura DB automatica, l'utente vede sempre l'esito visuale prima di commit. L'undo/redo del designer copre anche le azioni iniettate dal chatbot.


⚙️ Motore RAG nativo .NET (deploy senza Python)

Lo stack di serving del chatbot RAG può ora girare interamente su .NET, senza un server Python separato né virtual environment sulla macchina di destinazione. I modelli di retrieval (embeddings + reranker) sono caricati in-process tramite ONNX Runtime, con accelerazione GPU (CUDA) rilevata automaticamente e fallback trasparente su CPU.

  • Attivazione via appsettings.json: rag-use-dotnet-engine=true seleziona il motore .NET; il default false mantiene il comportamento precedente.
  • rag-engine-device (auto / cpu / cuda) sceglie il device di inferenza; rag-engine-profile controlla il livello di redazione delle fonti citate nelle risposte.
  • Al primo avvio gli artefatti necessari (modelli ONNX + indice) vengono scaricati on-demand, così il pacchetto base resta leggero.

Risultato pratico: il deploy al cliente è solo .NET — nessuna installazione Python né dipendenze native aggiuntive oltre al runtime .NET. La chiamata al modello conversazionale e la pipeline di retrieval e azioni restano identiche tra i due motori.


🐛 Bug fix degni di nota

  • Documentazione callback allineata al runtime: il ricettario dei callback descriveva firme non corrispondenti al comportamento effettivo per due casi. Il default value callback scrive il valore nel record (record[field.mc_nome_colonna] = ...) e il return viene ignorato; la validazione custom riceve (record, field, vr, wtoolbox) e comunica l'esito con un return boolean (false blocca il salvataggio) più vr.message per il testo mostrato. Gli esempi precedenti, basati su validateResult(...) e su un return per il default value, producevano callback che non si applicavano. Documentazione corretta in tutte e cinque le lingue.

  • Affidabilità delle azioni proposte dal chatbot: per le richieste d'azione il chatbot ora emette in modo deterministico la chip d'azione corrispondente, e ritenta automaticamente in caso di rate-limit transitorio del modello conversazionale invece di degradare silenziosamente a sola risposta testuale.

  • Scaffolder metadata — distinzione date vs datetime consolidata: completato il follow-up del fix introdotto in 1.2.1 sui tipi temporali generati. Il parser dei tipi sorgente ora copre anche varianti DDL atipiche (MySQL DATETIME(0) senza precision, PostgreSQL timestamp bare senza time-zone qualifier, Oracle TIMESTAMP(n) con precision esplicita) — tutte continuano a mappare correttamente sull'UI type datetime mantenendo il componente time al salvataggio.

  • Suggest sui campi metadata — mc_suggest_value_callback ora normalizza il return value: il callback configurabile lato DB poteva ritornare una promise o un valore sincrono, ma il parser runtime accettava solo il sincrono. Risultato: il suggest non scattava silenziosamente nei callback async. Ora la normalizzazione attende Promise.resolve(callback(...)) in modo uniforme.

  • Repository chat — Guid cross-driver: il driver MySQL.Data materializza una colonna CHAR(36) come Guid quando il flag OldGuids è false (default a partire dalla versione 6.6 del connettore), causando InvalidCastException su GetString. Stesso rischio su Oracle con storage RAW(16). La lettura del correlation id ora ha una cascata di fallback (GetGuid → GetString → GetValue con switch sul runtime type) — robusta su tutti e quattro i provider indipendentemente dalla configurazione del driver.

  • Repository chat — connessione MySQL non aperta: il gateway MySQL ritornava una connessione new MySqlConnection(cs) senza chiamare Open(), in modo asimmetrico rispetto ai gateway PostgreSQL e Oracle. Il primo ExecuteNonQueryAsync dello schema auto-apply falliva con "Connection must be valid and open". Aggiunto OpenConnectionToConnectionString simmetrico, allineato agli altri provider.


📦 Pacchetti aggiornati

Package Da 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

🔧 Aggiornamenti operativi raccomandati per chi aggiorna

  1. Per abilitare il chatbot RAG, aggiungere ad appsettings.json la chiave anthropic-api-key (e opzionalmente anthropic-default-chat-model e anthropic-auto-compact-threshold). Il backend rilegge le chiavi in hot-reload — non serve restart.
  2. Nessuno step DBA richiesto sull'installazione esistente: al primo Ask del chatbot, lo schema chat history (_rag_chat_sessions + _rag_chat_messages con tutte le colonne) viene applicato in modo idempotente sul provider configurato in MetaDataSQLConnection. L'auto-migration copre installazioni nuove e parzialmente migrate.
  3. Se l'installazione è su MySQL / PostgreSQL / Oracle, verificare che la connection string punti al provider corretto e che l'utente abbia i privilegi ALTER TABLE sullo schema metadati (necessari una volta sola, al primo avvio).
  4. Per monitorare il consumo del context window, il cerchio cue % nel header del chatbot è il driver visivo immediato. Sopra 80% conviene un compact manuale (/compact o click sul cue) per ridurre la latenza dei turn successivi.
  5. Per far girare il chatbot RAG senza Python sulla macchina di destinazione, impostare rag-use-dotnet-engine=true in appsettings.json (opzionalmente rag-engine-device e rag-engine-profile). Al primo avvio gli artefatti di inferenza vengono scaricati automaticamente.

v1.2.1

Torna all'indice

Versione precedente pubblicata: 1.2.0 (27 maggio 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


Release di manutenzione focalizzata su una classe di bug latenti che si manifestavano sui campi datetime e decimal in scenari cross-DBMS / cross-locale. La maggior parte degli utenti su workstation IT ne è già stata toccata almeno una volta — il componente time delle date veniva troncato a mezzanotte su INSERT e UPDATE, e i decimali con separatore non invariante producevano ORA-01722 su Oracle quando la sessione ODP.NET ereditava la cultura italiana di Windows.

I fix sono trasversali ai 4 provider supportati (MSSQL, MySQL, PostgreSQL, Oracle) e tutti i test di round-trip end-to-end risultano verdi nelle locale di sessione DB inglese (en-US) e italiana (Italiano dmy, lc_time=Italian_Italy.1252).


🐛 Bug fix degni di nota

  • Componente time troncato su INSERT/UPDATE di campi DATETIME2 / DATETIME(n) / TIMESTAMP: lo scaffolder dei metadati collassava tutti i tipi temporali del DB sorgente sul singolo tipo UI date. Risultato: una colonna SQL Server DATETIME2(3) (o MySQL DATETIME(3), PostgreSQL timestamp without time zone, Oracle TIMESTAMP(0)) veniva trattata come pura data e il framework emetteva '20261231' invece di '20261231 23:59:58' su INSERT/UPDATE — l'orario inserito a UI si perdeva al salvataggio. Lo scaffolder ora distingue date (data pura) da datetime (data + ora) e il salvataggio preserva il componente time con precisione al secondo. La precisione sotto-secondo (.fff) resta troncata intenzionalmente per coerenza col date-time picker UI che non la espone.

  • Oracle ORA-01722: valore stringa non valido su campi NUMBER(p,s) da workstation italiana: i provider emettevano i valori numerici quotati come stringa nelle INSERT/UPDATE (es. VALUES (..., '9876.4321', ...)). Oracle convertiva la stringa in numero usando NLS_NUMERIC_CHARACTERS della sessione, che ODP.NET deriva dalla CurrentCulture del thread .NET: in culture italiana il decimal è , e . diventa group separator → '9876.4321' veniva interpretato come gruppo invalido. Ora i valori numerici (decimal, float, double, numeric) sono emessi come literal SQL non quotati: i literal numerici Oracle usano sempre . come decimal point indipendentemente da NLS.

  • Oracle ORA-00904: identificativo non valido su tabelle con identificatori quoted-lowercase: una tabella creata con DDL CREATE TABLE "my_table" ("id" NUMBER, ...) (lowercase quoted, case-preserving) non era leggibile dal framework. La logica di quoting riconosceva i mixed-case e i reserved keywords ma trattava gli all-lower come "safe identifier" e li emetteva bare (Oracle li case-folda a UPPER), causando il mismatch con la fisica "id". Ora gli identificatori all-lowercase vengono preservati con quoting esplicito.

  • Locale-invariant parsing/formatting di date e timestamp lato server: il path di parsing/emit di DateTime su Oracle e PostgreSQL usava la CurrentCulture del thread. Ora il parsing tenta prima InvariantCulture e fa fallback a CurrentCulture solo se serve; il formatting per le clausole SQL (TO_TIMESTAMP(...) / literal yyyy-MM-dd HH:mm:ss) usa sempre InvariantCulture. Effetto utente: il round-trip rimane bit-perfect indipendentemente da CultureInfo.CurrentCulture del processo backend.

  • Oracle ORDER BY su PK lowercase: la clausola ORDER BY aggiunta automaticamente sulla chiave primaria emetteva il nome colonna senza passare per la logica di quoting → produceva ORA-00904 su tabelle con PK "id" lowercase quoted. Ora la PK passa per lo stesso quoting di tutte le altre colonne.


🗄️ Compatibilità DB cross-locale

I test di roundtrip end-to-end coprono ora le seguenti combinazioni provider × sessione DB:

Provider Sessione DB testata Esito
MSSQL @@LANGUAGE=Italiano, 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

Le date sono asserite invarianti (2026-12-31T23:59:58.000 resta 2026-12-31T23:59:58.000 end-to-end indipendentemente da sessione DB e CurrentCulture del backend), così come i decimali (9876.4321 resta 9876.4321).


📦 Pacchetti aggiornati

Package Da 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

Torna all'indice

Versione precedente pubblicata: 1.1.0 (13 maggio 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


Questa release estende il framework a due nuovi DBMS — PostgreSQL e Oracle — e corregge un bug del filtro Spreadsheet che si manifestava quando una route con server-side operations attive aveva colonne lookup.

  • Provider PostgreSQL e Provider Oracle: entrambi installabili come drop-in (postgresql.dll / oracle.dll accanto a WuicCore.dll), utilizzabili sia come data store sia come metadata store, con feature parity con MSSQL e MySQL.
  • Filtro Spreadsheet su colonne lookup in modalità server-side: il popup ora mostra i descrittivi delle lookup (es. Woodgrove Bank Crandon Lakes) e applica il filtro usando l'ID di chiave esterna, eliminando l'errore SQL che si presentava su provider con typing stretto.

🗄️ Provider PostgreSQL

Drop-in compatibile con PostgreSQL 14+ (testato su 16). Installazione: postgresql.dll accanto a WuicCore.dll nella physical path del sito IIS, o nella directory di publish del binario Linux. Il setup wizard firstRun espone automaticamente "PostgreSQL" nel dropdown DBMS quando rileva la presenza della DLL.

Coverage funzionale. Tutte le superfici core del framework operano nativamente su PG con la stessa semantica delle release MSSQL/MySQL: CRUD, server-side paging, sorting, grouping, aggregazioni, autocomplete lookup, OData, scheduled jobs, audit, notifiche, retry policy, ottimistic concurrency, validations, callbacks/events, import/export XLS, import/export PDF, multi-tenant.

Tipi PG-specific supportati. boolean (mappato automaticamente da/per smallint storage interno usato per parity con MSSQL/MySQL), varchar/text, numeric, integer/bigint, timestamp, date, bytea (upload binari), geometry (PostGIS — visualizzazione su mappe via ST_AsText).

File preconfigurati nel pacchetto.

  • appsettings.postgres.json / appsettings.linux.postgres.json / appsettings.multi-tenant.postgres.json — environment self-contained pronti, attivabili con ASPNETCORE_ENVIRONMENT=postgres.
  • dbms/scripts/first-run/*.postgres.sql — bootstrap metadata + tutorial WideWorldImporters DDL/DML.

🗄️ Provider Oracle

Drop-in compatibile con Oracle 19c / 21c / Free 23c. Installazione oracle.dll con la stessa modalità del provider PostgreSQL; "Oracle" appare nel dropdown firstRun automaticamente.

Coverage funzionale. Identica a PostgreSQL — tutte le superfici core con la stessa semantica delle release MSSQL/MySQL.

Identifier length. Oracle 11g/12.1 (max 30 char) non è ancora supportato — i lookup alias generati dal framework eccedono il limite. Oracle 12.2+ (128 char) è il floor di supporto.

File preconfigurati nel pacchetto.

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

🐛 Bug fix degni di nota

  • Filtro popup Spreadsheet su colonne lookup quando md_server_side_operations=true: il popup colonna funnel di <wuic-list-spreadsheet> su una colonna lookupByID mostrava ID numerici nudi (es. 1, 4, 5) invece dei descrittivi (es. Woodgrove Bank Crandon Lakes). Su PG/Oracle l'applicazione del filtro generava un errore SQL (42601 ilike %% su PostgreSQL, ORA-00904 su Oracle) perché il client trasmetteva la stringa descrittiva contro la colonna FK numerica. Ora il server emette il descrittivo joinato (<entity>___<dataTextField>__<colName>) accanto al FK ID e il client visualizza il descrittivo nel popup ma trasmette l'ID raw come filter value: la WHERE col = <id> rimane numerica e cross-DBMS-safe. Nessuna azione richiesta lato consumer.

📦 Pacchetti aggiornati

Package Da 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

🔧 Aggiornamenti operativi raccomandati per chi aggiorna

  1. Per chi resta su MSSQL o MySQL: nessuna azione richiesta. Il fix del filtro Spreadsheet si applica a tutti i provider in modo trasparente al primo refresh del client.
  2. Per attivare PostgreSQL: copiare postgresql.dll (insieme alle sue dipendenze runtime — Npgsql.dll, Npgsql.EntityFrameworkCore.PostgreSQL.dll, Microsoft.Extensions.Logging.Abstractions.dll) nella physical path del sito IIS o nella directory di publish Linux, riavviare il backend. Selezionare PostgreSQL nel wizard firstRun oppure puntare ASPNETCORE_ENVIRONMENT=postgres per usare appsettings.postgres.json preconfigurato.
  3. Per attivare Oracle: stessa procedura — oracle.dll + Oracle.EntityFrameworkCore.dll + Oracle.ManagedDataAccess.dll. Verificare che la versione del DB target sia ≥ 12.2 (vincolo identifier length).
  4. Cache client: dopo l'aggiornamento, un hard refresh del browser (Ctrl+F5) è sufficiente per allineare il client al nuovo contratto del filtro popup. Nessuna invalidazione metadata server richiesta.

v1.1.0

Torna all'indice

Versione precedente pubblicata: 1.0.20 (12 maggio 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


Salto a minor: questa release introduce due capability strutturali che cambiano il modello di deployment del framework.

  • Multi-tenant: una singola istanza del framework instrada dati e metadata di N aziende su N connessioni DB diverse. Configurazione tenant-by-tenant sulle colonne Aziende.Connessione_DB_Dati / Aziende.CONNESSIONE_DB_Meta; routing trasparente a livello applicativo via TenantContext (AsyncLocal, sopravvive a Task/scheduler).
  • Menu localizzabile per lingua: le voci di menu (mm_display_string_menu) non contengono più label italiane hard-coded ma chiavi stabili namespaced menu.<scope>.<slug>, risolte runtime dalla pipe translate di Angular contro _wuic_translations. Switch lingua dal selettore utente cambia tutte le voci senza F5.

🌐 Multi-tenant management

Una singola installazione del framework può ora servire più aziende ("tenant") con dati e metadata fisicamente isolati su DB diversi, senza richiedere repliche dell'applicazione né reverse-proxy partizionati per host.

Modello dati. L'instradamento tenant→connessioni è definito su due colonne del DB metadati primario:

  • Aziende.Connessione_DB_Dati — nome di una entry in ConnectionStrings per il DB applicativo del tenant
  • Aziende.CONNESSIONE_DB_Meta — nome di una entry in ConnectionStrings per il DB metadati del tenant

Le colonne contengono il nome della entry, non la stringa letterale. Rotazione credenziali via editing appsettings.<env>.json, senza toccare il DB.

Attivazione. Flag in appsettings.json (sezione AppSettings):

"multiConnectionEnabled": "true"

Con flag false (default) il comportamento resta single-tenant, identico alle release precedenti. Con flag true ogni richiesta HTTP autenticata risolve l'AziendaId dall'utente loggato e instrada GetOpenConnection alle connection string del tenant corrispondente.

Routing transparente. Tutti i punti di accesso a DB del framework (MetaService.*, scheduler, scaffolding, AsmxProxy CRUD, callback custom) consultano TenantScope.CurrentAziendaId via AsyncLocal, propagato dal middleware HTTP post-authenticate. Job background e callback custom dichiarano il tenant esplicitamente con using (TenantScope.Push(aziendaId)) { ... } quando partono fuori dal contesto di request.

Cache tenant-aware. Le chiavi Application[] server-side e i cache locali metadata vengono automaticamente suffissate per AziendaId quando il flag è attivo, evitando bleed di metadata tra tenant.

Login routing. Tabella _login_index(username_hash, id_azienda) sul DB primario mappa username → tenant per il fallback di MetaService.login: dopo autenticazione, il cookie k-user porta azienda_id come parte del payload e il middleware crea il TenantScope corretto a ogni richiesta successiva.

Scaffold propagation. L'azione "Scaffold tabella" propaga in modo idempotente le metadata della tabella a tutti i tenant elencati in Aziende. La propagazione gira con TenantScope esplicito su ogni target ed è idempotente: ri-eseguibile, applica solo le modifiche mancanti.

File preconfigurati nel pacchetto:

  • appsettings.multi-tenant.mssql.json / appsettings.multi-tenant.mysql.json — environment self-contained con 6 connection string esempio (1 primary + 5 tenant) e multiConnectionEnabled=true. Attivare con ASPNETCORE_ENVIRONMENT=multi-tenant.mssql.
  • dbms/scripts/multi_tenant_aziende_connessioni_mssql.sql / _mysql.sql — DDL per aggiungere le due colonne a Aziende su DB esistenti.

🗺️ Menu localizzabile in base alla lingua

Le voci di menu vengono ora tradotte dinamicamente seguendo la lingua dell'utente, senza bisogno di duplicare i record _metadati__menu per locale.

Architettura. Il campo mm_display_string_menu di _metadati__menu contiene una chiave stabile namespaced (menu.admin.roles, menu.crm.opportunities, menu.fleet.vehicles, ...). Il template del componente menu Angular applica la pipe translate su item.label e la chiave viene risolta runtime dal dizionario _wuic_translations filtrato per lingua corrente.

Schema chiave.

menu.<scope>.<slug>
   │       └── slug snake_case (es. column_styles, opportunities)
   └── scope = root | admin | demo | crm | fleet | invoice
  • menu.root.* — parent top-level (Amministrazione, Application, Home, ...)
  • menu.admin.* — 36 voci di sistema condivise (Ruoli, Designer, Stili colonna, Workflow Designer, ...)
  • menu.demo.* — demo content WideWorldImporters
  • menu.crm.* / menu.fleet.* / menu.invoice.* — voci specifiche del dominio del tenant

Vantaggio rispetto al modello precedente.

  • Il vecchio modello usava il testo italiano della label come chiave di traduzione (Aziende, Customers, Ruoli). Questo causava case-mismatch silenziosi (Ruoli vs ruoli, Stili Tabella vs Stili tabella) perché la pipe translate è case-sensitive, mentre _wuic_translations ha collation case-insensitive: ogni MERGE che entrava prima fissava la casing per sempre, e le INSERT successive case-divergenti diventavano no-op silenziosi.
  • Il nuovo modello con chiavi stabili è case-determinate (tutto lowercase per convenzione), namespacing per scope, e non collide più con altre risorse che potrebbero usare lo stesso testo italiano (es. button label "Ruoli" in un dropdown è una key diversa da menu.admin.roles).

5 lingue supportate. it-IT, en-US, fr-FR, es-ES, de-DE. Le traduzioni vivono in _wuic_translations (formato standard: language, resource, translation). Switch lingua dal dropdown utente in alto a destra rilegge il dizionario per la nuova lingua e ridipinge il menu senza F5.

Fallback runtime. Lingua corrente → en-US → it-IT → chiave raw. Se vedi menu.admin.roles letterale a schermo significa che la chiave non è stata seedata in nessuna delle 5 lingue.

Le vecchie chiavi italiane in _wuic_translations non vengono toccate dall'aggiornamento: possono essere consumate da altri punti dell'app (instant('Aziende') in code-behind, list-grid header, page title) e restano valide.


🐛 Bug fix degni di nota

  • Form di edit dinamici — Tab e widget nei template md_edit_template in production: in build di produzione i template HTML personalizzati associati a una route via md_edit_template non rendevano correttamente i Tab di PrimeNG 21 (le label apparivano come testo concatenato senza il chrome del componente) e i field-editor mostravano solo placeholder <!----> al posto degli input. Causa: il compilatore runtime usato dal framework per i template dinamici richiede l'enumerazione esplicita dei componenti standalone disponibili nel template, mentre MetadataProviderService.widgetDefinition.dynamicFormImports era incompleto. Aggiunti al baseline TabsModule + Tabs/TabList/Tab/TabPanels/TabPanel, FieldsetModule, DataRepeaterComponent, DataSourceComponent, ImageWrapperComponent. Nessuna azione richiesta lato app consumer una volta aggiornato il pacchetto wuic-framework-lib.

🎁 Free app pronte all'uso

Da questa release tre applicazioni complete sono distribuite gratuitamente sopra il framework — scaricabili dalla sezione "Free apps" della pagina Downloads:

  • CrmApp — CRM B2B self-hosted: anagrafica clienti, pipeline opportunità con kanban drag-and-drop, attività (call/meeting/email), dashboard role-based. (Leggi il post)
  • FatturazioneElettronica — Editor fatture FatturaPA v1.2, firma CADES-BES, validazione XSD, 4 provider SDI intercambiabili (DirectPec gratuito via PEC, ArubaPec / FatturePec / PecIt commerciali), conservazione a norma, registri IVA e liquidazione. (Leggi il post)
  • FlottaMezzi — Anagrafica mezzi/driver, scadenze automatiche (bollo / revisione / assicurazione / tagliando / patente), feed geolocation OBD/GPS, mappa live, aggregazione costi €/km per mezzo e per driver, reportistica TCO. (Leggi il post)

Ogni app è disponibile in tre formati: ZIP IIS con DB tutorial (pronto al restore), ZIP IIS senza DB, ZIP sorgenti.

Modello di licenza. Le free app sono GRATIS così come distribuite — il binario <App>.dll ZIP-ato porta una host-binding-license embedded che autorizza il runtime framework senza key esterne. Solo se si ricompila l'app dai sorgenti (per esempio per aggiungere un controller nuovo o modificare una signature pubblica) serve una licenza WUIC Developer o Professional: la ricompilazione produce un binario con identità diversa, perde il bundling, e il framework cade sul controllo licenza fingerprint standard.

Estendere le free app senza ricompilare il binario è coperto dal bundling: aggiunta metadata via SQL, componenti Angular nel wwwroot, job nella tabella scheduler, custom hook via appsettings.json:customCrudHookClass.


📦 Pacchetti aggiornati

Package Da 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

🔧 Aggiornamenti operativi raccomandati per chi aggiorna

  1. Per chi vuole attivare il multi-tenant (opt-in): applicare lo script DDL dbms/scripts/multi_tenant_aziende_connessioni_mssql.sql (o _mysql.sql) per aggiungere le colonne Connessione_DB_Dati e CONNESSIONE_DB_Meta ad Aziende. Popolare le righe Aziende con i nomi delle entry ConnectionStrings da appsettings.json. Settare AppSettings.multiConnectionEnabled = "true". Riavviare il backend.
  2. Per chi resta single-tenant: nessuna azione richiesta. Senza multiConnectionEnabled=true il routing tenant è disattivo e il comportamento è bit-identico alla 1.0.20.
  3. Menu localization — refresh metadata: dopo l'aggiornamento, eseguire una volta POST /api/Meta/AsmxProxy/MetaService.invalidateMetadataRuntime per ricaricare il dizionario menu lato client. In alternativa logout/login dell'utente.
  4. Menu localization — migrazione di un progetto esistente: per un progetto che parte da una versione precedente con etichette italiane in _metadati__menu.mm_display_string_menu, applicare due step SQL idempotenti: (a) UPDATE _metadati__menu SET mm_display_string_menu = '<menu.scope.slug>' WHERE mm_display_string_menu = '<vecchia etichetta>' per ogni voce, secondo lo schema menu.<scope>.<slug> documentato sopra; (b) INSERT/MERGE INTO _wuic_translations (language, resource, translation) 5 righe per ogni nuova chiave (una per lingua). Le vecchie righe in _wuic_translations con resource = testo italiano restano in DB e possono essere usate da altri consumer (instant(), list-grid headers).
  5. Hot reload backend in dev: se sviluppi con dotnet watch, il task backend: kill dll lockers ora richiede pwsh 7+ (non più Windows PowerShell 5.x). Lo script C# inline per Restart Manager usa sintassi Dictionary<,> corretta solo in PS 7+.

v1.0.20

Torna all'indice

Versione precedente pubblicata: 1.0.19 (4 maggio 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


Release di consolidamento dopo la 1.0.19, focalizzata su bug fix con impact diretto su editor e visualizzazione (INSERT con trigger INSTEAD OF, campi numerici azzerati al blur, calendar vuoto alla prima navigazione, preservazione SQL custom nei report) e su un giro di allineamento del componente mappa alle nuove API Google Maps: completamento delle opzioni dell'archetype map, migrazione a Routes API per lo snap-to-roads, rimozione della dipendenza dalla drawing library deprecata.


🐛 Bug fix degni di nota

  • INSERT con trigger INSTEAD OF: tabelle con trigger INSTEAD OF INSERT perdevano il PK ritornato dallo statement esterno (OUTPUT INSERTED.<pk> ritornava 0 o NULL perché il trigger dirottava l'INSERT). Fix: la INSERT generata da _Metadati_methods usa ora una table variable (@__inserted_pk con OUTPUT ... INTO) come canale primario e fallback a IDENT_CURRENT('<table>') quando il trigger consuma lo statement. Risolve anche il SQL Server msg 334 (OUTPUT INSERTED senza INTO non è ammesso su tabelle con trigger abilitati).
  • field-editor number — reset a 0 al blur: quando la colonna metadata aveva mc_min_value o mc_max_value valorizzati, il campo numerico veniva azzerato al blur invece di mantenere il valore digitato. Il guard di range scattava prima del round-trip di parsing, leggendo un valore intermedio non-numerico e collassando a 0. Comportamento corretto: il valore viene confermato e clampato sui limiti solo se effettivamente fuori range, altrimenti resta invariato.
  • Archetype map — opzioni completate: l'archetype del componente mappa ha tre nuove proprietà che chiudono gap UX comuni:
    • polyline — overlay polyline per tracciamento percorsi (record GPS storicizzati). Raggruppamento per campo (groupByField), ordinamento (orderByField), colore per record/per gruppo, opzionale snap-to-roads, dots waypoint distinti dal path interpolato.
    • clickableIcons — pass-through a google.maps.MapOptions.clickableIcons. Quando false, Google Maps non apre la propria info window built-in sui POI (negozi, fermate, indirizzi), che altrimenti intercettava i click destinati ai marker custom dell'app.
    • markerColorField — colore del PinElement letto da un campo del record (CSS #rrggbb). Ignorato se il record ha già una customMarkerImageSrcField valorizzata (immagine/SVG ha precedenza).
  • Google Maps Directions API — deprecato: DirectionsService è deprecato a partire dal 2026-02-25. Lo snap-to-roads delle polyline usa ora la nuova Routes API (google.maps.routes.Route.computeRoutes), con fallback automatico a DirectionsService legacy (funzionante fino al 2027-02-25) per key non ancora migrate. Travel mode legacy → routes mapping invariato (DRIVING/WALKING/BICYCLING). Batching automatico a 25 waypoint per chiamata.
  • Google Maps Drawing API — rimosso: la drawing library (google.maps.drawing) è deprecata dal 2025-08 e rimossa nelle versioni di Maps JavaScript API rilasciate da maggio 2026. La logica DrawingManager su MapListComponent era solo console.log stub (nessuna feature reale di disegno persistita) ed è stata rimossa. PointFilterComponent (filtro geo per area/cerchio nelle list-grid) è stato riscritto con click+mousemove handler manuali — stessa UX (poligono via click multipli, cerchio via centro+raggio, chiusura dblclick), indipendente dalla libreria deprecata.
  • Report — preservazione query SQL custom via sentinel __autogenerated: i report con SQL custom che alias-avano colonne non registrate nei metadata perdevano join/colonne perché la dynamic query auto-generata sovrascriveva la query utente. Fix cross-DBMS (MSSQL, MySQL, PostgreSQL, Oracle): ogni SELECT auto-generato inserisce ora 1 AS [__autogenerated] come prima colonna; la pipeline metadata riconosce il token a runtime e preserva la query custom quando il sentinel non è presente. Permette layout Stimulsoft che leggono colonne non registrate come metadata (tipico in template fatturazione/PEC dove il SQL deriva colonne computed).
  • Calendar — eventi non visibili alla prima navigazione: <wuic-scheduler-list> mostrava un calendario vuoto quando l'utente navigava direttamente a #/<route>/scheduler (l'inizializzazione di FullCalendar avveniva con data=[] prima della risposta async; un F5 lo popolava perché la cache di sessione consegnava i dati prima del mount). Fix: sincronizzazione esplicita degli eventi via API (removeAllEvents() + addEvent()) dopo il render del calendario, bypassando il binding [events]="data" non affidabile del wrapper FullCalendar 6.x Angular su update post-mount.

📦 Pacchetti aggiornati

Package Da 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

🔧 Aggiornamenti operativi raccomandati per chi aggiorna

  1. Eseguire dotnet ef database update se si è su EF migrations.
  2. Se si usa lo snap-to-roads sulle polyline mappa: verificare che la propria Google Maps API key abbia la Routes API abilitata oltre alla Directions API. Senza Routes API il framework cade sul legacy DirectionsService, che continua a funzionare ma è in finestra di deprecation (sunset 2027-02-25).
  3. Se si dipendeva dalla drawing toolbar standard di MapListComponent (zero use case noti, gli handler erano stub): la toolbar è stata rimossa. Nessuna azione richiesta per i filtri geo nelle list-grid — PointFilterComponent mantiene la stessa UX con implementazione interna.
  4. Per usare il nuovo overlay polyline su una route mappa: aggiungere a md_props_bag.archetypes.map.polyline la configurazione { enabled: true, groupByField, orderByField, ... } via designer o patch metadata.

v1.0.19

Torna all'indice

Versione precedente pubblicata: 1.0.7 (26 aprile 2026)
Backend: .NET 10 + IIS / Linux nginx
Frontend: Angular 21


In sei giorni di sviluppo intenso, WUIC compie un salto significativo: dal singolo deploy IIS Windows a una piattaforma multi-runtime (Windows + Linux nativo), con un sistema unificato di gestione errori tipizzati, crash reporting centralizzato, autenticazione LDAP, e un giro di hardening best-effort sulla superficie applicativa.


🛡️ Sicurezza

Best-effort hardening su tutta la superficie applicativa: throttling autenticazione, rinforzo headers HTTP standard (HSTS, CSP, X-Frame-Options, X-Content-Type-Options, Referrer-Policy), gestione environment-aware di CORS e Swagger, riduzione info disclosure nelle response di errore, gating granulare degli endpoint amministrativi, controlli aggiuntivi sul path SQL runtime. Le configurazioni di default sono ora più conservative anche per deploy demo/staging, con override esplicito disponibile via AppSettings.


🚨 Crash Reporting (end-to-end)

Nuovo sistema di crash reporting auto-installato che invia stack trace .NET + JavaScript a un receiver self-hosted.

  • Cattura passiva: le eccezioni unhandled vengono raccolte automaticamente, deduplicate via stack canonicalization e accodate async — nessun impatto sulla latency delle request.
  • Receiver privato: errors.wuic-framework.com accetta upload firmati con RSA license signature (zero API keys da gestire).
  • GDPR consent: opt-in esplicito gestito in AppSettings, configurabile dall'editor settings.
  • Attivazione: CrashReporting:Enabled=true in appsettings.json + consent GDPR via UI.

🐧 Linux deployment (nuovo)

WUIC è ora installabile su Ubuntu/Debian completamente automatizzato, con stack supportato:

  • .NET runtime + MSSQL Server o MySQL/MariaDB.
  • Python 3.12 + RAG environment.
  • Segreti via systemd credentials.
  • nginx reverse proxy con TLS Let's Encrypt.
  • Smoke test post-install che valida backend, RAG e proxy.

Il tarball Linux include appsettings.linux.mssql.json e appsettings.linux.mysql.json preconfigurati per i due stack supportati, più un README con la procedura passo-passo.


🔐 LDAP Authentication

Login WUIC ora supporta bind LDAP in alternativa al DB:

  • Configurazione tramite la sezione Authentication:Ldap:* in appsettings.json (server, base DN, bind template).
  • Auto-provisioning utenti: la riga locale viene creata/aggiornata al primo login con dati da LDAP.
  • Fallback DB: se LDAP è unreachable e Authentication:Ldap:FallbackToDbOnFailure=true, il login ricade sul DB tradizionale (admin/admin resta sempre raggiungibile per recovery).

Compatibile con Active Directory, OpenLDAP e directory Novell.


🗄️ Provider MySQL (Wuic.MySqlProvider 0.8.3)

Esteso supporto MySQL/MariaDB a paritá col primary MSSQL:

  • Coverage completo dei test funzionali (audit, CRUD client-side, concurrency, conditional styling, import-export, OData, retry, stored procedures, translations, validations).
  • Fix bug specifici Linux: collation default, JSON_TYPE quirks, paging hints.

🚦 Sistema unificato di errori (typed exceptions)

Refactor completo della gestione errori applicativi:

  • WuicException come base type per tutte le eccezioni applicative tipizzate (parte della public API del framework).
  • WuicErrorCodes: catalogo di 27 codici stabili (errors.auth.unauthenticated, errors.metadata.props_bag.malformed, errors.db.sql_exception, errors.report.render_failed, ecc.).
  • JSON envelope stabile per tutte le risposte di errore: { ok, errorCode, args, traceId, fallbackMessage }. Permette al client di mostrare messaggi localizzati invece di stack trace tecnici.
  • Traduzioni built-in IT/EN/DE/ES/FR/JA per tutti i codici noti.
  • Mapping automatico delle eccezioni runtime conosciute (SqlException, AuthenticationException, JsonException, ecc.) ai codici tipizzati.

📊 Export Excel

Riscrittura del path bulk export verso il formato .xlsx su pipeline producer/consumer e OpenXmlWriter streaming. L'impatto è soprattutto sui dataset grandi (decine di migliaia di righe in su).

  • Streaming OpenXML al posto del DOM-build incrementale: tipicamente 50× più veloce su export bulk, footprint memoria contenuto anche per dataset oltre il milione di righe.
  • Pipelining DB-read / xlsx-write su buffer limitato: la lettura del DB non si blocca più sul tempo di compressione del foglio.
  • Notifiche progress aggregate via canale dedicato: niente più una task per ogni update, eliminato lo storm WebSocket durante export lunghi.
  • Split automatico su più fogli quando il limite Excel di 1.048.576 righe per foglio viene superato. Il messaggio di completamento riporta il numero di fogli generati.

Nessuna azione richiesta: il path è attivo per default su tutti gli export .xlsx invocati dalla list-grid (toolbar Export XLS) e dalle API server-side.


🐛 Bug fix degni di nota

  • isSuperAdmin gating: corretta verifica permessi in più endpoint che precedentemente confondevano isAdmin (ruolo per-user) con isSuperAdmin (ruolo source of truth).
  • OData CRUD: corrette serializzazioni edge case (Decimal→string, DateTime UTC roundtrip, navigation properties).
  • First-run wizard: bootstrap iniziale ora consume correttamente IConfiguration (non più dipendenza da app.config legacy).
  • Crash reporting forwarding: bug 2026-04-28 risolto — le eccezioni MVC handled non bypassano più il middleware crash reporter.

📦 Pacchetti aggiornati

Package Da 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

🔧 Aggiornamenti operativi raccomandati per chi aggiorna

  1. Eseguire dotnet ef database update se si è su EF migrations.
  2. Verificare appsettings.json: il sistema legge ora anche AppSettings:AllowedOrigins (array string) e AppSettings:registrationEnabled (boolean kill-switch). Default sicuri se non specificati.
  3. Se si usa LDAP, configurare la sezione Authentication:Ldap:* in appsettings.json.
  4. Per deploy Linux: usare il tarball dedicato e seguire il README incluso.
  5. Per attivare crash reporting outgoing: settare CrashReporting:Enabled=true in appsettings.json + accettare consent GDPR via UI.