Ogni strumento, in un solo posto
Questa pagina è il reference pratico per ogni strumento nella sidebar del tuo ambiente Archestack. Ogni sezione copre cosa fa lo strumento, quando lo useresti, i passi per i workflow più comuni e le trappole in cui inciampano i nuovi utenti. La sezione finale (API chiamabili dagli script) documenta l'esatta superficie che gli script possono chiamare.
Schema Designer
Un editor visuale per lo schema del database, tabelle, colonne, tipi, relazioni, indici, che si salva automaticamente su un documento JSON. Lo schema è la fonte di verità per la tua applicazione; nessun altro strumento vede una colonna finché non la aggiungi qui e ne fai il deploy.
Workflow comune: nella toolbar, fai clic su Add Table (pulsante
icona). Si apre un dialog intitolato "Create New Table"; digita un nome (il testo di aiuto
ti ricorda "Lowercase with underscores recommended"), fai clic su Create. La
tabella compare sul canvas con una primary key SERIAL id auto-generata. Seleziona
la tabella, il pannello destro si apre sulla tab Columns. Aggiungi colonne dal
box "Add column" con bordo tratteggiato in basso (campo nome, dropdown Type, fai clic su
Add Column). Fai clic su ogni colonna per espanderla e regolare i toggle
(PK, NULL, UQ), Length e Default value.
Tipi di colonna disponibili nel dropdown Type: SERIAL, BIGSERIAL, INTEGER, BIGINT, SMALLINT, DECIMAL, NUMERIC, REAL, DOUBLE PRECISION, VARCHAR, CHAR, TEXT, BOOLEAN, DATE, TIME, TIMESTAMP, TIMESTAMPTZ, UUID, JSON, JSONB, BYTEA, INET, CIDR, MACADDR, MONEY, INTERVAL, più i tipi geometrici e array. La Length è rilevante solo per VARCHAR e CHAR.
Le foreign key stanno nella tab Relations del pannello destro (non "Relationships"). Scorri fino a "Add relationship": scegli la colonna FK sulla tabella corrente, il tipo di relazione (One-to-One / One-to-Many / Many-to-Many), la tabella di riferimento, la colonna di riferimento, poi fai clic su Add Relationship. Ogni relazione ha i dropdown On Delete e On Update (CASCADE / SET NULL / SET DEFAULT / RESTRICT / NO ACTION).
Auto-save: l'indicatore in basso a sinistra oscilla tra "Auto saving..." e "Saved". C'è anche un pulsante Save nella toolbar (abilitato solo quando ci sono modifiche in attesa) per i salvataggi espliciti.
Altri pulsanti della toolbar: Add Group (container visuali per tabelle correlate, pannello proprietà intitolato "Group"), Add Text (annotazioni libere, pannello proprietà intitolato "Text Annotation"), controlli di zoom, filtro package, ricerca tabelle.
Trappole: rinominare una colonna produce un piano distruttivo (drop + add):
modifica l'SQL nella tab Generated SQL del deployment per usare RENAME COLUMN
se vuoi preservare i dati. Aggiungere una colonna NOT NULL a una tabella non vuota senza
un default fallisce, rendila nullable, fai il backfill, poi altera. Il pulsante toolbar
Deploy ti porta su una pagina di configurazione del deployment, non direttamente nel deploy.
Database Deployments
Elenca ogni deployment con il suo stato (Draft / Executing / Succeeded / Failed) e ne lancia
di nuovi. Route: /database-deployments/overview.
Pulsanti in alto a destra: Refresh (ricarica la lista), New Deployment (crea una nuova bozza).
Da Schema Designer: il pulsante verde Deploy con icona razzo nella
toolbar di Schema Designer ti porta a /database-deployments/configure/new, una
pagina di configurazione deployment nuova.
Pagina di configurazione del deployment: due tab.
- Configuration - editor per gli script pre/post deployment (PostgreSQL) ciascuno con un pulsante Test Run. Il pre-script gira prima dei cambi di schema; il post-script dopo. Utili per backfill, ricostruzione di indici o pulizia di staging area. Più un toggle Force Deploy (Allow Data Loss) per operazioni distruttive.
- Generated SQL - mostra la migration prodotta dalla piattaforma. L'SQL è modificabile. Un pulsante Regenerate (icona refresh) riesegue il diff se hai fatto cambi di schema da quando hai aperto questa pagina.
Pulsanti in alto: Back, Save (salva la configurazione come Draft), Deploy (esegue il deployment immediatamente). Deploy è quello che clicchi alla fine.
Trappole: i deployment non vengono automaticamente avvolti in una transazione,
un fallimento a metà strada lascia il database in uno stato parziale. Per le migration
rischiose, avvolgi le tue istruzioni in BEGIN; ... COMMIT; nel pre-script. Il
toggle Force Deploy salta i controlli di sicurezza; usalo in modo deliberato.
Business Entities
Viste curate costruite su una master table più join da tabelle correlate. Le pagine si collegano alle Business Entities, mai a tabelle raw. Vedi Concetti -> Business Entities per il perché.
Workflow comune: fai clic su Create. Si apre l'editor a tutta pagina con le tab Visual, JSON, Events. Imposta Entity Name, Master Table (Autocomplete), e Label Column (la colonna il cui valore rappresenta un record nei picker). Salva, la BE auto-genera una lista di colonne native dalla master table.
Aggiungere join: scorri fino alla card del Join Configurator e fai clic su Add Join. Ogni join si apre come un Accordion con: Join Type (INNER / LEFT / RIGHT), From Table, To Table (Autocomplete raggruppato per Database Tables / Third Party), From Column, To Column, dropdown opzionali Type Cast, e un picker di colonne per quali colonne target esporre.
Aggregazioni: su un join, sposta Aggregate Mode. Per ogni colonna scelta poi scegli una Aggregate Function: COUNT / SUM / AVG / MIN / MAX / COUNT DISTINCT. "Numero di contatti aperti su questa Company" è l'esempio canonico.
Run Preview: l'editor ha un pulsante Run Preview (con un'icona play) che esegue la configurazione completa dei join e mostra righe reali in una griglia dati. Se una colonna joined torna vuota, la colonna non era spuntata nel picker delle colonne del join (o la relazione è mal configurata).
Più BE per master table: niente ti impedisce di avere
customer (sales view) e customer (support view) sulla stessa
master. Pagine diverse, colonne appropriate per pubblici diversi, stessa riga sottostante.
Trappole: le colonne joined e aggregate sono read-only. Per modificare l'etichetta joined, vai al record sorgente. Le colonne aggregate vengono ricalcolate a ogni query, va bene per centinaia di righe, lente su milioni.
Page Editor
Configura la UI runtime collegando una Page a una Business Entity. La piattaforma auto-genera le sezioni in base alle colonne della BE; tu raffini il layout da lì. Non c'è un "template picker" separato, ogni pagina parte dalla stessa baseline generata e tu la personalizzi.
Workflow comune: fai clic su Create. Compila Page Name,
Page Route (es. /companies), scegli la Business Entity
(Autocomplete). La pagina si apre nell'editor con le tab Visual, Overview,
Create, Entities, Events, JSON. Aggiusta il layout
auto-generato, poi sposta lo Switch Published nell'header in alto su ON.
Tipi di widget di campo (il Select Type su ogni campo): Text,
Textarea, Number, Date, Select, Checkbox, Email. Usa Select per i campi
foreign key e imposta l'autocomplete Entity del campo sulla BE referenziata così
gli utenti scelgono per label.
Tab nel form di dettaglio: fai clic su Add Tab nella tab Visual.
Dentro una tab puoi aggiungere una sezione RelatedGrid collegata a un'altra BE
filtrata per PK del record corrente. Esempio classico: una pagina Company con tab
"Contacts" e "Deals", ciascuna filtrata per company_id = current company's id.
Pulsanti azione nell'inspector Header del form di dettaglio. Fai clic su Add nella sezione Actions. Ogni azione ha Label, Icon (Save / Delete / Add / Refresh / Download / Bolt / None), Variant (Contained / Outlined / Text), Color (Primary / Secondary / Error / Success / Warning / Info), e Steps (una lista ordinata di: Save Record, Delete Record, Navigate, Business Events, Custom). Per eseguire un Business Event da un pulsante, imposta il tipo di step su Business Events e scegli l'event per nome.
Pubblicazione: lo Switch Published nell'header in alto è l'unico controllo di pubblicazione. ON = la pagina appare sotto Published Pages nella sidebar e gli utenti finali che navigano alla sua route la vedono. OFF = bozza (solo tu nell'editor vedi le tue modifiche).
Trappole: le colonne auto-generate su una Page fresca rispecchiano la BE, se la BE cambia (aggiungi un join), la Page non prenderà automaticamente le nuove colonne. Ricarica la pagina nell'editor o aggiungi la colonna manualmente alla sezione. Attualmente non c'è un tipo di step azione "Generate PDF", per collegare un PDF a un pulsante di pagina, esponi il PDF tramite uno Script Module che chiama l'endpoint REST e usa uno step Custom (oppure chiama l'endpoint direttamente da un Frontend Template).
Business Events
Regole che scattano sui cambi di dati (o su pianificazione, o manualmente) ed eseguono action quando le condizioni sono soddisfatte. Il meccanismo "quando succede X, fai Y" della piattaforma. Vedi Concetti -> Business Events per il modello.
Workflow comune: fai clic su Create. Imposta Rule Name, sposta Enabled. Scegli Business Entity. Spunta uno o più Triggers: BeforeCreate / BeforeUpdate / AfterCreate / AfterUpdate / BeforeDelete / OnSchedule / Manual / InitialValue. Costruisci l'albero di condizioni (gruppi AND/OR). Aggiungi una o più action nel FlowCanvas. Salva.
Tipi di action (RuleActionKind):
- Execute Script - esegue uno script C#. L'action più flessibile; usala ogni volta che vuoi impostare un campo, fare un calcolo, chiamare un'API, qualsiasi cosa custom. Lo script riceve
Entity(mutalo su trigger Before* per cambiare la scrittura in corso),OldEntity,Log,Db,Modules. - Validate - uno script che ritorna
bool.truesignifica che la validazione fallisce e il salvataggio è bloccato con il messaggio di errore configurato. Opzionalmente evidenzia colonne specifiche tramite errorColumns. - Block Operation - ferma duramente l'operazione con un messaggio configurato. Niente script.
- Create Entity - inserisce un record in un'altra BE. I valori dei campi supportano template expression come
{{ Entity.column_name }}e{{ now() }}. - Update Entity - aggiorna record in un'altra BE che matchano un filtro di condizione. Stesse template expression.
- Delete Entity - elimina record che matchano una condizione. Rifiuta di scattare senza una condizione (sicurezza).
- Send Email / Send Webhook / Publish Event - definite nello schema come miglioramenti futuri; attualmente loggate e saltate.
Pattern "imposta un campo": non c'è un'action discreta Set Field.
Il modo per impostare un campo è un Execute Script su un trigger Before* che muta
Entity. Esempio: Entity.title = ((string)Entity.title)?.Trim();. La
piattaforma persiste l'Entity modificato come parte della scrittura in corso, nessuna query
extra, nessun rischio di ricorsione.
Run Simulation: la tab Simulate dell'editor di trigger ha un picker di record e un pulsante Run Simulation. La piattaforma esegue le tue condizioni e action contro il record scelto senza persistere modifiche, le operazioni di scrittura girano in una transazione che viene rollback. Il pannello di output mostra quali condizioni hanno matchato e cosa avrebbe fatto ogni action. Usalo per beccare configurazioni sbagliate prima che i dati live le incontrino.
Template expression nella configurazione delle action usano parentesi
{{ ... }}. I token effettivi:
{{ Entity.column }},
{{ OldEntity.column }},
{{ now() }} / {{ getdate() }},
{{ today() }},
{{ guid() }} / {{ newid() }},
{{ year() }},
{{ month() }},
{{ day() }},
{{ timestamp() }},
aggregati come {{ SUM(column) }} dentro contesti di join,
e aritmetica post-sostituzione come {{ Entity.quantity * Entity.price }}.
Non c'è un token {{ user.email }}.
Operatori di condizione: Equals, NotEquals, GreaterThan, LessThan, GreaterThanOrEqual, LessThanOrEqual, Like (= ILIKE), Contains (= ILIKE %value%), IsNull, IsNotNull, In (= ANY(...)).
Trappole: un trigger che muta lo stesso record che osserva si rilancerà
da solo se usi Update Entity; usa invece Before Update +
Execute Script + Entity.field = .... Due trigger sullo stesso event
scattano in ordine di priorità. Gli event disabilitati appaiono comunque nella lista, il
toggle Enabled è separato dalla config del trigger.
Script Modules
Script C# riutilizzabili compilati a runtime da Roslyn. Prendono parametri, interrogano il
database tramite l'helper Db, ritornano un valore. Chiamabili da Business
Events, Scheduled Events, e direttamente dal front end.
Workflow comune: fai clic su Create. L'editor si apre con le tab
Edit, Parameters, Test, JSON. Nomina il modulo
(PascalCase, es. RecalcOpenRevenue). Nella tab Parameters, fai clic
su Add per parametro (Name, Type, Required, Default Value). Opzioni di Type:
string, int, decimal, double, bool, DateTime. Torna alla tab Edit, scrivi C#.
IntelliSense è attivo.
Pannello Test: la tab Test mostra gli input dei parametri a sinistra e un pulsante Run (icona PlayArrow). Fai clic su Run; il lato destro mostra un indicatore di successo o errore, log di output, e il valore di ritorno (formattato JSON).
L'helper Db, vedi il reference completo in API chiamabili dagli script sotto.
Chiamare da un Business Event: aggiungi un'action Execute Script il cui corpo chiama il modulo:
await Modules.CallAsync("RecalcCompanyOpenDealValue", new Dictionary<string, object?> {
["company_id"] = Entity.company_id
}); Chiamare da uno Scheduled Event: crea un event con il trigger
On Schedule, imposta il cron, aggiungi un'action Execute Script con lo
stesso corpo Modules.CallAsync.
Logging: ogni invocazione scrive una voce in Event Logs con tempo di esecuzione, parametri, e risultato (o errore).
Trappole: sempre await le chiamate Db, dimenticarlo compila
ma ritorna un Task. I ritorni sono passati per oggetto (non serializzati JSON dal
framework); per il consumo front-end, ritorna oggetti anonimi con campi primitivi. La
suggestion-on-commit-character è disabilitata di proposito nell'editor; usa Tab per accettare.
Frontend Templates
Frammenti UI riutilizzabili scritti in TSX che il page editor può inserire in una pagina. Utili quando i template configurati non bastano, grafici su misura, layout insoliti, integrazioni con widget di terze parti.
Workflow comune: fai clic su Create, nomina il template, scrivi
un componente TSX nell'editor. Il componente riceve props: record (la riga
corrente quando incorporato in un form di dettaglio), refresh (ri-recupera i
dati), e qualche helper. Salva. Referenzia il template da un campo del Page Editor.
Pacchettizzabile: i template fluiscono attraverso il sistema Package come qualsiasi altro oggetto config, vengono inclusi in cascading quando una pagina che li usa viene aggiunta a un package.
Trappole: il TSX è in sandbox, non puoi importare pacchetti npm arbitrari. Attieniti a React + gli helper forniti.
PDF Templates
HTML + template Scriban + un piccolo data script C# che renderizza in un PDF (Chromium headless). Ogni template è invocabile per nome da uno script via REST o direttamente da un pulsante su una Page (con un piccolo adattatore, vedi sotto).
Workflow comune: fai clic su + Create. L'editor si apre con i campi testo Name e Description in alto, cinque tab sul lato sinistro (HTML Template, Data Script, Settings, Params, JSON), e un pannello PDF Preview sempre attivo sulla destra. Le tab Data Script e HTML Template aprono ciascuna un editor Monaco sulla metà sinistra; l'anteprima si rigenera quando salvi (pulsante verde Update in alto a destra).
Dichiara i parametri nella tab Params tramite il pulsante + Add (Name, Type, Required, Default Value). L'etichetta della tab si aggiorna a Params (n) con il conteggio. Page format / orientation / margins / scale / header / footer vivono nella tab Settings.
Forma del data script (vedi tutorial PDF Invoices per uno reale):
var deal = await Db.GetAsync("deal", deal_id);
var lines = await Db.From("deal_line")
.Where("deal_id", "=", deal_id).ToListAsync();
return new {
InvoiceNumber = $"INV-{deal.id:D6}",
Lines = lines.Select(l => new { l.description, l.quantity })
}; Forma del template HTML (Scriban, simile a Liquid/Handlebars):
<h1>{{ InvoiceNumber }}</h1>
<table>
{{ for line in Lines }}
<tr><td>{{ line.description }}</td><td>{{ line.quantity }}</td></tr>
{{ end }}
</table> Pannello di anteprima: sempre visibile sul lato destro dell'editor. Si rigenera quando salvi (pulsante verde Update). Include una colonna di thumbnail per i PDF multi-pagina e una toolbar di viewer integrata (zoom, ruota, download, stampa). I pulsanti icona in alto a destra dell'editor alternano la visibilità del pannello di anteprima e l'editing a tutto schermo.
Chiamarlo da fuori dall'editor:
POST /api/v1/pdf-templates/{id}/preview- renderizza per ID, ritornaapplication/pdf. Usato dal pannello di anteprima dell'editor.POST /api/v1/pdf-templates/generate/{name}- renderizza per nome, ritornaapplication/pdf.POST /api/v1/pdf-templates/generate/{name}/base64- stesso ma ritorna{ "data": "<base64>" }.
Passa i valori dei parametri nel body JSON. L'auth è il Bearer token standard.
Limitazione del trial: sia l'endpoint generate sia l'endpoint
{id}/preview (usato dal pannello di anteprima dell'editor) ritornano
403 nella modalità trial, il rendering PDF è interamente disabilitato. Puoi comunque
creare il template (data script, HTML, settings, parametri) e salvarlo; semplicemente non
vedrai un PDF renderizzato finché non sei su un ambiente a pagamento.
Nota sul rendering chiamabile da script: il contesto di scripting C# non
espone un globale Pdf. Per renderizzare un PDF da uno Script Module oggi,
chiama l'endpoint REST generate tramite HttpClient. (L'autocomplete
dell'editor di script reclamizza Pdf.RenderAsync per la forward compatibility;
il binding runtime non è ancora cablato.)
Trappole: Scriban fa l'escape dell'HTML di default. I page break sono
guidati dal CSS, page-break-before: always su una sezione. I font disponibili
sul server di rendering sono limitati ai font di sistema più le famiglie Noto e Liberation,
incorpora i tuoi via @font-face base64 se ti serve un font di brand.
Scheduled Events
Lo stesso sistema di Event Trigger dei Business Events, con il trigger On Schedule spuntato. Usalo per ricalcoli notturni, digest settimanali, pulizie periodiche, report mensili.
Workflow comune: crea un Business Event con il trigger On Schedule
(invece di, o in aggiunta ai, trigger di cambio dati). Configura l'espressione cron.
Aggiungi un'action Execute Script il cui corpo invoca uno Script Module via
Modules.CallAsync(...).
Espressioni cron: in stile Quartz a 6 o 7 campi, vedi Concetti -> Scheduled Events per i pattern comuni. Gli orari sono il server time (UTC sullo stack di produzione).
Trappole: un job lungo che eccede il suo intervallo cron non si raddoppia, Quartz non fa scattare una seconda istanza dello stesso job in concorrenza, il secondo tick viene saltato. Le esecuzioni fallite non riprovano automaticamente; costruisci il retry nello script.
Packages
Bundle esportabili di oggetti di configurazione (BE, pagine, event, script, template, schema) con dipendenze in cascading. Aggiungere una Page a un package porta automaticamente tutto ciò che quella pagina referenzia.
Workflow comune (export): fai clic su Create, nomina e versiona il package. Aggiungi gli oggetti di livello superiore che ti interessano, di solito una manciata di pagine. Apri il pannello degli item collegati per vedere la lista in cascading (cosa conterrà effettivamente il package). Despunta qualsiasi cosa tu voglia omettere. Decidi se includere i dati (toggle all'export). Fai clic su Export, ricevi uno ZIP.
Workflow comune (import): sull'ambiente di destinazione, apri Packages, fai clic su Import, carica lo ZIP. La piattaforma mostra cosa sarà aggiunto o aggiornato. I delta di schema non sono auto-applicati, se il package referenzia una colonna che non esiste sulla destinazione, l'import fallisce.
Trappole: gli identificatori sono per nome, non per ID numerico. Una BE chiamata "customer" sulla sorgente si collega a una BE chiamata "customer" sulla destinazione, rinomina da una delle due parti e il link si rompe.
Third-Party Data Connections
Connessioni a database esterni (Postgres, SQL Server, MySQL, altri) che importano tabelle su pianificazione. Le tabelle importate si comportano come tabelle native, appaiono in Schema Designer e possono essere referenziate da Business Entities, Pages, e Scripts.
Workflow comune: crea una connessione (stringa di connessione, test, salva). Elenca le tabelle remote disponibili; scegli quali importare. Per ogni tabella importata, imposta la modalità di sync (Full / Delta) e il trigger di sync (cron / manuale / intervallo fisso).
In mirror, non federata: i dati importati vivono nel tuo
omnicore-db. Le letture sono veloci (Postgres locale). Compromesso:
obsolescenza tra i sync.
Colonne gestite dall'app: marca alcune colonne come "managed by Archestack", non saranno sovrascritte dai sync futuri. Utile quando vuoi annotare dati del vendor con i tuoi flag di stato.
Trappole: il primo sync di una tabella grande può richiedere un po' di
tempo. I sync delta richiedono una colonna che il connettore può usare come watermark, di
solito un timestamp modified_at.
AI Assistant
Un assistente chat integrato nell'app che può sia rispondere a domande sui tuoi dati sia modificare il tuo ambiente. Chiedi "quanti ordini di lavoro aperti per sede questo mese?" e interroga e risponde. Chiedi "aggiungi una colonna stato agli appuntamenti di servizio e una pagina per elencarli" e, se sei amministratore, lo costruisce.
Porta il tuo modello. Archestack non include alcun LLM e non paga alcuna inferenza. Un amministratore aggiunge un provider nella schermata AI Configuration: una base URL, un nome di modello e una chiave API. Funziona tutto ciò che parla l'API chat-completions di OpenAI (ChatGPT, DeepSeek, OpenRouter, Groq, Together, un Ollama o vLLM self-hosted), e l'API nativa di Anthropic è supportata direttamente. Puoi configurarne diversi e sceglierne uno per conversazione.
Tutto ciò che fa passa dall'MCP Server. L'assistente non ha una porta di servizio privata verso la piattaforma, chiama gli stessi tool di qualsiasi client MCP esterno, con la tua identità. I limiti che imposti lì valgono quindi anche per lui, e ogni azione finisce nello stesso audit log. Vedi MCP Server qui sotto.
Workflow comune: apri l'assistente dalla sidebar o dalla bolla fluttuante. Chiedi in una o due frasi. Legge il tuo schema attuale prima di proporre qualcosa, dice cosa sta per cambiare e aspetta la tua conferma. Ogni chiamata a un tool appare sotto la risposta, così vedi cosa ha fatto davvero.
Funziona bene per: domande estemporanee sui tuoi dati, funzionalità in forma CRUD, automazioni semplici, estensioni di entity esistenti.
Meno bene per: regole di business non ovvie e workflow multi-step complessi. Tratta ciò che costruisce come la PR di uno junior dev.
Trappole: lavora su dati di produzione e non c'è undo, quindi fai un backup prima di qualcosa di rischioso. I tuoi prompt e ciò che i tool restituiscono vengono inviati al provider che hai configurato, secondo le sue condizioni; puntalo su un modello self-hosted se la cosa conta. Le conversazioni lunghe ripropongono solo i turni più recenti, quindi una chat lasciata aperta tutto il giorno non ne ricorda l'inizio. E nota i due interruttori: con l'MCP Server fermo l'assistente può ancora parlare, ma non può leggere né cambiare nulla.
MCP Server
Ogni ambiente può esporsi tramite il Model Context Protocol, così che un client AI esterno ad Archestack, Claude Desktop, Claude Code, ChatGPT deep research, un IDE o un tuo script, possa lavorarci direttamente. È anche ciò su cui gira l'AI Assistant integrato.
Spento di default, e i tool che cambiano come è costruita l'applicazione restano spenti anche dopo averlo avviato. È deliberato.
Tre gruppi di tool. Read copre l'elenco e la descrizione delle entity, l'interrogazione delle righe e la lettura di schema, pagine, event, script modules, packages, translations ed event logs. Write è creare, aggiornare ed eliminare record, e passa dallo stesso percorso della UI, quindi i tuoi Business Events scattano esattamente come per una persona che clicca Salva. Admin è il gruppo che permette a un modello di costruire l'applicazione stessa: entity, schema, pagine, event, script modules, translations e packages.
Quattro cancelli decidono se una chiamata va a segno: il server è avviato, il gruppo è consentito, quello specifico tool è abilitato, e il token porta lo scope. Un tool bloccato da uno qualsiasi di questi è invisibile al client, invece di essere rifiutato dopo.
Token. Emettine uno per client nella schermata MCP Server, con gli scope che gli servono davvero e una scadenza facoltativa. Il segreto viene mostrato una sola volta, alla creazione, e viene memorizzato solo un hash: un token perso si ruota, non si recupera. Dai a ogni integrazione il proprio token: mantiene leggibile l'activity log, e revocarne uno non disturba gli altri.
Activity log. Ogni invocazione viene registrata, comprese quelle rifiutate e il motivo. È qui che controlli cosa ha fatto davvero un'integrazione.
Trappole: un token con lo scope admin viene trattato come amministratore a tutti gli effetti da tutto il resto, quindi distribuiscili con parsimonia. "Allow token in URL" esiste per i client che non possono inviare un header Authorization, ma un URL finisce nei log e negli screenshot molto più facilmente di un header: lascialo spento se non ti serve. E su un ambiente di produzione con dati reali, lascia spento il gruppo admin.
Object Browser
Vista raw di ogni tabella nativa e importata, aggiungi, modifica, elimina righe direttamente. Include un import CSV per caricamenti bulk.
Quando usarlo:
- Caricamento bulk di dati di riferimento prima che le pagine esistano (paesi, valute, enum di stato).
- Debugging, vedere a occhio cosa c'è effettivamente in una tabella quando una pagina si comporta male.
- Edit admin veloci a dati non ancora esposti tramite una Page.
- Import CSV: scegli una tabella, carica un file, mappa le colonne ai campi, anteprima, commit.
Trappole: Object Browser fa scattare i Business Events (passa attraverso lo stesso write path di EntityService del front end). L'eccezione è l'SQL diretto via Database Deployments, quello bypassa tutto.
Dependency Graph
Una mappa in sola lettura di come gli oggetti di configurazione nel tuo ambiente si referenziano a vicenda. Otto tipi di risorsa appaiono come nodi, colorati per tipo: Business Entities, Pages, Event Triggers, Script Modules, PDF Templates, Frontend Templates, Scheduled Events e Packages. Un arco tra due nodi significa che una risorsa dipende dall'altra. Usalo per rispondere alle domande "cosa si romperebbe se elimino questo?" e "c'è qualcosa di inutilizzato qui?".
Cosa significa un arco: una Page collegata a una Business Entity, un Event
Trigger registrato su una Business Entity, uno step di azione di Page che fa scattare un Event
Trigger, uno script che chiama un altro Script Module tramite
Modules.CallAsync("Name"), uno script che renderizza un PDF Template, uno
Scheduled Event che fa scattare un Event Trigger, o un Package che contiene una risorsa. È una
vista di design-time, riflette ciò che la tua configurazione collega insieme, non il
traffico runtime dal vivo.
Due tipi di problema vengono fatti risaltare visivamente:
- Loose ends (orfani) - nodi che niente referenzia e che non referenziano niente. Vengono raccolti in una banda "Loose ends" bordata di rosso in fondo al canvas. Uno Script Module che nessuno chiama; una Page collegata a niente.
- Dangling references - disegnate come archi tratteggiati rossi. Il riferimento esiste nella configurazione ma il suo target non può essere trovato, per esempio uno step di azione di Page che punta ancora a un Event Trigger eliminato, o uno script che chiama uno Script Module con un nome che non esiste più.
Workflow comune: apri Dependency Graph dalla sezione Tools della sidebar. Il pannello di sinistra ha una ricerca per nome, un selettore Layout (Left to right, Top to bottom, By type, Force-directed), gli interruttori Group by package, Show loose ends e Show edges, e una checklist per tipo. Clicca su un nodo per entrare in modalità focus: quel nodo e i suoi vicini diretti restano luminosi mentre il resto del grafo si attenua, così puoi tracciare esattamente cosa tocca una risorsa. Clicca sullo sfondo del canvas per cancellare il focus. Ogni nodo porta un piccolo pulsante di apertura in una nuova scheda che salta direttamente all'editor di quella risorsa. La riga di statistiche in alto riporta il numero di nodi, archi, orfani e dangling references.
Group by package: avvolge i membri di ogni package in un riquadro tratteggiato etichettato, così puoi vedere un package come un'unità e individuare le risorse che ha tirato dentro per cascata.
Trappole: il grafo viene costruito su richiesta a partire dallo stato
corrente, usa il pulsante di refresh dopo aver modificato risorse altrove. Gli archi derivati
dagli script vengono trovati scansionando i corpi degli script per la forma di chiamata
letterale Modules.CallAsync("Name"), un module invocato tramite un nome calcolato
non mostrerà un arco. Una dangling reference vale sempre la pena di essere corretta; un orfano
spesso no, uno Script Module nuovo di zecca conta come orfano finché qualcosa non lo chiama.
Event Logs
L'audit trail per tutto ciò che la piattaforma ha eseguito, Business Events, Script Modules, Scheduled Events, sync di terze parti.
Workflow comune: apri Event Logs, imposta Status su Failed, fai clic su una voce. Il pannello di dettaglio mostra il payload (stato del record al momento, parametri passati), l'eccezione con stack trace, e i tempi.
Logs e Charts: la pagina ha due schede che condividono un'unica riga di filtri. Logs è la tabella qui sopra. Charts è una dashboard operativa sullo stesso filtro: il volume nel tempo impilato per stato, un andamento del tasso di successo, una ripartizione per source, gli events che falliscono di più e i più lenti, la durata media e massima nel tempo, una ripartizione per tipo di trigger, e una heatmap giorno della settimana per ora del giorno, con i totali principali in alto. Entrambe le schede condividono un intervallo di date Da / A (con i preset Ultime 1h / 24h / 7d); la scheda Charts sceglie automaticamente un intervallo di tempo adatto al periodo e può aggiornarsi a cadenza regolare per il monitoraggio in tempo reale.
Notifiche in tempo reale: l'icona campanella nella barra in alto dell'app admin emerge i failure non letti via SignalR.
Trappole: il log può crescere molto. Le voci vecchie sono tenute per sempre di default; se il disco è un problema, configura uno Scheduled Event che pota le voci più vecchie di N giorni.
User Management
Crea, invita e gestisce utenti; assegna ruoli realm. Fa da wrapper all'API REST admin di Keycloak.
Ruoli:
- admin - tutto; può gestire tutte le Business Units, utenti, ruoli, impostazioni di sistema.
- owner - gestisce le proprie Business Units, può modificare le pagine di amministrazione e di runtime.
- editor - può vedere e modificare le pagine di runtime, ma non cambiare la configurazione di schema/BE/event.
- user - read-only sulle pagine di runtime.
Trappole: declassare un utente da admin a metà sessione non lo butta fuori, il cambiamento si applica al prossimo refresh del token (tipicamente entro un minuto).
Business Units
Gruppi basati su Keycloak che controllano la visibilità sulle singole risorse. Vedi Concetti -> Business Units per il modello.
Workflow comune: crea una BU. Invita i membri per email e scegli il ruolo. Assegna le risorse andando su ogni BE / Page / Trigger oppure tramite il pannello degli item collegati della BU.
Assegnazioni in cascading: quando assegni una Page a una BU, l'assegnazione si propaga alla BE a cui la pagina si collega.
Trappole: la BU attiva di un utente è impostata nello switcher
BU della barra in alto e persiste in localStorage. I nuovi utenti partono
dalla loro prima BU; se una pagina lista è sospettosamente vuota, controlla quale BU è
attiva.
Database Backups
pg_dump notturno di tutti e tre i database. Trigger manuale / upload /
restore dalla UI.
Workflow comune: Trigger now -> Download -> Upload -> Restore. Lo scheduling di default è notturno alle 03:00 UTC.
Limitazione del trial: i Backup sono disabilitati nell'ambiente trial.
Branding
Cambia il display name dell'app, il logo (chiaro + scuro), e lo schema colori primario, applicato a runtime, niente rebuild.
Workflow comune: imposta il nome dell'app, carica un logo chiaro e uno scuro (PNG/JPG/SVG, ≤ 10 MB), scegli un colore di brand primario. Salva. Aggiorna il browser.
Trappole: la favicon non viene sovrascritta da Branding, è bundled nello SPA.
Translations
Editor key/value per le stringhe UI dell'app. Aggiungi nuovi locale, sovrascrivi le label di default per cliente.
Workflow comune: scegli un locale, cerca una chiave, digita un nuovo valore, salva. Aggiorna l'app admin.
Trappole: le traduzioni sono caricate una volta per sessione; gli utenti su una tab vecchia non vedono i cambiamenti finché non aggiornano. Alcune label (intestazioni di colonna dalle BE) vengono dalla config della BE, non dalle traduzioni.
API chiamabili dagli script
L'esatta superficie che gli script possono chiamare. Verificata contro il sorgente, ogni metodo qui sotto esiste davvero.
Globali
Ogni script riceve queste variabili di livello superiore (nessun altro nome esiste nello scope dello script):
Entity-dynamicExpandoObject. Record corrente. Accedi ai campi conEntity.column_name. MutareEntityin un trigger Before* persiste le modifiche come parte della scrittura in corso.OldEntity-dynamicExpandoObject. Record precedente (trigger di update + delete). Read-only.Log-ILogger.Log.LogInformation("..."),Log.LogWarning(...),Log.LogError(...). Scrive sui log server e sulla voce dell'Event Log.Db-DbHelper. Accesso al database (vedi sotto).Modules-ModulesHelper. Chiama altri Script Modules:await Modules.CallAsync("ModuleName", new Dictionary<string, object?> { ["param"] = value }). RitornaTask<object?>.Pdf-ScriptPdfHelper. Renderizza un PDF Template salvato per nome:await Pdf.GenerateAsync("invoice", new Dictionary<string, string> { ["id"] = Entity.id.ToString() })ritornabyte[];await Pdf.GenerateBase64Async(...)ritorna lo stesso payload codificato in base64. I parametri sono inoltrati al data script del template come variabili locali tipo stringa.
Non c'è User, Http, Email,
Templates, o nessun altro globale.
Db - metodi single-row + di scrittura
Tutti async, tutti sull'oggetto di livello superiore Db:
await Db.GetAsync(string table, object id)- prende una riga per primary key. Ritornadynamic?(onullse non trovata).await Db.CreateAsync(string table, object values)- insert.valuespuò essere un oggetto anonimo o unDictionary<string, object?>. Fa scattare i trigger Before/After Create. Ritornaint(il nuovo ID).await Db.UpdateAsync(string table, object id, object values)- update per PK. Fa scattare i trigger Before/After Update.await Db.DeleteAsync(string table, object id)- delete per PK. Fa scattare il trigger Before Delete.
Db - query builder fluente
Parti con Db.From(table). Concatena filtri, poi un terminale:
.Where(string column, string op, object? value = null)- aggiunge una clausola WHERE. Operatori:=,!=/<>,>,>=,<,<=,LIKE,ILIKE,IN,IS NULL,IS NOT NULL. Concatena più chiamate.Where(...)per AND..OrderBy(string column, bool desc = false)- imposta ORDER BY. Solo uno consentito per query..Limit(int limit)- massimo di righe. Default è 1000.
Terminali (ciascuno esegue la query):
await ...ToListAsync()- ritornaList<dynamic>.await ...FirstAsync()- ritornadynamic?(primo match o null). Imposta temporaneamente il limit a 1.await ...CountAsync()- ritornaint.
Non c'è SumAsync, MaxAsync,
FirstOrDefaultAsync, o SingleAsync. Per le aggregazioni, recupera
con ToListAsync() e riduci in C#.
Esempio pratico
// Get a row by ID, query a list, calculate a sum, update.
var order = await Db.GetAsync("orders", 42);
if (order == null) return false;
var items = await Db.From("order_items")
.Where("order_id", "=", order.id)
.OrderBy("id")
.ToListAsync();
decimal totalAmount = 0;
foreach (var item in items) {
totalAmount += (decimal)(item.amount ?? 0);
}
await Db.UpdateAsync("orders", 42, new {
total = totalAmount,
updated_at = DateTime.UtcNow
});
return true; Modalità simulazione
Durante la simulazione del trigger (il pulsante Run Simulation su un Business
Event), la piattaforma imposta Db.SimulationMode = true. Tutte le operazioni
di scrittura (CreateAsync, UpdateAsync, DeleteAsync)
girano dentro una transazione PostgreSQL che alla fine viene sempre rollback. Le operazioni
di lettura funzionano normalmente. E' questo che rende Run Simulation sicuro da
usare contro dati reali.
Modules
await Modules.CallAsync(string moduleName, Dictionary<string, object?>? parameters = null)- chiama un altro Script Module per nome. I parametri diventano variabili tipizzate nello script del modulo chiamato. RitornaTask<object?>(qualunque cosa il modulo abbia ritornato).
Template expression (action dei Business Event)
La configurazione delle action usa parentesi {{ ... }}. La lista completa dei token validi:
{{ Entity.column_name }}/{{ Entity.id }}{{ OldEntity.column_name }}{{ now() }}/{{ getdate() }}- datetime UTC ISO 8601{{ today() }}- stringa di data{{ guid() }}/{{ newid() }}- GUID fresco{{ year() }},{{ month() }},{{ day() }},{{ timestamp() }}- secondi Unix{{ empty() }},{{ null() }}- Aggregati dentro un contesto di join:
{{ SUM(column) }},{{ AVG() }},{{ COUNT() }},{{ MIN() }},{{ MAX() }} - Aritmetica:
{{ Entity.quantity * Entity.price }}- valutata post-sostituzione viaDataTable.Compute()
Non c'è un {{ user.email }} o altro token di scope utente.