Reference

Jedes Tool, an einem Ort

Diese Seite ist die praktische Referenz für jedes Tool in der Sidebar deiner Archestack-Umgebung. Jeder Abschnitt behandelt, was das Tool tut, wann du danach greifst, die Schritte der gängigsten Workflows und die Stolperfallen, in die neue Nutzer tappen. Der letzte Abschnitt (Aus Skripten aufrufbare APIs) dokumentiert die exakte Oberfläche, die Skripte aufrufen können.

Schema Designer

Ein visueller Editor für das Datenbankschema, Tabellen, Spalten, Typen, Beziehungen, Indizes, der automatisch in ein JSON-Dokument speichert. Das Schema ist die Single Source of Truth für deine Anwendung; kein anderes Tool sieht eine Spalte, bis du sie hier anlegst und deployst.

Gängiger Workflow: Klick in der Symbolleiste auf Add Table (Icon-Button). Es öffnet sich ein Dialog mit dem Titel "Create New Table"; tippe einen Namen ein (der Hilfetext weist auf "Lowercase with underscores recommended" hin), klicke auf Create. Die Tabelle erscheint auf dem Canvas mit einem automatisch erzeugten id-SERIAL-Primärschlüssel. Wähle die Tabelle aus, das rechte Panel öffnet sich auf dem Columns-Tab. Füge Spalten über die gestrichelte "Add column"-Box unten hinzu (Namensfeld, Type-Dropdown, auf Add Column klicken). Klicke jede Spalte an, um sie aufzuklappen, und passe die Schalter (PK, NULL, UQ), Length und Default value an.

Spaltentypen verfügbar im Type-Dropdown: 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, plus geometrische und Array-Typen. Length ist nur für VARCHAR und CHAR relevant.

Fremdschlüssel leben im Relations-Tab des rechten Panels (nicht "Relationships"). Scrolle zu "Add relationship": Wähle die FK-Spalte auf der aktuellen Tabelle, den Beziehungstyp (One-to-One / One-to-Many / Many-to-Many), die referenzierte Tabelle, die referenzierte Spalte und klicke auf Add Relationship. Jede Beziehung hat On Delete- und On Update-Dropdowns (CASCADE / SET NULL / SET DEFAULT / RESTRICT / NO ACTION).

Auto-save: Die Anzeige unten links wechselt zwischen "Auto saving…" und "Saved". Es gibt auch einen Save-Button in der Symbolleiste (nur aktiv, wenn es ausstehende Änderungen gibt) für explizites Speichern.

Andere Symbolleisten-Buttons: Add Group (visuelle Container für verwandte Tabellen, Properties-Panel mit dem Titel "Group"), Add Text (freie Annotationen, Properties-Panel mit dem Titel "Text Annotation"), Zoom-Controls, Package-Filter, Tabellensuche.

Stolperfallen: Eine Spalte umzubenennen erzeugt einen destruktiven Plan (drop + add), bearbeite das SQL auf dem Generated SQL-Tab des Deployments, um RENAME COLUMN zu verwenden, wenn du Daten erhalten willst. Eine NOT NULL-Spalte ohne Default zu einer nicht-leeren Tabelle hinzuzufügen schlägt fehl, mach sie nullable, befülle nach, dann altere. Der Deploy-Symbolleisten-Button bringt dich zu einer Deployment-Konfigurationsseite, nicht direkt in ein Deploy.

Database Deployments

Listet jedes Deployment mit seinem Status (Draft / Executing / Succeeded / Failed) und führt neue aus. Route: /database-deployments/overview.

Oben rechts: Refresh (Liste neu laden), New Deployment (einen neuen Entwurf erstellen).

Aus dem Schema Designer: Der grüne Deploy-Button mit Raketensymbol in der Schema Designer-Symbolleiste bringt dich zu /database-deployments/configure/new, einer frischen Deployment-Konfigurationsseite.

Deployment-Konfigurationsseite: Zwei Tabs.

  • Configuration - Pre-/Post-Deployment-Skript-Editoren (PostgreSQL) mit je einem Test Run-Button. Pre-Skript läuft vor Schemaänderungen; Post-Skript danach. Nützlich für Befüllungen, Index-Wiederaufbau oder Staging-Bereich-Bereinigung. Plus ein Force Deploy (Allow Data Loss)-Toggle für destruktive Operationen.
  • Generated SQL - zeigt die Migration, die die Plattform erzeugt hat. Das SQL ist editierbar. Ein Regenerate-Button (Refresh-Icon) führt das Diff neu aus, falls du seit dem Öffnen dieser Seite Schemaänderungen gemacht hast.

Obere Buttons: Back, Save (speichert die Konfiguration als Draft), Deploy (führt das Deployment sofort aus). Deploy ist das, was du zuletzt klickst.

Stolperfallen: Deployments sind nicht automatisch in eine Transaktion eingewickelt, ein Fehler auf halbem Weg lässt die Datenbank in einem teilweisen Zustand zurück. Für riskante Migrationen wickle deine Statements in BEGIN; … COMMIT; im Pre-Skript ein. Der Force Deploy-Toggle überspringt Sicherheitsprüfungen; nutze ihn bewusst.

Business Entities

