Welche Sprache wo?
Pantarey wertet an vielen Stellen Ausdrücke aus: im Prozess Designer, im Daten Designer, in Formularen, Dashboards und in der Datenanalyse. Dahinter stehen fünf Mechaniken, die sich in Schreibweise und Verhalten unterscheiden. Die meisten Fehler entstehen, wenn ein Feld in der einen Sprache beschrieben wird, aber eine andere erwartet. Diese Seite ist die Landkarte: welches Feld welche Sprache erwartet, was $ oder der Kontext dort bedeutet und wie ein typischer Ausdruck aussieht. Die einzelnen Sprachen haben eigene Seiten: JSONata in Pantarey, Template-Funktionen $fn, Handlebars-Helfer.
Die fünf Mechaniken
JSONata. Das ganze Feld ist ein Ausdruck, der aus der Nachricht oder dem Datensatz ein Ergebnis berechnet: ein Feld, ein neues Objekt, eine gefilterte Liste. Ein leeres Feld lässt die Daten unverändert; ein Ausdruck ohne Ergebnis ist ein Fehler. Felder stehen ohne Klammern: antrag_db.mitarbeiter.
Platzhalter $(pfad) mit $fn(…). In Textfeldern wie Vorgangskennung, Betreff oder Dateiname wird jeder Platzhalter durch den Wert des Pfads ersetzt, der Rest des Texts bleibt stehen. Funktionen wie $fn('str_upper', $(name)) formen den Wert um; ein fehlender Wert ergibt leeren Text.
JavaScript. Gateway-Bedingungen, berechnete Felder und Prüfregeln mit Sprache JavaScript sowie Formular-Bedingungen werden als JavaScript ausgewertet. Am Gateway werden zuerst die $(…)-Platzhalter ersetzt, dann läuft der Vergleich; im Daten Designer stehen $, obj und root für den Datensatz.
Handlebars. HTML- und Textvorlagen für PDF, E-Mail und externe Aufgaben verwenden {{feld}}-Blöcke mit einem zentralen Satz von Helfern. Der Kontext ist das Ergebnis des zugehörigen Daten-Mappings, ohne Mapping die ganze Eingabe der Aktivität.
SQL. Abfragen im Datenbank-Element, die Live-Daten der externen Aufgabe, das Formularfeld Werte laden, die Datenanalyse und SQL-Widgets sind SQL (Athena/Trino). Platzhalter $(…) und $fn('sql_list', …) gibt es nur im Datenbank-Element und in den Live-Daten; Formular und Analyse kennen stattdessen Systemplatzhalter wie @currentUserEmail.
Quer durch alle Mechaniken gehen zwei Token: {{value:name}} setzt einen Wert ein und wird vor allem anderen ersetzt, aber nur in Designer-Texten, nie in Formular- oder Datensatzdaten. {{secret:NAME}} setzt ein Secret ein und wirkt ausschließlich in den Eingaben von Service-Aufgaben an dafür freigegebenen Pfaden, etwa headers.Authorization beim HTTP-Aufruf.
Erkennungsregel
Ob ein Feld JSONata oder Platzhalter erwartet, verrät sein Label: Felder mit dem Zusatz (JSONata) nehmen einen ganzen Ausdruck, alle anderen Textfelder nehmen Text mit $(…)-Platzhaltern.
| Erkennung | Sprache | Feld lesen | Beispiel |
|---|---|---|---|
| Ganzes Feld ist ein Ausdruck | JSONata | feld, $.feld, $$.feld |
antrag_db.mitarbeiter |
| Platzhalter im Text | $(pfad) + $fn |
$(feld), $($$context.feld) |
Urlaub $(antrag_db.von) prüfen |
| Vergleich am Gateway | JavaScript nach $(…) |
$(feld) |
$(pruefung.ok) === false |
{{…}} in einer Vorlage |
Handlebars | {{feld}} |
{{currency_eur betrag}} |
select … from … |
SQL | Spaltennamen, in der Datenbank '$(feld)' |
select id from invoices where kunde = '$(kunde)' |
Ort in der App
Die Tabelle nennt die Felder mit ihrer Bezeichnung in der Oberfläche. „Nachricht“ ist das JSON, das durch den Prozess wandert, siehe Daten im Prozess; „Eingabe“ ist die Nachricht nach dem Input-Ausdruck der Aktivität.
Prozess Designer: Aufgaben, Daten & Variablen
| Ort in der App | Sprache | Was $ bzw. der Kontext ist |
Beispiel |
|---|---|---|---|
| Daten & Variablen konfigurieren → Input-Ausdruck (JSONata) | JSONata | $ = aktuelle Nachricht, $$ = Wurzel der Nachricht; $fn(…) verfügbar, {{value:…}} vorher eingesetzt |
{ "to": antrag_db.mitarbeiter, "von": $fn('date_toGermanDate', antrag_db.von) } |
| Daten & Variablen konfigurieren → Output-Ausdruck (JSONata) | JSONata | $ = Rohergebnis der Aktivität |
payload.body.pdf |
| Daten & Variablen konfigurieren → Ergebnispfad | Pfad (Kleinbuchstaben, Unterstrich, Punkte) + $(…) |
Platzhalter werden gegen das Ergebnis des Schritts aufgelöst, nicht gegen die Nachricht; __proto__, constructor, prototype sind verboten |
ergebnis_$(schritt) |
| Eigenschaften → Technisch → Vorgangskennung | $(pfad) + $fn(…) |
aktuelle Nachricht beim Erreichen des Elements; in Schleifen je Durchlauf das aktuelle Element | RE-$(rechnung_db.prio_seq) $fn('str_upper', $(kunde.name)) |
| Benutzeraufgabe → Anzeigetext | $(pfad) + $fn(…) |
wie Vorgangskennung | Rechnung $(rechnung_db.prio_seq) prüfen |
| Benutzeraufgabe → Zuweisung („Wer soll die Aufgabe durchführen?“) | $(pfad) + $fn(…) |
wie Vorgangskennung | $($$context.executedBy) |
| Benutzeraufgabe → Benutzerdefiniertes Formular, Formular (erweitert) | erst $(…)-Ersetzung, dann JSONata |
das Formular-JSON ist ein JSONata-Ausdruck über die Nachricht; Ergebnis muss die Feldliste sein | [ { "template": request_summary.html }, { "key": "begruendung", "type": "input" } ] |
| Benutzeraufgabe → Zeitlimit Datum aus Prozessdaten | $(pfad) |
ISO-Datum oder Sekunden aus der Nachricht | $(deadline) |
| Zwischenereignis Timer → Wartezeit (Sekunden) | $(pfad) |
Ergebnis wird als Zahl gelesen | $(wartezeit) |
| Signal werfen → Nutzdaten, Signalname | $(pfad) im JSON-Text |
gegen die Nachricht; das Ergebnis muss gültiges JSON bleiben | { "orderId": "$(orderId)" } |
Startereignisse
| Ort in der App | Sprache | Was $ bzw. der Kontext ist |
Beispiel |
|---|---|---|---|
| Startereignis (Zeitplan, einfaches Startereignis) → Input-Ausdruck (JSONata) | JSONata | $ = Startnachricht, beim Timer nur { "$$context": … }. Beim Benutzer-Start wird der Input-Ausdruck übersprungen; die Formulardaten werden unverändert zur Nachricht |
{ "stichtag": $substring($now(), 0, 10) } |
Input und Ergebnis des Startereignisses sind auf je 50 KB Text begrenzt; die Validierung meldet sonst „Start Event Nachricht überschreitet Größenlimit (max. 50 KB)“. Mehr zu den Startarten unter Startereignisse.
Gateway
| Ort in der App | Sprache | Was $ bzw. der Kontext ist |
Beispiel |
|---|---|---|---|
| Sequenzfluss am XOR-Gateway → condition expression | JavaScript nach $(…)-Ersetzung |
Textwerte werden automatisch in "…" gesetzt (außer der Platzhalter steht schon in Anführungszeichen), fehlende Werte werden zu undefined, null bleibt null, Objekte werden JSON; {{value:…}} typgerecht; kein $, kein $$, kein JSONata |
$(pruefung.ok) === false, $(manager_approval.$$context.selectedAction) === 'approve', $(betrag) > {{value:schwelle}} |
| Gateway → Default Flow | – | Flows ohne Bedingung (außer dem Default) sind ein Fehler („Ausgehende Flows ohne Bedingung gefunden“); treffen alle Bedingungen nicht zu und es gibt keinen Default, scheitert der Schritt („Kein Default-Pfad definiert …“); der erste zutreffende Flow in Modellreihenfolge gewinnt |
Die Regeln für Bedingungen stehen unter Gateway und Bedingungen.
Datenbank-Element
| Ort in der App | Sprache | Was $ bzw. der Kontext ist |
Beispiel |
|---|---|---|---|
| Datenbank-Element (eingehend) → Input, Operationen Write, Update, Merge | JSONata, danach $(…)-Ersetzung über den JSON-Text des Ergebnisses |
JSONata gegen die Nachricht; $(…) in Textwerten des Schreibobjekts werden danach noch ersetzt |
$sift(vacation_user_entry, function($v, $k) { $k != '$$context' }) |
| Datenbank-Element Delete → Objekt-ID | $(pfad) |
gegen die Nachricht | $(antrag_db.id) |
| Datenbank-Element Read → Object id | $(pfad) |
muss nach der Ersetzung eine 26-stellige ULID sein, sonst „Ungültige ID angegeben“ | $(kunde.id) |
| Datenbank-Element Read → Object prefix | $(pfad) |
Präfix des Dokumentnamens | 2026/$(monat) |
| Datenbank-Element Read → Abfrage | SQL mit $(pfad), $fn('sql_list', …), $fn('sql_raw', …) |
Textwerte gehören in '…'; außerhalb von Anführungszeichen sind nur Zahlen, true, false und null erlaubt; ein Wert mit ' wird gemeldet |
select id from invoices where kunde IN ($fn('sql_list', $(kunden))) |
| Datenbank-Element Read → Output, Ergebnispfad | JSONata, Pfad | $ = gelesenes Objekt bzw. Liste |
$[0] |
Service-Aufgaben: PDF, E-Mail, Graustufen, Handlebars
| Ort in der App | Sprache | Was $ bzw. der Kontext ist |
Beispiel |
|---|---|---|---|
| E-Mail versenden an externe Empfänger → Betreff | $(pfad) + $fn(…), einzeilig |
gegen die Eingabe der Aktivität | Rechnung $(rechnung.nummer) |
| E-Mail → Empfänger (An, Cc, Bcc), Absender-E-Mail, Antwort an | JSONata, Adressen als Text toleriert | JSONata gegen die Eingabe; sieht der Text wie eine Adresse oder Adressliste aus (a@b.de, Name <a@b.de>, Komma, Semikolon, Zeilenumbruch), gilt er wörtlich |
kunde.email, info@firma.de, [antrag_db.mitarbeiter, "chef@firma.de"] |
| E-Mail → Anhänge | JSONata | Ergebnis sind Dateiverweise { "referenceId": …, "filename": …, "contentType": … }; alles ohne referenceId wird verworfen |
invoice.pdfReference, [rechnung_pdf, anlage] |
| E-Mail → HTML-Dateninput (JSONata) | JSONata | leer → die ganze Eingabe ist Handlebars-Kontext | { "customer": customer, "items": positions } |
| E-Mail → HTML-Inhalt | Handlebars | Kontext = Ergebnis des HTML-Dateninputs; {{value:…}} wird erst hier eingesetzt |
{{currency_eur betrag}} |
| PDF erstellen aus Template → Daten (JSONata) | JSONata | $ = Eingabe der Aktivität |
$.invoice |
| PDF → PDF Template (HTML + Handlebars) | Handlebars | Kontext = Ergebnis von Daten (JSONata), leer → ganze Eingabe | {{kunde.name}} |
| PDF → Dateiname | $(pfad) + $fn(…) |
gegen die ganze Eingabe, unabhängig vom Daten-Mapping; / wird -; leer = document.pdf; der erweiterte Editor ist hier aus |
Rechnung_$(invoiceNumber).pdf |
| PDF in Graustufen umwandeln → Eingabe-Datei (JSONata) | JSONata | muss ein Datei-Objekt mit referenceId liefern; Standard $.document |
attachment, files[0] |
| Text aus Vorlage erstellen (Handlebars) | Handlebars; Eingabe per Input-Ausdruck { content, template } |
content ist der Kontext, template die Vorlage |
{ "content": $, "template": "Hallo {{name}}" } |
| E-Mail aus Vorlage (SMTP, Microsoft 365, interne Vorlage) | Handlebars | Kontext = contentData; SMTP rendert HTML, Betreff und Text, Microsoft 365 nur den Inhalt (Betreff nicht), die interne Vorlage Inhalt und Betreff |
Externe Aufgabe
| Ort in der App | Sprache | Was $ bzw. der Kontext ist |
Beispiel |
|---|---|---|---|
| Externe Aufgabe → HTML-Seite, Betreff, E-Mail-Text, Teams-Text, Seiten „Bereits beantwortet“, „Erfolg“, „Abgelaufen“, „Abgebrochen“, Erfolgsseite je Aktion | Handlebars, gleicher Helfer-Satz wie PDF und E-Mail | Kontext = data der Eingabe (Standard-Input { "data": $ }), sonst die ganze Eingabe; dazu die Marker %%EXTERNAL_URL%%, %%FILE:var%% und <button data-action="…">, die kein Handlebars sind |
{{name}} |
| Externe Aufgabe → Benachrichtigung: Empfänger, Cc, Bcc, Absenderadresse | $(pfad) |
data und Wurzel der Eingabe gemischt, bei gleichen Namen gewinnt die Wurzel |
max@firma.de, $(email) |
| Externe Aufgabe → Live-Daten SQL-Abfrage | SQL mit $(…) und $fn('sql_list', …) |
gegen data; einmal beim Anlegen der Aufgabe ausgeführt, Ergebnis in der Seite als window.__liveData |
select * from auftrag where id = '$(auftrag_id)' |
Daten Designer
| Ort in der App | Sprache | Was $ bzw. der Kontext ist |
Beispiel |
|---|---|---|---|
| Attribut → Reiter Berechnet → Sprache JSONata oder JS, siehe Berechnete Felder | JSONata oder JavaScript | JSONata: $ = Datensatz bzw. Listenzeile, $root = ganzer Datensatz, $old = gespeicherter Vorzustand (null bei Neuanlage). JS: $, obj, root, $old |
$sum(positionen.(menge * preis)), $old.status != status ? $now() : $old.status_seit |
| Reiter Validierung → Sprache, Ausdruck, Fehlermeldung, siehe Prüfregeln | JSONata oder JavaScript; Fehlermeldung mit $(feldname) |
JSONata: $ und $root = Datensatz, kein $old; JS: $, obj, root = Datensatz; Regel erfüllt = wahr |
bis >= von; „Bis $(bis) darf nicht vor Von $(von) liegen.“ |
| Attribut → Reiter Bedingungen (Pflichtfeld, ausblenden, deaktivieren), siehe Dynamische Formulare | JavaScript im Browser | data (ganzer Datensatz), model (Elternobjekt, in Listen die Zeile), field, formControl, value, loaded (Werte aus Werte laden) |
model.status === 'abgelehnt' |
| Attribut → Ersatzwert | $(pfad) + $fn(…) |
gegen den Datensatz beim Speichern, nur wenn das Feld leer ist | $fn('nextId', 'kunde') |
| Dokumentenname, Dokumentennamen-Baukasten, siehe Dokumentname | $(pfad) + $fn(…) |
gegen den Datensatz; Wertelisten-Werte sind vorher durch ihre Beschriftung ersetzt; / im Wert wird -, / in der Vorlage bildet Ordner; Ergebnis wird auf 500 Zeichen gekürzt |
$fn('date_toPath', $(datum))/R-$fn('str_padStart', $(prio_seq), 5, '0') |
Formular: Werte laden
| Ort in der App | Sprache | Was $ bzw. der Kontext ist |
Beispiel |
|---|---|---|---|
Formularfeld Werte laden (sql-values), siehe Formulare |
SQL mit Systemplatzhaltern @currentUserEmail, @currentDate, @currentYear |
keine $(…)-Platzhalter, keine Formularwerte; Ergebnis liegt unter loaded.<key> im Formularzustand, nicht im Datensatz |
SELECT CAST(work_days AS JSON) AS work_days FROM employees WHERE lower(e_mail) = lower('@currentUserEmail') |
Dashboards
| Ort in der App | Sprache | Was $ bzw. der Kontext ist |
Beispiel |
|---|---|---|---|
| Widget Datensatz → Datensatz-Anzeige konfigurieren → JSONata-Ausdruck | JSONata im Browser, ohne $fn und andere Pantarey-Funktionen |
gegen die Nachricht des Kanals, root = Nachricht; Ergebnis ist ein Objekt oder eine ID, leer oder null lässt den aktuellen Datensatz stehen; Ausdruck testen mit Beispiel-Nachricht (JSON) |
rechnungsempfaenger |
| Widget Planungstafel → Absicht → Bedingung und Texte | Bedingung: JSONata im Browser; Texte: $(entry.x), $(row.x), $(range.start), $(user.email), $(choice) |
Kontext { entry, row, range, user }, entry und row enthalten Daten und Metafelder gemischt; true bietet die Aktion an, false oder kein Ergebnis verbirgt sie, ein Text zeigt sie deaktiviert mit diesem Grund |
entry.status = 'geplant' |
Datenanalyse
| Ort in der App | Sprache | Was $ bzw. der Kontext ist |
Beispiel |
|---|---|---|---|
| Datenanalyse, SQL in Widgets | SQL | Systemplatzhalter @currentUserEmail, @currentDate; keine $(…)-Platzhalter |
Die häufigsten Verwechslungen
$(feld)in einem JSONata-Feld. Im Input- oder Output-Ausdruck ist$(…)ein Funktionsaufruf und scheitert. In JSONata steht das Feld ohne Klammern:feldoder$.feld.- JSONata im Betreff. Der Betreff ist Text mit Platzhaltern.
rechnung.nummerbleibt dort wörtlich stehen; richtig istRechnung $(rechnung.nummer). {{secret:NAME}}im Formular oder in einer Benutzeraufgabe. Der Token bleibt als Text stehen. Secrets wirken nur in den Eingaben von Service-Aufgaben an freigegebenen Pfaden, siehe Secrets.$fn('sql_list', …)in JSONata. Die Meldung lautet „fn(): not allowed in jsonata: 'sql_list'“.sql_listundsql_rawgehören in SQL-Abfragen mit$(…); in JSONata wird eine Liste direkt gebaut./wird zu-. Bei jedem$(…)-Platzhalter wird ein Schrägstrich im Wert zum Bindestrich, nicht nur im Dokumentnamen, sondern auch im Betreff, in der Vorgangskennung und im Dateinamen. Ausnahme: Gateway-Bedingungen.- Das Gateway kennt kein
$. Eine Bedingung ist JavaScript;$,$$und JSONata-Funktionen gibt es dort nicht.$$contextist nur innerhalb eines Platzhalters erreichbar:$(aufgabe.$$context.selectedAction) === 'approve'.
Regeln der Platzhalter
- Ein Platzhalter ist
$(pfad); im Pfad sind Buchstaben, Ziffern,_,.,$,-,@,#und%erlaubt, deshalb geht$($$context.executedBy). - Ein fehlendes Feld oder
nullergibt leeren Text. Zahlen und Wahrheitswerte werden Text, Objekte und Listen werden JSON,/in Textwerten wird-. Die Pfadteile__proto__,constructorundprototypeergeben immer leeren Text. - Reihenfolge: zuerst das innerste
$fn(…), dann$(…)und die alten Schreibweisen$nextCounter(…),$ulid(),$dateToPath(…),$toGermanDate(…), zuletzt$fnnoch einmal. Klammern und Kommas in Textargumenten gehören in'…'. - Argumente von
$fnmit$kommen als Text an („0815“ bleibt „0815“); Literale ohne$werden umgewandelt (5wird Zahl,true,false,null;'5'bleibt Text). - Längen: Vorgangskennung 500, Anzeigetext 300, Zuweisung 200, Ergebnispfad 1000 Zeichen. Wird eine Grenze überschritten, scheitert der Schritt mit
FIELD_LENGTH_EXCEEDED. Der Dokumentname wird bei 500 Zeichen gekürzt statt abgelehnt. - Am Gateway gelten andere Regeln: Textwerte werden in
"…"gesetzt, fehlende Werte werdenundefined,/bleibt/.
Werte und Secrets
{{value:name}} wird in allen Designer-Texten ersetzt, in Code-Feldern typgerecht (ein Objekt-Wert bleibt Objekt, ein Text in JSONata wird zu "…"), in Textfeldern als Text. Der Deploy prüft unbekannte Namen. In PDF- und E-Mail-HTML-Vorlagen wird der Wert erst beim Rendern eingesetzt. Alles dazu unter Werte im Prozess.
{{secret:NAME}} ersetzt Pantarey nur in Service-Aufgaben an den Pfaden, die der jeweilige Service freigibt, etwa URL und Autorisierungs-Header beim HTTP-Aufruf, Zugangsdaten bei SMTP, Microsoft 365, FTP, SharePoint, Teams oder E-POST. Außerhalb davon bleibt der Token stehen. Alles dazu unter Secrets.
Beispiel
Im Prozess „Urlaub beantragen“ der Musterfirma GmbH schreibt „Antrag speichern“ den Datensatz mit dem Input
$sift($, function($v, $k) { $k != '$$context' })(JSONata) und dem Ergebnispfadantrag_db. Die Benutzeraufgabe „Urlaubsantrag genehmigen“ hat den AnzeigetextUrlaub $(antrag_db.mitarbeiter) vom $fn('date_toGermanDate', $(antrag_db.von))(Platzhalter). Das Gateway dahinter prüft$(entscheidung.$$context.selectedAction) === 'approve'(JavaScript). „Zusage senden“ baut die E-Mail mit dem Input-Ausdruck (JSONata), der Betreff lautetUrlaub genehmigt: $(antrag_db.von)(Platzhalter), der HTML-Inhalt nutzt{{von}}(Handlebars).
Häufige Fragen
Woran erkenne ich, ob ein Feld JSONata oder Platzhalter erwartet?
Am Label. Steht dort (JSONata), ist das ganze Feld ein Ausdruck und ein Feld wird ohne Klammern angesprochen. Sonst ist es ein Textfeld, in dem nur $(…)-Platzhalter ersetzt werden.
Warum steht im Betreff mein Ausdruck wörtlich drin?
Der Betreff nimmt Platzhalter, kein JSONata. kunde.name bleibt Text; $(kunde.name) wird ersetzt.
Kann ein Platzhalter auf $$context zugreifen?
Ja, mit $($$context.executedBy) für den letzten Schritt oder $(aufgabe.$$context.selectedAction), wenn das Ergebnis der Aufgabe unter aufgabe liegt.
Funktionieren $fn-Funktionen im Dashboard?
Nein. Das Datensatz-Widget und die Planungstafel werten JSONata im Browser aus, ohne Pantarey-Funktionen. Dort gilt nur die JSONata-Standardbibliothek.
Warum ändert sich mein Ordner-Trennzeichen im Betreff?
Platzhalter wandeln / in Textwerten immer in - um. Soll ein Ordner im Dokumentnamen entstehen, gehört der / in die Vorlage, nicht in den Wert.
Nächster Schritt
JSONata in Pantarey: Variablen,
$$context, zehn Grundmuster, Fehlerverhalten und Testen mit der Live-Vorschau.