Workflows & Notifications
Workflows automate multi-step processes in your application. They can be triggered by entity events, manual actions from the UI, or webhooks.
Defining a Workflow
Section titled “Defining a Workflow”[workflow.SetIssueStatus]description = "Update issue status and write an audit event."
[workflow.SetIssueStatus.trigger]manual = true
[[workflow.SetIssueStatus.steps]]type = "query"entity = "Issue"action = "update"[workflow.SetIssueStatus.steps.where]id = "{{ variables.data.record.id }}"[workflow.SetIssueStatus.steps.data]status = "{{ variables.data.payload.status }}"Trigger Types
Section titled “Trigger Types”Manual Triggers
Section titled “Manual Triggers”Triggered from the UI via action bar buttons on detail pages:
[workflow.ApproveRequest.trigger]manual = trueWire it to a page action bar:
[[page."/issues/:id".actionBar.actions]]label = "Approve"workflow = "ApproveRequest"style = "primary"Entity Event Triggers
Section titled “Entity Event Triggers”Fire when records are created, updated, or deleted:
[workflow.NotifyOnDone.trigger]entity = "Issue"event = "update"
[workflow.NotifyOnDone.trigger.condition]"after.status" = "done""before.status" = { "$ne" = "done" }The condition uses before.* and after.* to compare the record’s state before and after the change. The $ne operator means “not equal”.
Webhook Triggers
Section titled “Webhook Triggers”Receive events from external systems:
[workflow.HandleSlackCommand.trigger]webhook = "/webhooks/slack"Step Types
Section titled “Step Types”Query Steps
Section titled “Query Steps”Perform database operations:
[[workflow.MyWorkflow.steps]]type = "query"entity = "Issue"action = "update"[workflow.MyWorkflow.steps.where]id = "{{ variables.data.record.id }}"[workflow.MyWorkflow.steps.data]status = "closed"Actions: create, update, delete, findOne.
Condition Steps
Section titled “Condition Steps”Branch based on previous step results:
[[workflow.MyWorkflow.steps]]type = "condition"if = { "steps.0.result.id" = { "$exists" = true } }then = [ { type = "query", entity = "Issue", action = "update", where = { id = "{{ variables.data.record.id }}" }, data = { status = "awaiting_approval" } }]else = [ { type = "query", entity = "AuditEvent", action = "create", data = { issueId = "{{ variables.data.record.id }}" } }]Notify Steps
Section titled “Notify Steps”Send notifications via configured adapters:
[[workflow.MyWorkflow.steps]]type = "notify"adapter = "slack_dispatch"body = "Issue resolved: {{ trigger.after.title }}"[workflow.MyWorkflow.steps.metadata]mrkdwn = trueWebhook Steps
Section titled “Webhook Steps”Make HTTP requests to external services:
[[workflow.MyWorkflow.steps]]type = "webhook"url = "https://api.example.com/events"method = "POST"body = { issueId = "{{ variables.data.record.id }}" }Template Variables
Section titled “Template Variables”Workflow steps can reference data using {{ }} template syntax:
| Variable | Description |
|---|---|
variables.data.record | The current record |
variables.data.payload | Data sent with the action |
trigger.before | Record state before update (event triggers) |
trigger.after | Record state after update (event triggers) |
steps.N.result | Result of step N (zero-indexed) |
Notifications
Section titled “Notifications”Notifications are delivered through adapters. Configure them in the [notifications] section.
Console Adapter
Section titled “Console Adapter”Logs to stdout (useful for development):
[[notifications.adapters]]name = "console"type = "console"Slack Adapter
Section titled “Slack Adapter”Posts messages to Slack channels:
[[notifications.adapters]]name = "slack_ops"type = "slack"[notifications.adapters.config]botTokenEnv = "SLACK_BOT_TOKEN"signingSecretEnv = "SLACK_SIGNING_SECRET"defaultChannel = "#ops"| Config | Description |
|---|---|
botTokenEnv | Environment variable holding the Slack bot token |
signingSecretEnv | Environment variable for webhook signing secret |
defaultChannel | Default channel for messages |
defaultChannelEnv | Env var for default channel |
The Slack adapter also handles inbound webhooks for interactive messages.
Email Adapter
Section titled “Email Adapter”Sends email notifications:
[[notifications.adapters]]name = "email"type = "email"[notifications.adapters.config]from = "noreply@example.com"outboxFile = "./data/email-outbox.log"Setting a Default
Section titled “Setting a Default”[notifications]default = "console"The default adapter is used when a notify step doesn’t specify an adapter.