Tutorial - 45 min

Bouw je eerste app

Aan het einde van deze tutorial heb je een klein CRM met drie tabellen (company, contact, deal), een list-and-detail-pagina voor elk, een Business Event die automatisch de updated_at van de deal stempelt, en een Script Module die de totale open-deal-waarde van het bedrijf herberekent zodra een deal wijzigt. Elk concept uit Kernconcepten komt minstens een keer voorbij.

Het gaat ervan uit dat je Aan de slag hebt afgerond en dat je een open Archestack-omgeving in een andere tab hebt. Totale tijd: ongeveer 45 minuten als je zorgvuldig leest, 25 als je doorscant.

Conventies die hier worden gebruikt: tabel- en kolomnamen zijn snake_case (het platform hint naar deze conventie in het veld "Table name" van Schema Designer). Code- voorbeelden gebruiken de echte Db-API, zie Referentie, Via-script-aanroepbare API's voor het volledige oppervlak.

Stap 1 - Ontwerp het schema (10 min)

Open Schema Designer en voeg drie tabellen toe.

Voor elke tabel: klik op Add Table in de werkbalk, typ de naam in het veld "Table name" van de dialoog, klik op Create. De nieuwe tabel verschijnt op het canvas met een automatisch gegenereerde id SERIAL primary key (vergrendeld). Het rechterpaneel opent op de Columns-tab, voeg extra kolommen toe vanuit het "Add column"- vak met gestippelde rand onderaan. Klik op elke kolom om hem uit te klappen en pas de toggles (PK / NULL / UQ), de Length, en de Default value aan.

Tabel: company

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

Tabel: contact

  • id - SERIAL, PK (auto)
  • first_name, last_name - VARCHAR(100), required
  • email - VARCHAR(200), required, UQ aan
  • company_id - INTEGER, required - foreign key, hierna ingesteld

Tabel: deal

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

Foreign keys

Foreign keys leven in de Relations-tab van het rechterpaneel. Selecteer de contact-tabel, schakel naar Relations, scroll naar de "Add relationship"-sectie:

  1. FK column (on this table) = company_id
  2. Relation type = One-to-Many
  3. References, table = company
  4. References, column = id
  5. Klik op Add Relationship.

Herhaal voor de deal-tabel (zijn company_id naar company.id).

Schema Designer-canvas met meerdere tabellen verbonden door FK-lijnen. Werkbalk bovenaan heeft Canvas/JSON-tabs, Packages-dropdown, Find table-zoekveld, zoom-controls, en rechts: + (Add Table), Add Group, Add Text, Save, JSON/code, Deploy (groene raket).
Hoe het canvas eruitziet zodra je een paar tabellen met relaties hebt. De werkbalk (bovenaan) heeft Canvas / JSON-tabs, een Packages-filter, een Find-table-zoekveld, zoom-controls, en rechts de icoonknoppen + (Add Table), Add Group, Add Text, Save, JSON, en de groene Deploy-raket. FK-kolommen tonen een chain-link-icoon naast hun type, en de relaties renderen als gekleurde lijnen tussen tabellen. (Het getoonde voorbeeld gebruikt andere tabellen dan deze tutorial, jouw company / contact / deal-setup ziet er hetzelfde uit met twee FK-lijnen die naar company wijzen.)

Deploy

Klik in de Schema Designer-werkbalk op Deploy. Je belandt op de deployment- configpagina. Schakel naar de Generated SQL-tab, je zou drie CREATE TABLE-statements plus de FK-constraints moeten zien. Klik op Deploy rechtsboven.

Wat je zult zien als het werkt: de deployment-rij in Database Deployments, Overview gaat binnen enkele seconden van "Executing" naar "Succeeded". De drie tabellen verschijnen in de tabellenlijst van Object Browser.

Als de deploy faalt op FK-constraints: de Generated SQL emit tabellen in de volgorde waarin ze zijn opgeslagen. Open de SQL-tab en herorden zodat company wordt aangemaakt voor contact en deal, en redeploy. Of klik op Regenerate nadat je tabellen handmatig in het Schema Designer-canvas hebt herordend.

Stap 2 - Componeer de Business Entities (10 min)

Elke pagina heeft een Business Entity nodig om aan te binden. Open Business Entities en klik op Create voor elk. Klik na elke save op Run Preview om te bevestigen dat de kolommen correct terugkomen.

BE: company

Entity Name company, Master Table company, Label Column name. Sla op.

Klik twee keer op Add Join om twee geaggregeerde joins toe te voegen:

  • Join naar contact: From column company.id, To column contact.company_id. Schakel Aggregate Mode aan. Kies kolom id, zet Aggregate Function = COUNT, noem het contact_count.
  • Join naar deal: From column company.id, To column deal.company_id. Aggregate Mode aan. Kies kolom id, function COUNT, noem het open_deal_count. (We filteren in Stap 5 via een Business Event op "open" deals; voor nu telt dit alle deals.)

BE: contact