Kuratierte Sichten, gebaut auf einer Master-Tabelle plus Joins von verwandten Tabellen. Pages binden an Business Entities, nie an rohe Tabellen. Siehe Concepts → Business Entities für das Warum.

Gängiger Workflow: Klicke auf Create. Der ganzseitige Editor öffnet sich mit den Tabs Visual, JSON, Events. Setze Entity Name, Master Table (Autocomplete) und Label Column (die Spalte, deren Wert einen Datensatz in Pickern repräsentiert). Speichern, die BE erzeugt automatisch eine Liste nativer Spalten aus der Master-Tabelle.

Joins hinzufügen: Scrolle zur Join Configurator-Karte und klicke auf Add Join. Jeder Join öffnet sich als Accordion mit: Join Type (INNER / LEFT / RIGHT), From Table, To Table (Autocomplete gruppiert nach Database Tables / Third Party), From Column, To Column, optionale Type Cast-Dropdowns und einen Spalten-Picker, welche Zielspalten herausgereicht werden sollen.

Aggregationen: Auf einem Join schalte Aggregate Mode ein. Für jede gewählte Spalte wählst du dann eine Aggregate Function: COUNT / SUM / AVG / MIN / MAX / COUNT DISTINCT. "Anzahl offener Kontakte zu dieser Company" ist das kanonische Beispiel.

Run Preview: Der Editor hat einen Run Preview-Button (mit einem Play-Icon), der die vollständige Join-Konfiguration ausführt und echte Zeilen in einem Datengrid zeigt. Wenn eine Join-Spalte leer zurückkommt, wurde die Spalte im Spalten-Picker des Joins nicht angekreuzt (oder die Beziehung ist falsch konfiguriert).

Mehrere BEs pro Master-Tabelle: Nichts hindert dich daran, customer (sales view) und customer (support view) auf demselben Master zu haben. Verschiedene Pages, verschiedene zielgruppengerechte Spalten, dieselbe zugrundeliegende Zeile.

Stolperfallen: Gejointe und aggregierte Spalten sind schreibgeschützt. Um das gejointe Label zu bearbeiten, navigiere zum Quelldatensatz. Aggregierte Spalten werden bei jeder Query neu berechnet, in Ordnung für hunderte Zeilen, langsam bei Millionen.

Page Editor

Konfiguriert die Laufzeit-UI, indem eine Page an eine Business Entity gebunden wird. Die Plattform erzeugt automatisch Abschnitte basierend auf den BE-Spalten; du feinjustierst das Layout von dort. Es gibt keinen separaten "Template-Picker", jede Page startet von derselben erzeugten Basis und du passt sie an.

Gängiger Workflow: Klicke auf Create. Fülle Page Name, Page Route (z. B. /companies), wähle die Business Entity (Autocomplete). Die Page öffnet sich im Editor mit den Tabs Visual, Overview, Create, Entities, Events, JSON. Justiere das automatisch erzeugte Layout, dann schalte den Published-Switch im oberen Header auf AN.

Field-Widget-Typen (das Type-Select auf jedem Feld): Text, Textarea, Number, Date, Select, Checkbox, Email. Nutze Select für Fremdschlüssel-Felder und setze das Entity-Autocomplete des Feldes auf die referenzierte BE, damit Nutzer per Label auswählen.

Tabs im Detailformular: Klicke auf Add Tab im Visual-Tab. Innerhalb eines Tabs kannst du eine RelatedGrid-Sektion hinzufügen, die an eine andere BE gebunden ist, gefiltert nach dem PK des aktuellen Datensatzes. Klassisches Beispiel: eine Company-Page mit "Contacts"- und "Deals"-Tabs, jeweils gefiltert nach company_id = current company's id.

Aktions-Buttons im Header-Inspector des Detailformulars. Klicke auf Add im Actions-Bereich. Jede Action hat Label, Icon (Save / Delete / Add / Refresh / Download / Bolt / None), Variant (Contained / Outlined / Text), Color (Primary / Secondary / Error / Success / Warning / Info) und Steps (eine geordnete Liste aus: Save Record, Delete Record, Navigate, Business Events, Custom). Um ein Business Event von einem Button auszuführen, setze den Step-Typ auf Business Events und wähle das Event per Name.

Publishing: Der Published-Switch im oberen Header ist die einzige Publish-Steuerung. AN = die Page erscheint unter Published Pages in der Sidebar und Endnutzer, die zu ihrer Route navigieren, sehen sie. AUS = Entwurf (nur du siehst deine Änderungen im Editor).

Stolperfallen: Die automatisch erzeugten Spalten auf einer frischen Page spiegeln die BE, wenn sich die BE ändert (du fügst einen Join hinzu), wird die Page neue Spalten nicht automatisch übernehmen. Lade die Page im Editor neu oder füge die Spalte manuell zur Sektion hinzu. Es gibt aktuell keinen "Generate PDF"-Action-Step-Typ, um ein PDF an einen Page-Button zu binden, gib das PDF über ein Script Module heraus, das den REST-Endpunkt aufruft, und nutze einen Custom-Step (oder rufe den Endpunkt direkt aus einem Frontend Template auf).

Business Events

