Darstellung
Flow-Builder
Der Flow-Builder steuert den strukturierten Gesprächsablauf eines Bots. Du definierst eine Abfolge von Steps, die der Bot durchläuft — von einfachen Textnachrichten über interaktive Buttons bis hin zu KI-gesteuerten Antworten und zeitverzögerten Nachrichten.
6 Block-Typen
Jeder Flow-Step hat einen step_type und eine step_config (JSONB). Die erlaubten Typen und ihre Pflichtfelder:
| step_type | Beschreibung | step_config Pflichtfelder |
|---|---|---|
text | Einfache Textnachricht | message (String, max 4096 Zeichen). Optional: typing_delay (0, 1, 2 oder 3) |
dsgvo | Datenschutz-Block | dsgvo_mode (consent, notice oder disabled) |
interactive | Buttons oder Liste (WhatsApp) | Benötigt block_id (Referenz auf bot_interactive_blocks) |
n8n | n8n Webhook-Aufruf | n8n_mode (fire_and_forget oder wait_for_response). Optional: timeout_seconds (1-60) |
delay | Zeitverzögerung | delay_mode (hours, days oder fixed_date). Bei hours/days: delay_value (min 0.01/1, max 365). Optional: message_after_delay (max 4096 Zeichen) |
ai | KI-gesteuerte Antwort | Optional: max_answers (0, 1, 3 oder 5), ai_prompt (max 4096 Zeichen) |
Universelle step_config Felder (alle Typen)
Zusätzlich zu den typspezifischen Feldern kann jeder Step diese Felder in step_config haben:
| Feld | Typ | Beschreibung |
|---|---|---|
conditions | Array | Bedingungen, wann der Step ausgeführt wird. Siehe FlowConditionEngine. |
condition_logic | String | OR (default) oder AND — Verknüpfung der Conditions |
exits | Object | Definierte Ausgänge (GOTO). Keys sind Exit-Namen, Values sind step_order (Zahl) oder 'end'. |
Flow-API-Endpoints
Alle Endpoints erfordern Auth + Tenant-Check. Basis-Pfad: /api/bots/:botId/flow
| Methode | Pfad | Beschreibung |
|---|---|---|
GET | / | Alle Flow-Steps eines Bots laden (sortiert nach step_order, mit Checkpoint-Info) |
POST | / | Neuen Step hinzufügen. Body: step_type, step_config, optional block_id, trigger_text, option_actions, step_order |
PUT | /reorder | Reihenfolge ändern. Body: order (Array von Step-IDs) |
GET | /generate-prompt | Flow-Prompt für den Bot generieren |
PUT | /:stepId | Einzelnen Step aktualisieren |
DELETE | /:stepId | Step entfernen |
Route-Reihenfolge
/reorder und /generate-prompt sind VOR /:stepId definiert (spezifisch vor generisch).
FlowConditionEngine
Die FlowConditionEngine steuert die Bedingungslogik und Navigation zwischen Steps. Sie verhindert Doppel-Senden und ermöglicht Verzweigungen.
Methoden
| Methode | Parameter | Beschreibung |
|---|---|---|
shouldExecuteStep(step, progress) | Step-Objekt, Progress-Record | Prüft ob ein Step ausgeführt werden soll. false wenn bereits besucht oder Conditions nicht erfüllt. |
getNextStep(step, exitKey, tenantId, botId, progress) | Aktueller Step, Exit-Key (z.B. 'default'), IDs, Progress | Bestimmt den nächsten Step. Prüft exits, dann linearen Nachfolger. |
getNextLinearStep(currentStep, tenantId, botId, progress) | Aktueller Step, IDs, Progress | Findet den nächsten ausführbaren Step nach step_order. Überspringt Steps deren Conditions nicht erfüllt sind. |
recordChoice(contactId, botId, stepOrder, optionId) | IDs, Step-Nummer, gewählte Option | Speichert eine User-Auswahl (Button/Liste) im Progress. |
markStepVisited(contactId, botId, stepOrder) | IDs, Step-Nummer | Markiert einen Step als besucht (verhindert Doppel-Senden). |
resetProgress(contactId, botId) | IDs | Setzt den Flow-Progress zurück (z.B. bei neuem Gespräch). |
getProgress(contactId, botId) | IDs | Lädt den aktuellen Progress für einen Kontakt. |
Conditions (AND/OR Logik)
Conditions prüfen, welche Optionen der User in vorherigen Steps gewählt hat:
json
{
"conditions": [
{ "source_step_order": 2, "option_id": "ja" },
{ "source_step_order": 3, "option_id": "premium" }
],
"condition_logic": "AND"
}- OR (default): Mindestens eine Condition muss erfüllt sein
- AND: Alle Conditions müssen erfüllt sein
Die Choices werden im choices-Feld des Progress-Records als { "step_order": "option_id" } gespeichert.
Exits-System
Exits definieren wohin der Flow nach einem Step springt:
json
{
"exits": {
"default": 5,
"success": 3,
"error": "end"
}
}- Ziel kann eine
step_order(positive Zahl) oder'end'(Flow beenden) sein - Der Exit-Key wird beim Aufruf von
getNextStep()übergeben - Wenn kein passender Exit-Key gefunden wird, fällt die Engine auf
'default'zurück - Wenn weder passender Key noch
'default'vorhanden: Flow-Stopp (NICHT linear weiter), sofern sowohl Conditions als auch Exits definiert sind - Ohne Exits: linearer Fallback zum nächsten Step nach
step_order
Datenbank-Schemas
bot_flow_steps
| Spalte | Typ | Nullable | Default | Beschreibung |
|---|---|---|---|---|
| id | uuid | NOT NULL | gen_random_uuid() | Primary Key |
| tenant_id | uuid | NOT NULL | — | FK auf tenants |
| bot_id | uuid | NOT NULL | — | FK auf bots |
| block_id | uuid | NULL | — | FK auf bot_interactive_blocks (nur bei step_type='interactive') |
| step_order | integer | NOT NULL | 0 | Position im Flow |
| trigger_text | varchar(255) | NULL | — | Auslöse-Text |
| option_actions | jsonb | NULL | '{}' | Aktionen pro Option (altes System) |
| is_active | boolean | NULL | true | Aktiv/Inaktiv |
| created_at | timestamptz | NOT NULL | CURRENT_TIMESTAMP | Erstelldatum |
| updated_at | timestamptz | NOT NULL | CURRENT_TIMESTAMP | Änderungsdatum |
| step_type | varchar(20) | NOT NULL | 'interactive' | Block-Typ (interactive, text, dsgvo, consent, n8n, delay, ai) |
| step_config | jsonb | NOT NULL | '{}' | Typ-spezifische Konfiguration |
Indizes:
bot_flow_steps_bot_id_block_id_unique— UNIQUE auf (bot_id, block_id)bot_flow_steps_bot_id_step_order_index— btree auf (bot_id, step_order)bot_flow_steps_tenant_id_index— btree auf (tenant_id)idx_flow_steps_step_type— btree auf (bot_id, step_type)
contact_flow_progress
| Spalte | Typ | Nullable | Default | Beschreibung |
|---|---|---|---|---|
| id | uuid | NOT NULL | gen_random_uuid() | Primary Key |
| contact_id | uuid | NOT NULL | — | FK auf contacts |
| bot_id | uuid | NOT NULL | — | FK auf bots |
| tenant_id | uuid | NOT NULL | — | FK auf tenants |
| current_step_order | integer | NULL | 1 | Aktueller Step |
| flow_completed | boolean | NULL | false | Flow abgeschlossen? |
| flow_started_at | timestamptz | NULL | CURRENT_TIMESTAMP | Start-Zeitpunkt |
| flow_completed_at | timestamptz | NULL | — | Abschluss-Zeitpunkt |
| updated_at | timestamptz | NULL | CURRENT_TIMESTAMP | Letzte Änderung |
| choices | jsonb | NOT NULL | '{}' | Gewählte Optionen pro Step: {"step_order": "option_id"} |
| visited_steps | jsonb | NOT NULL | '[]' | Liste besuchter step_orders |
| last_sent_block_id | uuid | NULL | — | FK auf bot_interactive_blocks |
| status | varchar(20) | NULL | 'active' | Status des Progress-Records |
| step_data | jsonb | NOT NULL | '{}' | Zusätzliche Step-Daten |
Constraint: UNIQUE auf (contact_id, bot_id) — ein Progress-Record pro Kontakt/Bot-Paar.
Status-Werte: active, waiting_delay, waiting_ai
scheduled_flow_steps
| Spalte | Typ | Nullable | Default | Beschreibung |
|---|---|---|---|---|
| id | uuid | NOT NULL | gen_random_uuid() | Primary Key |
| tenant_id | uuid | NOT NULL | — | FK auf tenants |
| bot_id | uuid | NOT NULL | — | FK auf bots |
| contact_id | uuid | NOT NULL | — | FK auf contacts |
| step_id | uuid | NOT NULL | — | FK auf bot_flow_steps |
| scheduled_at | timestamp | NOT NULL | — | Geplanter Ausführungszeitpunkt |
| cancel_on_reply | boolean | NULL | true | Bei User-Antwort abbrechen? |
| status | varchar(20) | NULL | 'pending' | Status (pending, executed, cancelled) |
| cancelled_reason | varchar(50) | NULL | — | Grund der Stornierung |
| created_at | timestamp | NULL | now() | Erstelldatum |
| executed_at | timestamp | NULL | — | Ausführungszeitpunkt |
Indizes:
idx_scheduled_pending— Partial Index auf (status, scheduled_at) WHERE status='pending'idx_scheduled_contact— btree auf (contact_id, status)uq_scheduled_step_pending— UNIQUE auf (contact_id, step_id) WHERE status='pending'
Partial Unique Index
Der Unique-Constraint uq_scheduled_step_pending gilt NUR für status='pending'. Dadurch kann ein Kontakt denselben Step mehrfach durchlaufen — aber nie zwei gleichzeitig wartende Delays für denselben Step haben.
DelayExecutorJob
Der DelayExecutorJob ist ein Background-Job, der fällige Delay-Steps ausführt.
Konfiguration
| Parameter | Wert | Beschreibung |
|---|---|---|
| Polling-Intervall | 60 Sekunden | Prüft alle 60s auf fällige Delays |
| Batch-Größe | 10 | Maximal 10 Delays pro Durchlauf |
Ablauf
- Fällige Delays laden:
status='pending'ANDscheduled_at <= NOW() - Atomisch auf
executedsetzen (verhindert Doppel-Ausführung) message_after_delayan den Kontakt senden (falls konfiguriert)- Flow fortsetzen via
FlowConditionEngine.getNextStep()
delay_mode
| Modus | Beschreibung | delay_value |
|---|---|---|
hours | Verzögerung in Stunden | 0.01 – 365 |
days | Verzögerung in Tagen | 1 – 365 |
fixed_date | Festes Datum/Uhrzeit | Nicht verwendet (scheduled_at wird direkt gesetzt) |
Fehlerbehandlung
Bei Ausführungsfehlern wird der Status auf cancelled gesetzt mit cancelled_reason: 'execution_error', damit der Delay nicht endlos wiederholt wird.