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), requiredindustry- VARCHAR(80), nullableopen_deal_value- DECIMAL, default0- in sync gehouden via het script in Stap 5created_at- TIMESTAMPTZ, defaultnow()
Tabel: contact
id- SERIAL, PK (auto)first_name,last_name- VARCHAR(100), requiredemail- VARCHAR(200), required, UQ aancompany_id- INTEGER, required - foreign key, hierna ingesteld
Tabel: deal
id- SERIAL, PK (auto)company_id- INTEGER, required - foreign key, hierna ingesteldtitle- VARCHAR(200), requiredstage- VARCHAR(40), required, default'New'- waarden: New, Qualified, Proposal, Won, Lostamount- DECIMAL, required, default0created_at,updated_at- TIMESTAMPTZ, defaultnow()
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:
- FK column (on this table) =
company_id - Relation type =
One-to-Many - References, table =
company - References, column =
id - Klik op Add Relationship.
Herhaal voor de deal-tabel (zijn company_id naar company.id).
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 zodatcompanywordt aangemaakt voorcontactendeal, 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 columncompany.id, To columncontact.company_id. Schakel Aggregate Mode aan. Kies kolomid, zet Aggregate Function =COUNT, noem hetcontact_count. -
Join naar
deal: From columncompany.id, To columndeal.company_id. Aggregate Mode aan. Kies kolomid, functionCOUNT, noem hetopen_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:
- Companies - Page Name
Companies, Page Route/companies, Business Entitycompany. 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. - Contacts - Page Name
Contacts, Page Route/contacts, Business Entitycontact. Hetcompany_id-veld van het automatisch gegenereerde detailformulier verschijnt als een getal, verander zijn Type naar Select en stel de Entity-autocomplete in opcompanyzodat gebruikers een company op naam kiezen. - Deals - Page Name
Deals, Page Route/deals, Business Entitydeal. Zelfde behandeling voorcompany_id(TypeSelect, Entitycompany). Voorstage, laat Type voor nu opText, de waarden kunnen later via eenValidate-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.
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.
Voorcreated_at/updated_at/created_by/updated_byheb 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.
- Open Business Events, Create.
- Rule Name:
Normalize deal.title. Schakel Enabled AAN. - Business Entity:
deal. Triggers: vink Before Update aan. - Geen condities, vuur bij elke update.
-
Voeg een actie toe: kies Execute Script. De scriptbody van de actie:
string title = Entity.title; Entity.title = title?.Trim(); -
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.titleis gezet. (Geen echte write gebeurt, simulatie draait in een teruggedraaide transactie.) - 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:
awaitvergeten op.ToListAsync(), het script compileert maaropenDealshoudt uiteindelijk eenTaskvast, niet de rijen. De fout in het Test-paneel zal "cannot be enumerated" noemen.Db.Querygebruiken in plaats vanDb.From, er is geenQuery-methode. Houd je aanDb.From(table)voor geketende queries enDb.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
- Open Business Events, Create.
- Rule Name:
Recalc company.open_deal_value on deal change. Enabled AAN. - Business Entity:
deal. Triggers: vink After Create, After Update, en Before Delete aan. - Geen condities, vuur bij elke wijziging.
-
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 }); - Sla op. Bewerk de
amountvan 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.
- Open Packages, Create. Noem het
MiniCRM v1. - 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.
- Vink uit wat je liever weglaat, typisch zou je voor een tutorial als deze alles behouden.
- 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.