Regeln, die auf Datenänderungen feuern (oder nach Zeitplan, oder manuell) und Actions ausführen, wenn Conditions erfüllt sind. Der "wenn X passiert, tu Y"-Mechanismus der Plattform. Siehe Concepts → Business Events für das Modell.

Gängiger Workflow: Klicke auf Create. Setze Rule Name, schalte Enabled. Wähle Business Entity. Kreuze eine oder mehrere Triggers an: BeforeCreate / BeforeUpdate / AfterCreate / AfterUpdate / BeforeDelete / OnSchedule / Manual / InitialValue. Baue den Condition-Baum (AND/OR-Gruppen). Füge eine oder mehrere Actions im FlowCanvas hinzu. Speichern.

Action-Typen (RuleActionKind):

  • Execute Script - führt ein C#-Skript aus. Die flexibelste Action; greife danach, wann immer du ein Feld setzen, eine Berechnung machen, eine API aufrufen oder irgendwas Eigenes tun willst. Das Skript bekommt Entity (mutiere es auf Before*-Triggern, um den laufenden Schreibvorgang zu ändern), OldEntity, Log, Db, Modules.
  • Validate - ein Skript, das bool zurückgibt. true bedeutet, dass die Validierung fehlschlägt und das Speichern mit der konfigurierten Fehlermeldung blockiert wird. Hebt optional bestimmte Spalten über errorColumns hervor.
  • Block Operation - stoppt die Operation hart mit einer konfigurierten Nachricht. Kein Skript.
  • Create Entity - fügt einen Datensatz in eine andere BE ein. Feldwerte unterstützen Template-Ausdrücke wie {{ Entity.column_name }} und {{ now() }}.
  • Update Entity - aktualisiert Datensätze in einer anderen BE, die auf einen Bedingungsfilter passen. Gleiche Template-Ausdrücke.
  • Delete Entity - löscht Datensätze, die auf eine Bedingung passen. Verweigert ohne Bedingung (Sicherheit).
  • Send Email / Send Webhook / Publish Event - im Schema als zukünftige Erweiterungen definiert; aktuell geloggt und übersprungen.

"Set a field"-Muster: Es gibt keine eigene Set Field-Action. Der Weg, ein Feld zu setzen, ist ein Execute Script auf einem Before*-Trigger, das Entity mutiert. Beispiel: Entity.title = ((string)Entity.title)?.Trim();. Die Plattform persistiert die modifizierte Entity als Teil des laufenden Schreibvorgangs, keine zusätzliche Query, kein Rekursionsrisiko.

Run Simulation: Der Simulate-Tab des Trigger-Editors hat einen Datensatz-Picker und einen Run Simulation-Button. Die Plattform führt deine Conditions und Actions gegen den gewählten Datensatz aus, ohne Änderungen zu persistieren, Schreiboperationen laufen in einer Transaktion, die zurückgerollt wird. Das Ausgabe-Panel zeigt, welche Conditions zugetroffen haben und was jede Action getan hätte. Nutze das, um Fehlkonfigurationen zu fangen, bevor sie auf echte Daten treffen.

Template-Ausdrücke in der Action-Konfiguration nutzen {{ … }}-Klammern. Die tatsächlichen Tokens: {{ Entity.column }}, {{ OldEntity.column }}, {{ now() }} / {{ getdate() }}, {{ today() }}, {{ guid() }} / {{ newid() }}, {{ year() }}, {{ month() }}, {{ day() }}, {{ timestamp() }}, Aggregate wie {{ SUM(column) }} in Join-Kontexten und Post-Substitutions-Arithmetik wie {{ Entity.quantity * Entity.price }}. Es gibt keinen {{ user.email }}-Token.

Condition-Operatoren: Equals, NotEquals, GreaterThan, LessThan, GreaterThanOrEqual, LessThanOrEqual, Like (= ILIKE), Contains (= ILIKE %value%), IsNull, IsNotNull, In (= ANY(...)).

Stolperfallen: Ein Trigger, der denselben Datensatz mutiert, den er beobachtet, feuert sich selbst erneut, wenn du Update Entity nutzt; nutze stattdessen Before Update + Execute Script + Entity.field = …. Zwei Trigger auf demselben Event feuern in Prioritätsreihenfolge. Deaktivierte Events erscheinen weiterhin in der Liste, der Enabled-Toggle ist getrennt von der Trigger-Konfiguration.

Script Modules

Wiederverwendbare C#-Skripte, zur Laufzeit von Roslyn kompiliert. Nehmen Parameter, fragen die Datenbank über den Db-Helper ab, geben einen Wert zurück. Aufrufbar aus Business Events, Scheduled Events und direkt aus dem Frontend.

Gängiger Workflow: Klicke auf Create. Der Editor öffnet sich mit den Tabs Edit, Parameters, Test, JSON. Benenne das Modul (PascalCase, z. B. RecalcOpenRevenue). Im Parameters-Tab klicke pro Parameter auf Add (Name, Type, Required, Default Value). Type-Optionen: string, int, decimal, double, bool, DateTime. Zurück zum Edit-Tab, schreibe C#. IntelliSense ist an.

Test-Panel: Der Test-Tab zeigt deine Parameter-Eingaben links und einen Run-Button (PlayArrow-Icon). Klicke Run; die rechte Seite zeigt Erfolg- oder Fehler-Indikator, Ausgabe-Log und den Rückgabewert (JSON-formatiert).

