Tutorial - 45 min

Crea la tua prima app

Alla fine di questo tutorial avrai un piccolo CRM con tre tabelle (company, contact, deal), una pagina lista-e-dettaglio per ciascuna, un Business Event che marca automaticamente updated_at del deal, e uno Script Module che ricalcola il valore totale dei deal aperti della company ogni volta che un deal cambia. Ogni concetto da Concetti chiave compare almeno una volta.

Si presume tu abbia finito Per iniziare e che tu abbia un ambiente Archestack aperto in un'altra tab. Tempo totale: circa 45 minuti se leggi con attenzione, 25 se scorri.

Convenzioni usate qui: i nomi di tabelle e colonne sono snake_case (la piattaforma suggerisce questa convenzione nel campo "Table name" di Schema Designer). Gli esempi di codice usano la vera API Db, vedi Reference -> API chiamabili dagli script per la superficie completa.

Passo 1 - Progetta lo schema (10 min)

Apri Schema Designer e aggiungi tre tabelle.

Per ogni tabella: fai clic su Add Table nella toolbar, digita il nome nel campo "Table name" del dialog, fai clic su Create. La nuova tabella appare sul canvas con una primary key SERIAL id auto-generata (bloccata). Il pannello destro si apre sulla tab Columns, aggiungi colonne aggiuntive dal box "Add column" con bordo tratteggiato in basso. Fai clic su ogni colonna per espanderla e aggiustare i toggle (PK / NULL / UQ), la Length, e il Default value.

Tabella: company

  • id - SERIAL, PK (auto)
  • name - VARCHAR(200), required
  • industry - VARCHAR(80), nullable
  • open_deal_value - DECIMAL, default 0 - tenuto in sync via lo script al Passo 5
  • created_at - TIMESTAMPTZ, default now()

Tabella: contact

  • id - SERIAL, PK (auto)
  • first_name, last_name - VARCHAR(100), required
  • email - VARCHAR(200), required, UQ attiva
  • company_id - INTEGER, required - foreign key, configurato sotto

Tabella: deal

  • id - SERIAL, PK (auto)
  • company_id - INTEGER, required - foreign key, configurato sotto
  • title - VARCHAR(200), required
  • stage - VARCHAR(40), required, default 'New' - valori: New, Qualified, Proposal, Won, Lost
  • amount - DECIMAL, required, default 0
  • created_at, updated_at - TIMESTAMPTZ, default now()

Foreign key

Le foreign key vivono nella tab Relations del pannello destro. Seleziona la tabella contact, passa a Relations, scorri fino alla sezione "Add relationship":

  1. FK column (on this table) = company_id
  2. Relation type = One-to-Many
  3. References -> table = company
  4. References -> column = id
  5. Fai clic su Add Relationship.

Ripeti per la tabella deal (il suo company_id -> company.id).