Entity Name contact, Master Table contact, Label Column email. Voeg een Join toe naar company via contact.company_id naar company.id, surface de name-kolom als company_name. (Schakel Aggregate Mode hier niet aan, het is een gewone join.)

BE: deal

Entity Name deal, Master Table deal, Label Column title. Voeg een Join toe naar company via deal.company_id naar company.id, surface de name-kolom als company_name.

Verifieer: klik op elke BE op Run Preview. Je ziet een leeg grid (nog geen data) met de kolomkoppen die je hebt gedefinieerd. Als een joinkolom-kop ontbreekt, ben je waarschijnlijk vergeten de kolom in de kolompicker van de join aan te vinken. Heropen de join, vink de kolom aan, sla op, run preview opnieuw.

Stap 3 - Bouw de pagina's (10 min)

Open Page Editor. Klik voor elke Business Entity op Create:

  1. Companies - Page Name Companies, Page Route /companies, Business Entity company. De Visual-tab genereert automatisch een lijst en een detailformulier. Klik in het detailformulier twee keer op Add Tab om Contacts- en Deals-tabs toe te voegen. Voeg in elke tab een RelatedGrid-sectie toe gebonden aan de contact / deal-BE met het joinfilter op company.id = current record's id.
  2. Contacts - Page Name Contacts, Page Route /contacts, Business Entity contact. Het company_id-veld van het automatisch gegenereerde detailformulier verschijnt als een getal, verander zijn Type naar Select en stel de Entity-autocomplete in op company zodat gebruikers een company op naam kiezen.
  3. Deals - Page Name Deals, Page Route /deals, Business Entity deal. Zelfde behandeling voor company_id (Type Select, Entity company). Voor stage, laat Type voor nu op Text, de waarden kunnen later via een Validate-event worden afgedwongen als je wilt.

Zet voor elke pagina de Published-schakelaar in de bovenste header op AAN. De pagina's verschijnen in de sidebar onder een APPLICATION-sectie (gegroepeerd per categorie). Voeg een Company toe, dan een Contact gekoppeld aan die Company, dan een Deal, bevestig dat de relaties correct renderen. De Companies-pagina zou nu 1 moeten tonen in contact_count.