Der Db-Helper, siehe die vollständige Referenz in Script-aufrufbare APIs unten.

Aufruf aus einem Business Event: Füge eine Execute Script-Action hinzu, deren Body das Modul aufruft:

await Modules.CallAsync("RecalcCompanyOpenDealValue", new Dictionary<string, object?> {
    ["company_id"] = Entity.company_id
});

Aufruf aus einem Scheduled Event: Erstelle ein Event mit dem On Schedule-Trigger, setze den Cron, füge eine Execute Script-Action mit demselben Modules.CallAsync-Body hinzu.

Logging: Jeder Aufruf schreibt einen Eintrag in Event Logs mit Ausführungszeit, Parametern und Ergebnis (oder Fehler).

Stolperfallen: awaite immer Db-Aufrufe, Vergessen kompiliert, gibt aber einen Task zurück. Rückgaben werden als Objekt durchgereicht (nicht vom Framework JSON-serialisiert); für die Frontend-Nutzung gib anonyme Objekte mit primitiven Feldern zurück. Suggestion-on-commit-character ist im Editor absichtlich deaktiviert; nutze Tab zum Akzeptieren.

Frontend Templates

Wiederverwendbare UI-Fragmente, in TSX geschrieben, die der Page Editor in eine Page ablegen kann. Nützlich, wenn die konfigurierten Templates nicht ausreichen, maßgeschneiderte Diagramme, ungewöhnliche Layouts, Integrationen von Drittanbieter-Widgets.

Gängiger Workflow: Klicke auf Create, benenne das Template, schreibe eine TSX-Komponente im Editor. Die Komponente erhält Props: record (die aktuelle Zeile, wenn in einem Detailformular eingebettet), refresh (Daten neu laden) und ein paar Helper. Speichern. Referenziere das Template aus einem Page Editor-Feld.

Paketierbar: Templates fließen wie jedes andere Konfigurationsobjekt durch das Package-System, sie werden mit kaskadiert, wenn eine Page, die sie nutzt, einem Package hinzugefügt wird.

Stolperfallen: Das TSX ist gesandboxt, du kannst keine beliebigen npm-Pakete importieren. Bleib bei React + den mitgelieferten Helpern.

PDF Templates

HTML + Scriban-Template + ein kleines C#-Data-Script, das in ein PDF rendert (headless Chromium). Jedes Template ist per Name aus einem Skript aufrufbar, über REST oder direkt von einem Button auf einer Page (mit einem kleinen Adapter, siehe unten).

Gängiger Workflow: Klicke auf + Create. Der Editor öffnet sich mit Name- und Description-Textfeldern oben, fünf Tabs auf der linken Seite (HTML Template, Data Script, Settings, Params, JSON) und einer immersichtbaren PDF Preview-Pane auf der rechten Seite. Die Tabs Data Script und HTML Template öffnen je einen Monaco-Editor auf der linken Hälfte; die Vorschau rendert neu, wenn du speicherst (grüner Update-Button oben rechts).

Deklariere Parameter im Params-Tab über den + Add-Button (Name, Type, Required, Default Value). Das Tab-Label aktualisiert sich auf Params (n) mit der Anzahl. Seitenformat / Orientierung / Ränder / Skalierung / Kopfzeile / Fußzeile leben im Settings-Tab.

Data-Script-Form (siehe PDF Invoices Tutorial für ein echtes Beispiel):

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 })
};

HTML-Template-Form (Scriban, ähnlich Liquid/Handlebars):

<h1>{{ InvoiceNumber }}</h1>
<table>
  {{ for line in Lines }}
  <tr><td>{{ line.description }}</td><td>{{ line.quantity }}</td></tr>
  {{ end }}
</table>

Preview-Pane: Immer sichtbar auf der rechten Seite des Editors. Rendert neu, wenn du speicherst (grüner Update-Button). Enthält eine Thumbnail-Spalte für mehrseitige PDFs und eine eingebaute Viewer-Symbolleiste (Zoom, Drehen, Download, Druck). Die Icon-Buttons oben rechts im Editor schalten die Sichtbarkeit der Preview-Pane und den Vollbild-Bearbeitungsmodus um.

Aufruf von außerhalb des Editors:

  • POST /api/v1/pdf-templates/{id}/preview - rendert nach ID, gibt application/pdf zurück. Wird von der Preview-Pane des Editors genutzt.
  • POST /api/v1/pdf-templates/generate/{name} - rendert nach Name, gibt application/pdf zurück.
  • POST /api/v1/pdf-templates/generate/{name}/base64 - gleich, gibt aber { "data": "<base64>" } zurück.

Übergib Parameterwerte im JSON-Body. Auth ist das standardmäßige Bearer-Token.

Trial-Einschränkung: Sowohl der generate-Endpunkt als auch der {id}/preview-Endpunkt (genutzt von der Preview-Pane des Editors) geben im Trial-Modus 403 zurück, PDF-Rendering ist komplett gesperrt. Du kannst das Template trotzdem bearbeiten (Data Script, HTML, Settings, Parameter) und speichern; du wirst nur kein gerendertes PDF sehen, bis du in einer bezahlten Umgebung bist.

