

Lagotto BI — Architettura e funzionamento tecnico
Lagotto BI legge da un gestionale su MSSQL, sincronizza i dati su un database MariaDB interno ogni 5–15 minuti, e li espone tramite dashboard drag&drop configurabili senza scrivere codice. Il tempo che separa “non ho ancora collegato il gestionale” da “ho una dashboard con dati reali” si misura in passaggi di wizard, non in settimane di sviluppo custom.
Stack tecnico
| Componente | Tecnologia |
|---|---|
| Backend | FastAPI (Python 3.11+), SQLAlchemy 2.x async, MariaDB |
| Connettore sorgente | pymssql — solo lettura, mai scrittura sul gestionale |
| Sync | APScheduler — incrementale 5–15 min, full sync notturno zero-downtime |
| Frontend | Vue 3 + Vite + TypeScript, Pinia |
| Grafici | Apache ECharts (tree-shaken, solo i moduli usati) |
| Tabelle / Pivot | Tabulator 6 / pivottable.js |
| Isolamento | Schema MariaDB dedicato per tenant — nessun dato condiviso tra clienti |
Tempi reali di configurazione
Ogni passaggio ha un test o un’anteprima integrata. Non si salva mai alla cieca.
| Passaggio | Cosa succede | Tempo tipico |
|---|---|---|
| 1. Connessione al gestionale | Wizard 5 step: host, porta, credenziali, schema registry, test di connessione live prima di salvare | 3–5 minuti |
| 2. Mappatura schema | Mapper Builder: wizard visivo campo→campo, trasformazioni predefinite, test con anteprima di 50 righe reali prima di salvare | 10–20 minuti per tabella la prima volta — istantaneo su schema già certificato |
| 2b. Import tabella intera | Wizard 3 step: tabella MSSQL → staging MariaDB, senza mappatura campo per campo | 2–3 minuti |
| 3. Prima sincronizzazione | Automatica — incrementale ogni 5–15 minuti, configurabile per datasource | Dati disponibili entro 15 minuti |
| 4. Prima dashboard | Griglia drag&drop, ogni widget con anteprima live durante la configurazione | 1–2 minuti per widget |
| 5. Filtri e drill-through | Wizard filtri con propagazione automatica cross-vista | 2–3 minuti per filtro |
Da gestionale non ancora collegato a dashboard con dati reali: l’ordine di grandezza è la mezz’ora, non il ciclo tipico analisi-preventivo-sviluppo-collaudo di un progetto BI custom.
Motore di aggregazione
La differenza che si vede meno ma pesa di più: l’aggregazione avviene sul database, non nel browser. Un grafico con Top 10 + “Altro” su una vista da centinaia di migliaia di righe non scarica quelle righe nel browser per poi tagliarle in JavaScript — il backend esegue GROUP BY + SUM con l’ordinamento già applicato, e restituisce solo le righe che verranno disegnate.
GET /api/data/v_fatturato_mensile ?_top_n_x=mese&_top_n_y=totale&_top_n=10&_raggruppamento=regione_cliente-- generato dal backend, parametrizzato — mai interpolazione di stringaSELECT mese, regione_cliente, SUM(totale) AS totaleFROM v_fatturato_mensileWHERE anno = :annoGROUP BY mese, regione_clienteORDER BY SUM(totale) DESCIl widget Pivot (PRO) segue la logica opposta quando serve: dati grezzi senza LIMIT, aggregati client-side da pivottable.js. Verificato su 100.576 righe reali con € 21.142.336 sommati in tempo reale mentre l’utente trascina i campi.
Una cache in memoria (TTL 60 secondi, per utente) evita che un cambio di tab o un doppio clic sul filtro rigeneri la stessa query due volte.
Catalogo widget
Sette tipi di widget, tutti configurabili da pannello — nessuno richiede JSON scritto a mano.
| Widget | Tier | Cosa fa | Cosa lo distingue |
|---|---|---|---|
| KPI | FREE | Valore singolo con confronto periodo precedente e formattazione automatica | Delta periodo su periodo calcolato automaticamente |
| Bar / Line | FREE | Grafici a barre e linee, singola o multi-serie | Multi-serie retrocompatibile |
| Bar — varianti | FREE | Barre impilate, orizzontali, valori sopra/accanto | Configurabili a checkbox |
| Pie / Donut | FREE | Valore assoluto, percentuale o entrambi; Top-N con voce “Altro” | Aggregazione server-side |
| Table | FREE | Tabulator con paginazione, ordinamento, colonne aggregate | Formattazione automatica per colonna |
| Combo | PRO | Serie miste barre + linea, doppio asse Y | Ogni serie sceglie asse, tipo e colore indipendentemente |
| Pivot | PRO | Pivot interattiva su dati grezzi, righe × colonne trascinabili | Nessun limite righe lato backend; export Excel con un click |
Esempio: grafico combinato
{ "tipo": "combo", "titolo": "Fatturato vs margine", "vista": "v_marginalita_mensile", "asse_x": "mese", "serie": [ { "campo": "fatturato", "etichetta": "Fatturato", "tipo": "bar", "asse_y": "sx", "colore": "#4a90d9" }, { "campo": "margine_pct", "etichetta": "Margine %", "tipo": "line", "asse_y": "dx", "colore": "#e85d4a" } ]}Questo blocco JSON — generato dal Widget Builder, mai scritto a mano — è tutto ciò che serve per un grafico che in molti strumenti BI richiede una vista SQL dedicata più configurazione manuale del secondo asse.
Azioni e drill-through
Ogni widget può reagire a un click. Lo stack di drill-through è ricorsivo — un clic dentro un modal aperto da un clic precedente apre un terzo livello, con breadcrumb per tornare indietro. Configurabile da pannello, non da codice.
| Azione | Comportamento |
|---|---|
open_table / open_bar / open_pie / open_line / open_pivot | Apre un modal fullscreen con il widget scelto, filtrato sul valore cliccato |
open_cliente | Naviga a una dashboard specifica, pre-filtrata sul cliente selezionato |
filter_dashboard | Applica un filtro globale a tutta la dashboard corrente |
Mapper Builder e Query Manager
Ogni gestionale ha un file JSON che mappa le proprie tabelle allo schema standard di Lagotto:
{ "gestionale": "custom_erp", "tabelle": { "FATT_TESTATE": { "vista_target": "v_fatturato_mensile", "colonne": { "DATA_DOC": { "target": "data_fattura", "tipo": "date" }, "COD_CLI": { "target": "cod_cliente", "tipo": "string" }, "TOT_DOC": { "target": "fatturato", "tipo": "decimal", "display": { "tipo": "currency", "simbolo": "€", "decimali": 0 } } } } }}Sei trasformazioni predefinite coprono i casi che normalmente finiscono in uno script scritto a mano:
simple— copia direttamap— lookup a dizionariolookup— tabella esterna (es. provincia→regione)coalesce— primo valore non nullo tra più campiconcat— concatenazionearitmetico— somma/sottrazione tra campi
Il campo display propaga automaticamente la formattazione fino al widget finale senza configurarla una seconda volta.
Query Manager (View Builder, PRO): editor SQL con pannello delle tabelle di staging disponibili. Una vista creata qui è disponibile nel Widget Builder immediatamente — nessun riavvio del backend, nessun deploy.
-- margine per categoria, calcolato in una vista customCREATE OR REPLACE VIEW v_margine_categoria ASSELECT categoria, SUM(ricavo) AS ricavo_totale, SUM(costo) AS costo_totale, ROUND((SUM(ricavo) - SUM(costo)) / NULLIF(SUM(ricavo),0) * 100, 1) AS ricarico_pctFROM raw_fatturatoGROUP BY categoriaSicurezza e isolamento multi-tenant
- Whitelist vista obbligatoria: l’endpoint dati accetta solo viste nella whitelist esplicita — nessuna query arbitraria dal frontend
- Query sempre parametrizzate: mai interpolazione di stringa, anche per nomi colonna con spazi o caratteri accentati
- Filtro agente forzato lato server: un utente con ruolo
agentevede solo i propri dati — il filtro è applicato nel backend, non aggirabile dal frontend - Schema per tenant: ogni cliente ha un proprio schema MariaDB (
lagotto_{slug}) — zero dati condivisi, zero query cross-tenant possibili per costruzione - Profilazione granulare per utente: un admin può restringere dashboard, tab, widget e filtri permanenti per singolo utente — filtrato server-side
Piani e licenza
| Piano | Dashboard | Widget Builder | Pivot / Combo | Datasource | Utenti | Prezzo |
|---|---|---|---|---|---|---|
| Starter | 10 standard | — | — | 1 | 1 | Sempre gratuito |
| Professional | Illimitate | ✓ | ✓ | 3 | 5 | Dinamico — vedi listino |
| AI | Illimitate | ✓ | ✓ | Illimitati | >100 | Su richiesta |
Il limite utenti è verificato server-side a ogni creazione. Il piano viene ri-verificato live contro il License Server ogni 30 minuti — revoche e upgrade si propagano senza riavviare nulla. I prezzi mostrati all’utente sono letti in tempo reale dal License Server, non un numero fisso nel codice.
Velocità — numeri, non aggettivi
| Metrica | Valore |
|---|---|
| Sync incrementale | 5–15 minuti, configurabile per datasource |
| Downtime full sync notturno | Zero — tabella-ombra + RENAME TABLE atomico |
| Cache dati per widget | 60 secondi per utente, invalidata sul cambio filtro |
| Righe aggregate in pivot | 100.576 righe reali verificate |
| Valore sommato in tempo reale | € 21.142.336 |
| Latenza propagazione cambio piano | 30 minuti massimo |
Roadmap dichiarata
Non ancora in produzione:
- Query Manager esteso: materializzare il risultato di una query in una tabella di staging, non solo in una vista calcolata a ogni lettura — per join pesanti su milioni di righe
- Libreria di mapper certificati: esportare/importare uno schema di mappatura collaudato tra installazioni diverse dello stesso gestionale
- Import/export dashboard complete: layout, widget e filtri come file esportabile, riutilizzabile come punto di partenza per un nuovo cliente
Documento tecnico — Lagotto BI. Le funzionalità in roadmap non sono ancora disponibili in produzione.
Fonti
Autore: Giantommaso Fogli
Data Pubblicazione: 2026-07-09
Diritti e attribuzioni
Immagini, loghi e fotografie sono di proprietà dei legittimi titolari. Utilizzati per finalità di commento.
← Back to journal