Canvas di Schema Designer con diverse tabelle connesse da linee FK. La toolbar in cima ha tab Canvas/JSON, dropdown Packages, ricerca Find table, controlli di zoom, e a destra: + (Add Table), Add Group, Add Text, Save, JSON/code, Deploy (razzo verde).
Com'è il canvas una volta che hai qualche tabella con relazioni. La toolbar (in cima) ha le tab Canvas / JSON, un filtro Packages, una ricerca Find-table, controlli di zoom, e a destra i pulsanti icona + (Add Table), Add Group, Add Text, Save, JSON, e il razzo Deploy verde. Le colonne FK mostrano un'icona a catena accanto al loro tipo, e le relazioni si renderizzano come linee colorate tra le tabelle. (L'esempio mostrato usa tabelle diverse da questo tutorial, il tuo setup company / contact / deal avrà la stessa forma con due linee FK che puntano a company.)

Deploy

Fai clic su Deploy nella toolbar di Schema Designer. Atterri sulla pagina di configurazione del deployment. Passa alla tab Generated SQL, dovresti vedere tre istruzioni CREATE TABLE più i vincoli FK. Fai clic su Deploy in alto a destra.

Cosa vedrai se funziona: la riga del deployment in Database Deployments -> Overview va da "Executing" a "Succeeded" in pochi secondi. Le tre tabelle appaiono nella lista tabelle di Object Browser.

Se il deploy fallisce sui vincoli FK: il Generated SQL emette le tabelle nell'ordine in cui sono state salvate. Apri la tab SQL e riordina così che company sia creata prima di contact e deal, poi rideploy. Oppure fai clic su Regenerate dopo aver riordinato manualmente le tabelle nel canvas di Schema Designer.

Passo 2 - Componi le Business Entities (10 min)

Ogni pagina ha bisogno di una Business Entity a cui collegarsi. Apri Business Entities e fai clic su Create per ciascuna. Premi Run Preview dopo ogni salvataggio per confermare che le colonne tornino correttamente.

BE: company

Entity Name company, Master Table company, Label Column name. Salva.

Fai clic su Add Join due volte per aggiungere due join aggregati:

  • Join a contact: From column company.id, To column contact.company_id. Sposta Aggregate Mode su ON. Scegli la colonna id, imposta Aggregate Function = COUNT, nominala contact_count.
  • Join a deal: From column company.id, To column deal.company_id. Aggregate Mode su ON. Scegli la colonna id, funzione COUNT, nominala open_deal_count. (Filtreremo ai deal "aperti" tramite un Business Event al Passo 5; per ora conta tutti i deal.)

BE: contact

Entity Name contact, Master Table contact, Label Column email. Aggiungi un Join a company via contact.company_id -> company.id, esponi la colonna name come company_name. (Non abilitare Aggregate Mode qui, è un join normale.)

BE: deal

Entity Name deal, Master Table deal, Label Column title. Aggiungi un Join a company via deal.company_id -> company.id, esponi la colonna name come company_name.

Verifica: su ogni BE, fai clic su Run Preview. Vedrai una griglia vuota (nessun dato ancora) con le intestazioni di colonna che hai definito. Se un'intestazione di colonna joined manca, probabilmente hai dimenticato di spuntare la colonna nel picker di colonne del join. Riapri il join, spunta la colonna, salva, esegui di nuovo la preview.

Passo 3 - Costruisci le pagine (10 min)

Apri Page Editor. Per ogni Business Entity, fai clic su Create:

  1. Companies - Page Name Companies, Page Route /companies, Business Entity company. La tab Visual auto-genera una lista e un form di dettaglio. Nel form di dettaglio, fai clic su Add Tab due volte per aggiungere le tab Contacts e Deals. In ogni tab, aggiungi una sezione RelatedGrid collegata alla BE contact / deal con il filtro di join impostato su company.id = current record's id.
  2. Contacts - Page Name Contacts, Page Route /contacts, Business Entity contact. Il campo company_id del form di dettaglio auto-generato apparirà come numero, cambia il suo Type in Select e imposta l'autocomplete Entity su company così gli utenti scelgono una company per nome.
  3. Deals - Page Name Deals, Page Route /deals, Business Entity deal. Stesso trattamento per company_id (Type Select, Entity company). Per stage, lascia Type come Text per ora, i valori possono essere imposti tramite un event Validate più tardi se vuoi.

Per ogni pagina, sposta lo switch Published nell'header in alto su ON. Le pagine appaiono nella sidebar sotto una sezione APPLICATION (raggruppate per categoria). Aggiungi una Company, poi un Contact legato a quella Company, poi un Deal, conferma che le relazioni si renderizzino correttamente. La pagina Companies ora dovrebbe mostrare 1 in contact_count.

Pagina end-user pubblicata con breadcrumb (Home / Customers / Record #9), un pulsante Edit in alto a destra, più tab (Details, Vehicles, Address & Contact, Open service orders, Closed Service orders), un form Properties con pencil di edit inline per campo, e una griglia di dati correlati (Vehicles) sotto il form.
Com'è una pagina pubblicata a runtime. L'esempio qui è una pagina Customer da un dominio diverso (DMS), ma la forma è esattamente quella che produrrà la tua pagina company. Nota: la sezione APPLICATION della sidebar appare non appena pubblichi, le pagine sono raggruppate sotto un'intestazione di categoria (qui: CUSTOMER PORTAL). Il pannello di dettaglio renderizza breadcrumb, un pulsante Edit (in alto a destra), icone pencil per campo per edit inline, tab aggiuntive in cima (Details / Vehicles / ecc.), e sotto il form una sezione griglia correlata che tira righe da un'altra BE filtrata per il record corrente. Il badge campanella ("1") mostra che c'è un errore di Event Log non letto.
Se qualcosa sembra vuoto: la causa più comune è dimenticare di spostare lo switch Published, se è OFF, navigare su /companies nella sidebar non mostra niente. Spostalo su ON e fai refresh.

Passo 4 - Pulisci un campo al salvataggio con un Business Event (5 min)

I Business Events eseguono un po' di logica non appena un record viene scritto. Il più piccolo utile: rimuovere gli spazi superflui dal title di un deal a ogni salvataggio, così che " Acme renewal " diventi "Acme renewal". Mettiamolo in piedi.

Per created_at / updated_at / created_by / updated_by non ti serve mai una regola. Archestack aggiunge quelle quattro colonne di audit a ogni tabella e le marca a ogni insert e update automaticamente, quindi un trigger "marca updated_at" non farebbe che duplicare un lavoro che la piattaforma già svolge.
  1. Apri Business Events -> Create.
  2. Rule Name: Normalize deal.title. Sposta Enabled su ON.
  3. Business Entity: deal. Triggers: spunta Before Update.
  4. Nessuna condizione, scatta su ogni update.
  5. Aggiungi un'action: scegli Execute Script. Il corpo dello script dell'action:
    string title = Entity.title;
    Entity.title = title?.Trim();
  6. Fai clic sulla tab Simulate -> scegli qualsiasi Deal esistente -> fai clic su Run Simulation. Il pannello di output mostra che lo script è girato con successo e a cosa è stato impostato Entity.title. (Nessuna scrittura reale avviene, la simulazione gira in una transazione che viene rollback.)
  7. Salva. Testa modificando un Deal con spazi iniziali o finali nel titolo, il titolo dovrebbe tornare ripulito a ogni salvataggio.
Perché Before Update + Execute Script invece di un'action che "imposta un campo"? Archestack non ha un'action discreta "Set field". Il modo in cui muti un record da un trigger è assegnare a Entity.column_name dentro un Execute Script su un timing Before*. La piattaforma persiste l'Entity modificato come parte della scrittura in corso, nessuna query extra, nessun rischio di ricorsione.

Passo 5 - Ricalcola company.open_deal_value con uno Script Module (10 min)

Un totale calcolato come "valore deal aperti per company" è troppo dinamico perché una colonna salvata resti accurata a mano. La terremo in sync con un piccolo script che rigira ogni volta che un deal su una company viene inserito, aggiornato o eliminato.

Scrivi lo script

Apri Script Modules -> Create. Nominalo RecalcCompanyOpenDealValue.

Passa alla tab Parameters. Fai clic su Add. Name company_id, Type int, Required spuntato.

Torna alla tab Edit. Corpo:

var openDeals = await Db.From("deal")
    .Where("company_id", "=", company_id)
    .Where("stage", "!=", "Won")
    .Where("stage", "!=", "Lost")
    .ToListAsync();

decimal total = 0;
foreach (var d in openDeals) total += (decimal)(d.amount ?? 0);

await Db.UpdateAsync("company", company_id, new { open_deal_value = total });

return total;

Passa alla tab Test. Digita un company_id reale dalla tua pagina Companies nell'input del parametro, fai clic su Run. L'output mostra il valore di ritorno (il totale) e un indicatore di successo. Ricarica la pagina Companies, open_deal_value su quella company ora è in sync.

Inciampi comuni:
  • Dimenticare await su .ToListAsync(), lo script compila ma openDeals finisce per contenere un Task, non le righe. L'errore nel pannello Test menzionerà "cannot be enumerated".
  • Usare Db.Query invece di Db.From, non c'è un metodo Query. Attieniti a Db.From(table) per le query concatenate e a Db.GetAsync(table, id) per single-row-by-PK.
  • Provare .SumAsync(...), non esiste. Fetch + sum in C#, come sopra.

Collegalo a un Business Event

  1. Apri Business Events -> Create.
  2. Rule Name: Recalc company.open_deal_value on deal change. Enabled ON.
  3. Business Entity: deal. Triggers: spunta After Create, After Update, e Before Delete.
  4. Nessuna condizione, scatta su ogni cambio.
  5. Aggiungi un'action: Execute Script. Corpo:
    var entity = OldEntity != null && OldEntity.company_id != null
        ? OldEntity      // for delete & update, OldEntity has the original company_id
        : Entity;        // for create, only Entity is populated
    
    await Modules.CallAsync("RecalcCompanyOpenDealValue", new Dictionary<string, object?> {
        ["company_id"] = entity.company_id
    });
  6. Salva. Modifica l'amount di un Deal e ricarica la pagina Company, il totale resta in sync.
Perché chiamarlo tramite Modules invece di inserire la logica direttamente nello script di questo trigger? Due motivi. Primo, il ricalcolo è riutilizzabile, puoi chiamarlo anche da uno Scheduled Event (catch-up notturno) o direttamente dal front end. Secondo, isola la logica in un singolo posto con un nome, più facile da testare, più facile da trovare dopo.

Passo 6 - Impacchettalo come package (5 min)

Hai costruito un vero mini-CRM funzionante. Impacchettalo così puoi spostarlo in un altro ambiente.

  1. Apri Packages -> Create. Nominalo MiniCRM v1.
  2. Aggiungi le tre Pages. Apri il pannello degli item collegati per vedere il cascade: il package porterà le BE che le pagine referenziano, le tabelle sorgente da cui quelle BE leggono, più i due Business Event e lo Script Module che le toccano.
  3. Despunta qualsiasi cosa preferiresti omettere, tipicamente terresti tutto per un tutorial come questo.
  4. Fai clic su Export -> scarica lo ZIP.

Importare lo ZIP in un ambiente diverso ricrea tutto (assumendo che lo schema sia deployato prima). E' così che i partner spediscono configurazioni specifiche per verticale e come promuoveresti il lavoro da un trial a un ambiente a pagamento più tardi.

Riepilogo - cosa è appena successo

  • Hai progettato uno schema, l'hai deployato come tabelle PostgreSQL reali, e non hai mai scritto SQL a mano.
  • Hai esposto quelle tabelle attraverso le Business Entities, scegliendo cosa esporre, unendo etichette per usabilità, aggregando conteggi di righe correlate.
  • Hai composto tre pagine solo dalla configurazione, con tab incorporate e ricerca.
  • Hai aggiunto un comportamento con un Business Event (auto-stamping) e un calcolo più complesso con uno Script Module, otto righe di C# che girano ogni volta che i dati cambiano.
  • Hai impacchettato il tutto come Package, portabile tra ambienti.

Lo stesso loop scala a dozzine di tabelle e centinaia di pagine. La Reference copre il resto della piattaforma, branding, sync di dati di terze parti, scaffolding assistito da AI, ma la competenza centrale è quella che hai appena imparato.

Dove andare dopo

  • Genera fatture in PDF - aggiungi un template di fattura stampabile ai Deals che hai appena costruito. Stessi dati, nuovo canale di output.
  • Scheduled Events - estendi lo script di ricalcolo con un catch-up notturno che gira senza azione utente.
  • AI Builder - indirizzalo su "aggiungi supporto per gli appuntamenti di servizio, data, customer, veicolo, status" e guardalo fare lo scaffolding di una funzionalità simile.