Hinweis zum script-aufrufbaren Rendering: Der C#-Skripting-Kontext stellt kein Pdf-Global bereit. Um ein PDF heute aus einem Script Module zu rendern, rufe den generate-REST-Endpunkt über HttpClient auf. (Die Autocomplete des Skript-Editors bewirbt Pdf.RenderAsync für zukünftige Kompatibilität; die Laufzeit-Bindung ist noch nicht verdrahtet.)

Stolperfallen: Scriban escapt HTML standardmäßig. Seitenumbrüche sind CSS-gesteuert, page-break-before: always auf einer Sektion. Schriftarten, die auf dem Render-Server verfügbar sind, sind auf System-Schriften plus die Noto- und Liberation-Familien beschränkt, bette deine eigene per base64 @font-face ein, wenn du eine Markenschrift brauchst.

Scheduled Events

Dasselbe Event Trigger-System wie Business Events, mit dem On Schedule-Trigger angekreuzt. Nutze es für nächtliche Neuberechnungen, wöchentliche Digests, periodische Aufräumarbeiten, monatliche Berichte.

Gängiger Workflow: Erstelle ein Business Event mit dem On Schedule-Trigger (anstelle der oder zusätzlich zu den Datenänderungs-Triggern). Konfiguriere den Cron-Ausdruck. Füge eine Execute Script-Action hinzu, deren Body ein Script Module über Modules.CallAsync(...) aufruft.

Cron-Ausdrücke: Quartz-Style 6 oder 7 Felder, siehe Concepts → Scheduled Events für gängige Muster. Zeiten sind Serverzeit (UTC auf dem Produktions-Stack).

Stolperfallen: Ein langlaufender Job, der sein Cron-Intervall überzieht, verdoppelt sich nicht, Quartz feuert nicht zwei Instanzen desselben Jobs gleichzeitig, der zweite Tick wird übersprungen. Fehlgeschlagene Läufe wiederholen sich nicht automatisch; baue Retry in das Skript ein.

Packages

Exportierbare Bündel von Konfigurationsobjekten (BEs, Pages, Events, Scripts, Templates, Schema) mit kaskadierenden Abhängigkeiten. Eine Page einem Package hinzuzufügen zieht automatisch alles mit, was diese Page referenziert.

Gängiger Workflow (Export): Klicke auf Create, benenne und versioniere das Package. Füge die Top-Level-Objekte hinzu, die dich interessieren, meist eine Handvoll Pages. Öffne das Linked-Items-Panel, um die kaskadierte Liste zu sehen (was das Package tatsächlich enthalten wird). Hake alles ab, was du weglassen willst. Entscheide, ob Daten enthalten sein sollen (Toggle beim Export). Klicke auf Export, du bekommst ein ZIP.

Gängiger Workflow (Import): Öffne in der Zielumgebung Packages, klicke auf Import, lade das ZIP hoch. Die Plattform zeigt, was hinzugefügt oder aktualisiert wird. Schema-Deltas werden nicht automatisch angewendet, wenn das Package eine Spalte referenziert, die in der Zielumgebung nicht existiert, schlägt der Import fehl.

Stolperfallen: Identifikatoren sind nach Name, nicht nach numerischer ID. Eine BE namens "customer" in der Quelle bindet an eine BE namens "customer" im Ziel, benenne eine Seite um und die Verbindung bricht.

Third-Party Data Connections

Verbindungen zu externen Datenbanken (Postgres, SQL Server, MySQL, andere), die Tabellen nach Zeitplan importieren. Importierte Tabellen verhalten sich wie native Tabellen, sie tauchen im Schema Designer auf und können von Business Entities, Pages und Skripten referenziert werden.

Gängiger Workflow: Erstelle eine Verbindung (Connection String, Test, Speichern). Liste verfügbarer Remote-Tabellen; wähle, welche importiert werden sollen. Für jede importierte Tabelle setze Sync-Modus (Full / Delta) und Sync-Trigger (Cron / manuell / festes Intervall).

Gespiegelt, nicht föderiert: Die importierten Daten leben in deiner eigenen omnicore-db. Lesen ist schnell (lokales Postgres). Nachteil: Veralterung zwischen Syncs.

App-managed Spalten: Markiere einige Spalten als "von Archestack verwaltet", sie werden von zukünftigen Syncs nicht überschrieben. Nützlich, wenn du Lieferantendaten mit deinen eigenen Statusflags annotieren willst.

Stolperfallen: Der erste Sync einer großen Tabelle kann eine Weile dauern. Delta-Syncs erfordern eine Spalte, die der Connector als Wasserzeichen nutzen kann, meist ein modified_at-Timestamp.

AI Builder

Ein geführter Assistent, in dem du eine Funktion in natürlicher Sprache beschreibst und der Assistent einen Build-Plan generiert, Schema-Erweiterungen, BE-Änderungen, Pages, Events, die du zeilenweise prüfst und anwendest. Die Plangenerierung wird von einem externen LLM deiner Wahl gemacht (Claude, ChatGPT, Gemini), der Assistent komponiert einen eigenständigen Prompt zum Einfügen und akzeptiert die JSON-Antwort zurück. Es gibt keinen In-App-Chat-Assistenten mehr.