Gepubliceerde eindgebruikerspagina met breadcrumbs (Home / Customers / Record #9), een Edit-knop rechtsboven, meerdere tabs (Details, Vehicles, Address & Contact, Open service orders, Closed Service orders), een Properties-formulier met inline edit-pennen per veld, en een related-data-grid (Vehicles) onder het formulier.
Hoe een gepubliceerde pagina er op runtime uitziet. Het voorbeeld hier is een Customer-pagina uit een ander domein (DMS), maar de vorm is precies wat je company-pagina zal produceren. Let op: de APPLICATION-sectie van de sidebar verschijnt zodra je publiceert, pagina's worden gegroepeerd onder een categorie-header (hier: CUSTOMER PORTAL). Het detailpaneel rendert breadcrumbs, een Edit-knop (rechtsboven), per-veld potlood-iconen voor inline-bewerkingen, extra tabs bovenaan (Details / Vehicles / etc.), en onder het formulier een related-grid-sectie die rijen uit een andere BE haalt, gefilterd op het huidige record. De bel-badge ("1") laat zien dat er een ongelezen Event Log-fout is.
Als er iets leeg lijkt: de meest voorkomende oorzaak is vergeten om de Published-schakelaar om te zetten, als die UIT staat, toont navigeren naar /companies in de sidebar niets. Zet hem AAN en refresh.

Stap 4 - Ruim een veld op bij het opslaan met een Business Event (5 min)

Business Events draaien wat logica zodra een record wordt weggeschreven. De kleinste nuttige: overtollige spaties uit de title van een deal trimmen bij elke save, zodat " Acme renewal " als "Acme renewal" landt. Laten we dat opzetten.

Voor created_at / updated_at / created_by / updated_by heb je nooit een regel nodig. Archestack voegt die vier audit-kolommen automatisch toe aan elke tabel en stempelt ze bij elke insert en update, dus een "stempel updated_at"-trigger zou alleen werk dupliceren dat het platform al doet.
  1. Open Business Events, Create.
  2. Rule Name: Normalize deal.title. Schakel Enabled AAN.
  3. Business Entity: deal. Triggers: vink Before Update aan.
  4. Geen condities, vuur bij elke update.
  5. Voeg een actie toe: kies Execute Script. De scriptbody van de actie:
    string title = Entity.title;
    Entity.title = title?.Trim();
  6. Klik op de Simulate-tab, kies een bestaande Deal, klik op Run Simulation. Het output-paneel toont dat het script succesvol heeft gedraaid en waarop Entity.title is gezet. (Geen echte write gebeurt, simulatie draait in een teruggedraaide transactie.)
  7. Sla op. Test door een Deal te bewerken waarvan de titel voor- of achteraan spaties heeft, de titel zou bij elke save getrimd moeten terugkomen.
Waarom Before Update + Execute Script in plaats van een actie die "een veld zet"? Archestack heeft geen aparte "Set field"-actie. De manier om een record vanuit een trigger te muteren is door toe te wijzen aan Entity.column_name binnen een Execute Script op een Before*-timing. Het platform persisteert de aangepaste Entity terug als onderdeel van de in-flight write, geen extra query, geen recursie-risico.

Stap 5 - Herbereken company.open_deal_value met een Script Module (10 min)

Een berekend totaal als "open deal-waarde per bedrijf" is te dynamisch voor een opgeslagen kolom om met de hand accuraat te blijven. We houden het in sync met een klein script dat opnieuw draait zodra een deal op een bedrijf wordt ingevoegd, bijgewerkt of verwijderd.

Schrijf het script

Open Script Modules, Create. Noem het RecalcCompanyOpenDealValue.

Schakel naar de Parameters-tab. Klik op Add. Name company_id, Type int, Required aangevinkt.

Terug naar de Edit-tab. Body:

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;

Schakel naar de Test-tab. Typ een echte company_id uit je Companies-pagina in de parameter-invoer, klik op Run. De output toont de return-waarde (het totaal) en een succesindicator. Herlaad de Companies-pagina, open_deal_value op dat bedrijf is nu in sync.

Veelgemaakte struikelblokken:
  • await vergeten op .ToListAsync(), het script compileert maar openDeals houdt uiteindelijk een Task vast, niet de rijen. De fout in het Test-paneel zal "cannot be enumerated" noemen.
  • Db.Query gebruiken in plaats van Db.From, er is geen Query-methode. Houd je aan Db.From(table) voor geketende queries en Db.GetAsync(table, id) voor single-row-op-PK.
  • .SumAsync(...) proberen, bestaat niet. Haal op + sommeer in C#, zoals hierboven.

Koppel het aan een Business Event

  1. Open Business Events, Create.
  2. Rule Name: Recalc company.open_deal_value on deal change. Enabled AAN.
  3. Business Entity: deal. Triggers: vink After Create, After Update, en Before Delete aan.
  4. Geen condities, vuur bij elke wijziging.
  5. Voeg een actie toe: Execute Script. Body:
    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. Sla op. Bewerk de amount van een Deal en herlaad de Company-pagina, het totaal blijft in sync.
Waarom het via Modules aanroepen in plaats van de logica in het script van deze trigger inlinen? Twee redenen. Ten eerste is de herberekening herbruikbaar, je kunt hem ook vanuit een Scheduled Event aanroepen (nachtelijke inhaalslag) of direct vanuit de front-end. Ten tweede isoleert het de logica op een enkele genoemde plek, makkelijker te testen, makkelijker later terug te vinden.

Stap 6 - Bundel het als een package (5 min)

Je hebt een echt, werkend mini-CRM gebouwd. Bundel het zodat je het naar een andere omgeving kunt verplaatsen.

  1. Open Packages, Create. Noem het MiniCRM v1.
  2. Voeg de drie Pages toe. Open het linked-items-paneel om de cascade te zien: de package zal de BEs meetrekken waarnaar de pagina's verwijzen, de brontabellen waaruit die BEs lezen, plus de twee Business Events en de Script Module die ze raken.
  3. Vink uit wat je liever weglaat, typisch zou je voor een tutorial als deze alles behouden.
  4. Klik op Export, download de ZIP.

De ZIP importeren in een andere omgeving herschept alles (ervan uitgaande dat het schema eerst is gedeployed). Zo verschepen partners vertical-specifieke configuraties en zo zou je later werk van een trial naar een betaalde omgeving promoten.

Recap - wat er zojuist is gebeurd

  • Je hebt een schema ontworpen, het gedeployed als echte PostgreSQL-tabellen, en nooit SQL met de hand geschreven.
  • Je hebt die tabellen geexposed via Business Entities, gekozen wat te tonen, labels ingejoind voor bruikbaarheid, gerelateerde-rij-tellingen geaggregeerd.
  • Je hebt drie pagina's gecomponeerd uit configuratie alleen, met ingebedde tabs en zoeken.
  • Je hebt een gedrag toegevoegd met een Business Event (automatisch stempelen) en een meer complexe berekening met een Script Module, acht regels C# die elke keer draaien als de data wijzigt.
  • Je hebt het geheel gebundeld als een Package, draagbaar over omgevingen heen.

Dezelfde loop schaalt naar tientallen tabellen en honderden pagina's. De Referentie dekt de rest van het platform, branding, third-party-data-sync, AI-assisted scaffolding, maar de kernvaardigheid is wat je net hebt geleerd.

Waar nu naartoe

  • Genereer PDF-facturen - voeg een afdrukbare factuur-template toe aan de Deals die je net hebt gebouwd. Dezelfde data, nieuw uitvoerkanaal.
  • Scheduled Events - breid het herrekenscript uit met een nachtelijke inhaalslag die zonder gebruikersactie draait.
  • AI Builder - richt het op "voeg ondersteuning toe voor service-afspraken, datum, klant, voertuig, status" en kijk hoe het een vergelijkbare feature scaffold.