Gängiger Workflow: Beschreibe die Funktion in 1-3 Sätzen ("add support for service appointments, each one has a date, a customer, a vehicle, and a status"). Klicke auf Generate prompt, füge ihn in dein externes LLM ein, füge die JSON-Antwort zurück in den Import-Schritt ein, klicke auf Review. Hake ab, was du nicht willst. Klicke auf Apply.

Funktioniert gut für: CRUD-artige Funktionen, einfache Automatisierungen, geradlinige Erweiterungen bestehender Entitäten.

Weniger gut für: nicht-offensichtliche Geschäftsregeln, komplexe mehrstufige Workflows. Der Plan ist ein Ausgangspunkt, prüfe ihn wie den PR eines Junior-Devs.

Stolperfallen: Apply ist nicht rückgängig zu machen. Für riskante Funktionen mach erst ein Backup (oder wende es auf einer Trial-Umgebung an, evaluiere, dann baue auf Produktion aus dem resultierenden Package nach).

Object Browser

Rohe Sicht auf jede native und importierte Tabelle, Zeilen direkt hinzufügen, bearbeiten, löschen. Enthält einen CSV-Import zum Bulk-Laden.

Wann du danach greifst:

  • Bulk-Laden von Referenzdaten, bevor Pages existieren (Länder, Währungen, Status-Enums).
  • Debugging, anschauen, was tatsächlich in einer Tabelle ist, wenn sich eine Page seltsam verhält.
  • Schnelle Admin-Edits an Daten, die noch nicht über eine Page freigegeben sind.
  • CSV-Import: wähle eine Tabelle, lade eine Datei hoch, mappe Spalten zu Feldern, Vorschau, commit.

Stolperfallen: Object Browser feuert Business Events (er läuft denselben EntityService-Schreibpfad ab wie das Frontend). Die Ausnahme ist direktes SQL über Database Deployments, das umgeht alles.

Dependency Graph

Eine schreibgeschützte Karte davon, wie die Konfigurationsobjekte in deiner Umgebung aufeinander verweisen. Acht Ressourcentypen erscheinen als Knoten, eingefärbt nach Typ: Business Entities, Pages, Event Triggers, Script Modules, PDF Templates, Frontend Templates, Scheduled Events und Packages. Eine Kante zwischen zwei Knoten bedeutet, dass eine Ressource von der anderen abhängt. Greif danach, um die Fragen zu beantworten "was würde brechen, wenn ich das lösche?" und "ist hier irgendetwas ungenutzt?".

Was eine Kante bedeutet: eine Page, die an eine Business Entity gebunden ist, ein Event Trigger, der auf einer Business Entity registriert ist, ein Page-Aktionsschritt, der einen Event Trigger feuert, ein Skript, das ein anderes Script Module über Modules.CallAsync("Name") aufruft, ein Skript, das ein PDF Template rendert, ein Scheduled Event, der einen Event Trigger feuert, oder ein Package, das eine Ressource enthält. Es ist eine Design-Zeit-Sicht, sie spiegelt wider, was deine Konfiguration miteinander verdrahtet, nicht den Live-Laufzeit-Verkehr.

Zwei Arten von Problemen werden visuell hervorgehoben:

  • Loose ends (Waisen) - Knoten, auf die nichts verweist und die selbst auf nichts verweisen. Sie werden in einem rot umrandeten "Loose ends"-Band am unteren Rand der Leinwand gesammelt. Ein Script Module, das niemand aufruft; eine Page, die an nichts gebunden ist.
  • Dangling references - als rote gestrichelte Kanten gezeichnet. Der Verweis existiert in der Konfiguration, aber sein Ziel kann nicht gefunden werden, zum Beispiel ein Page-Aktionsschritt, der noch auf einen gelöschten Event Trigger zeigt, oder ein Skript, das ein Script Module unter einem Namen aufruft, der nicht mehr existiert.

Gängiger Workflow: öffne Dependency Graph aus dem Tools-Abschnitt der Sidebar. Das linke Panel hat eine Namenssuche, eine Layout-Auswahl (Left to right, Top to bottom, By type, Force-directed), die Schalter Group by package, Show loose ends und Show edges sowie eine Checkliste pro Typ. Klicke auf einen Knoten, um den Fokusmodus zu aktivieren: dieser Knoten und seine direkten Nachbarn bleiben hell, während der Rest des Graphen abdunkelt, sodass du genau nachverfolgen kannst, was eine Ressource berührt. Klicke auf den Leinwand-Hintergrund, um den Fokus aufzuheben. Jeder Knoten trägt einen kleinen Knopf, der die Ressource in einem neuen Tab öffnet, direkt in ihrem Editor. Die Statistikzeile oben meldet die Anzahl an Knoten, Kanten, Waisen und Dangling references.

Group by package: umrahmt die Mitglieder jedes Packages in einer beschrifteten gestrichelten Box, sodass du ein Package als Einheit siehst und die Ressourcen erkennst, die es per Kaskade hereingezogen hat.

Stolperfallen: der Graph wird bei Bedarf aus dem aktuellen Zustand aufgebaut, nutze den Refresh-Knopf, nachdem du anderswo Ressourcen geändert hast. Skript-abgeleitete Kanten werden gefunden, indem Skriptkörper nach der wörtlichen Modules.CallAsync("Name")-Aufrufform durchsucht werden, ein Module, das über einen berechneten Namen aufgerufen wird, zeigt keine Kante. Eine Dangling reference ist immer eine Behebung wert; eine Waise oft nicht, ein brandneues Script Module gilt als verwaist, bis etwas es aufruft.

Event Logs

Der Audit-Trail für alles, was die Plattform ausgeführt hat, Business Events, Script Modules, Scheduled Events, Third-Party-Syncs.

Gängiger Workflow: Öffne Event Logs, setze Status auf Failed, klicke in einen Eintrag. Das Detail-Panel zeigt die Payload (Datensatzzustand zum Zeitpunkt, übergebene Parameter), die Exception mit Stack Trace und das Timing.

Logs und Charts: Die Seite hat zwei Tabs, die sich eine Filterzeile teilen. Logs ist die Tabelle oben. Charts ist ein Betriebs-Dashboard über denselben Filter: Volumen im Zeitverlauf, gestapelt nach Status, ein Trend der Erfolgsquote, eine Aufschlüsselung pro Source, die Events mit den meisten Fehlern und die langsamsten Events, durchschnittliche und maximale Dauer im Zeitverlauf, eine Aufschlüsselung nach Trigger-Typ und eine Heatmap aus Wochentag und Tagesstunde, mit den wichtigsten Summen oben. Beide Tabs teilen sich einen Von / Bis Datumsbereich (mit den Presets Letzte 1h / 24h / 7d); der Charts-Tab wählt automatisch eine passende Bucket-Größe für den Zeitraum und kann sich in einem festen Intervall aktualisieren, für Live-Monitoring.

Echtzeit-Benachrichtigungen: Das Glockensymbol in der oberen Leiste der Admin-App zeigt ungelesene Fehler über SignalR an.

Stolperfallen: Das Log kann groß werden. Alte Einträge werden standardmäßig für immer aufbewahrt; wenn Platz ein Thema ist, richte ein Scheduled Event ein, das Einträge älter als N Tage löscht.

User Management

Nutzer anlegen, einladen und verwalten; Realm-Rollen zuweisen. Hüllt die Keycloak Admin REST API ein.

Rollen:

  • admin - alles; kann alle Business Units, Nutzer, Rollen, Systemeinstellungen verwalten.
  • owner - verwaltet ihre eigenen Business Units, kann Administrations- und Laufzeit-Pages bearbeiten.
  • editor - kann Laufzeit-Pages ansehen und bearbeiten, aber nicht Schema/BE/Event-Konfiguration ändern.
  • user - schreibgeschützt auf Laufzeit-Pages.

Stolperfallen: Einen Nutzer mitten in der Session von admin zu degradieren wirft ihn nicht raus, die Änderung greift beim nächsten Token-Refresh (typischerweise innerhalb einer Minute).

Business Units

Keycloak-gestützte Gruppen, die Sichtbarkeit auf einzelne Ressourcen steuern. Siehe Concepts → Business Units für das Modell.

Gängiger Workflow: Erstelle eine BU. Lade Mitglieder per E-Mail ein und wähle die Rolle. Weise Ressourcen zu, indem du zu jeder BE / Page / Trigger gehst oder über das Linked-Items-Panel der BU.

Kaskadierende Zuweisungen: Wenn du eine Page einer BU zuweist, kaskadiert die Zuweisung zur BE, an die die Page bindet.

Stolperfallen: Die aktive BU eines Nutzers wird im BU-Umschalter der oberen Leiste gesetzt und in localStorage persistiert. Neue Nutzer defaulten auf ihre erste BU; wenn eine Listen-Page verdächtig leer ist, prüfe, welche BU aktiv ist.

Database Backups

Nächtlicher pg_dump aller drei Datenbanken. Manueller Trigger / Upload / Restore aus der UI.

Gängiger Workflow: Trigger nowDownloadUploadRestore. Der Zeitplan ist standardmäßig nächtlich um 03:00 UTC.

Trial-Einschränkung: Backups sind in der Trial-Umgebung deaktiviert.

Branding

Ändert den Anzeigenamen der App, das Logo (hell + dunkel) und das Primärfarbschema, zur Laufzeit angewendet, ohne Neu-Build.

Gängiger Workflow: Setze den App-Namen, lade ein helles und ein dunkles Logo hoch (PNG/JPG/SVG, ≤ 10 MB), wähle eine Primär-Markenfarbe. Speichern. Browser aktualisieren.

Stolperfallen: Das Favicon wird nicht von Branding überschrieben, es ist im SPA gebündelt.

Translations

Key/Value-Editor für die UI-Strings der App. Neue Locales hinzufügen, Standardlabels pro Kunden überschreiben.

Gängiger Workflow: Wähle eine Locale, suche nach einem Key, tippe einen neuen Wert, speichere. Admin-App aktualisieren.

Stolperfallen: Übersetzungen werden einmal pro Session geladen; Nutzer auf einem veralteten Tab sehen Änderungen nicht, bis sie aktualisieren. Manche Labels (Spaltenüberschriften aus BEs) kommen aus der BE-Konfiguration, nicht aus Translations.


Script-aufrufbare APIs

Die exakte Oberfläche, die Skripte aufrufen können. Gegen den Quellcode verifiziert, jede Methode unten existiert tatsächlich.

Globals

Jedes Skript bekommt diese Top-Level-Variablen (keine anderen Namen existieren im Skript-Scope):

  • Entity - dynamic ExpandoObject. Aktueller Datensatz. Greife auf Felder mit Entity.column_name zu. Entity in einem Before*-Trigger zu mutieren persistiert die Änderungen als Teil des laufenden Schreibvorgangs.
  • OldEntity - dynamic ExpandoObject. Vorheriger Datensatz (Update- + Delete-Trigger). Schreibgeschützt.
  • Log - ILogger. Log.LogInformation("…"), Log.LogWarning(…), Log.LogError(…). Schreibt in Server-Logs und den Event Log-Eintrag.
  • Db - DbHelper. Datenbankzugriff (siehe unten).
  • Modules - ModulesHelper. Andere Script Modules aufrufen: await Modules.CallAsync("ModuleName", new Dictionary<string, object?> { ["param"] = value }). Gibt Task<object?> zurück.
  • Pdf - ScriptPdfHelper. Ein gespeichertes PDF Template per Name rendern: await Pdf.GenerateAsync("invoice", new Dictionary<string, string> { ["id"] = Entity.id.ToString() }) gibt byte[] zurück; await Pdf.GenerateBase64Async(…) gibt dieselbe Nutzlast base64-kodiert zurück. Parameter werden an das Data-Script des Templates als string-typisierte lokale Variablen weitergegeben.

Es gibt kein User, Http, Email, Templates oder irgendein anderes Global.

Db - Single-Row + Write-Methoden

Alle async, alle auf dem Top-Level-Db-Objekt:

  • await Db.GetAsync(string table, object id) - eine Zeile per Primärschlüssel holen. Gibt dynamic? zurück (oder null, wenn nicht gefunden).
  • await Db.CreateAsync(string table, object values) - einfügen. values kann ein anonymes Objekt oder ein Dictionary<string, object?> sein. Feuert Before/After Create-Trigger. Gibt int zurück (die neue ID).
  • await Db.UpdateAsync(string table, object id, object values) - per PK aktualisieren. Feuert Before/After Update-Trigger.
  • await Db.DeleteAsync(string table, object id) - per PK löschen. Feuert Before Delete-Trigger.

Db - fluenter Query-Builder

Beginne mit Db.From(table). Verkette Filter, dann ein Terminal:

  • .Where(string column, string op, object? value = null) - eine WHERE-Klausel hinzufügen. Operatoren: =, != / <>, >, >=, <, <=, LIKE, ILIKE, IN, IS NULL, IS NOT NULL. Mehrere .Where(...)-Aufrufe verketten für AND.
  • .OrderBy(string column, bool desc = false) - ORDER BY setzen. Nur eines pro Query erlaubt.
  • .Limit(int limit) - maximale Zeilen. Standard ist 1000.

Terminale (jedes führt die Query aus):

  • await ...ToListAsync() - gibt List<dynamic> zurück.
  • await ...FirstAsync() - gibt dynamic? zurück (erster Treffer oder null). Setzt das Limit vorübergehend auf 1.
  • await ...CountAsync() - gibt int zurück.

Es gibt kein SumAsync, MaxAsync, FirstOrDefaultAsync oder SingleAsync. Für Aggregationen hole mit ToListAsync() und reduziere in C#.

Durchgearbeitetes Beispiel

// 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;

Simulationsmodus

Während der Trigger-Simulation (der Run Simulation-Button auf einem Business Event) setzt die Plattform Db.SimulationMode = true. Alle Schreiboperationen (CreateAsync, UpdateAsync, DeleteAsync) laufen in einer PostgreSQL-Transaktion, die am Ende immer zurückgerollt wird. Leseoperationen funktionieren normal. Das ist, was Run Simulation sicher gegen echte Daten macht.

Modules

  • await Modules.CallAsync(string moduleName, Dictionary<string, object?>? parameters = null) - ein anderes Script Module per Name aufrufen. Parameter werden im Skript des aufgerufenen Moduls zu typisierten Variablen. Gibt Task<object?> zurück (was immer das Modul zurückgegeben hat).

Template-Ausdrücke (Business Event Actions)

Action-Konfiguration nutzt {{ … }}-Klammern. Die vollständige Liste gültiger Tokens:

  • {{ Entity.column_name }} / {{ Entity.id }}
  • {{ OldEntity.column_name }}
  • {{ now() }} / {{ getdate() }} - ISO 8601 UTC-Datetime
  • {{ today() }} - Datums-String
  • {{ guid() }} / {{ newid() }} - frische GUID
  • {{ year() }}, {{ month() }}, {{ day() }}, {{ timestamp() }} - Unix-Sekunden
  • {{ empty() }}, {{ null() }}
  • Aggregate in einem Join-Kontext: {{ SUM(column) }}, {{ AVG() }}, {{ COUNT() }}, {{ MIN() }}, {{ MAX() }}
  • Arithmetik: {{ Entity.quantity * Entity.price }} - nach der Substitution über DataTable.Compute() ausgewertet

Es gibt keinen {{ user.email }}- oder anderen nutzerbezogenen Token.