Workflows
The workflow system provides state machine automation for any collection. Workflows control how items move between states (e.g., draft → review → published), who can trigger each transition, and what side effects run automatically.
Concepts
| Concept | Description |
|---|---|
| Workflow Definition | JSON state machine stored in daas_wf_definition |
| Workflow Assignment | Links a workflow to a collection + optional filter rule |
| Workflow Instance | Created automatically when a matching item is created |
| Transition | Moving from one state to another via a named command |
| Action | An event emitted after a successful transition |
Workflow Definition Structure
{
"initial_state": "Draft",
"states": [
{
"name": "Draft",
"commands": [
{
"name": "Submit",
"next_state": "Pending Approval",
"policies": [],
"actions": []
}
],
"isEndState": false
},
{
"name": "Pending Approval",
"commands": [
{
"name": "Reject",
"next_state": "Draft",
"policies": [],
"actions": []
},
{
"name": "Approve",
"next_state": "Published",
"policies": ["550e8400-e29b-41d4-a716-446655440000"],
"actions": [
{
"name": "Publish",
"event_name": "xtr.item.promote",
"parameters": {}
}
]
}
],
"isEndState": false
},
{
"name": "Published",
"commands": [],
"isEndState": true
}
]
}State fields
| Field | Type | Description |
|---|---|---|
name | string | Unique state identifier |
commands | array | Available transitions from this state |
isEndState | boolean | Terminal state — no further transitions |
Command fields
| Field | Type | Description |
|---|---|---|
name | string | Unique command identifier |
next_state | string | State to transition to |
policies | string[] | Required policy UUIDs — user must hold at least one |
actions | array | Events to emit after transition |
Action fields
| Field | Type | Description |
|---|---|---|
name | string | Human-readable label |
event_name | string | Event emitted — xtr.item.promote or custom |
parameters | object | Extra data passed to the event handler |
Automatic Instance Creation
When an item is created in a collection that has a Workflow Assignment, the system automatically:
- Checks
daas_wf_assignmentfor matching assignments (by collection + filter rule) - Creates a
daas_wf_instancewithcurrent_stateset toinitial_state - Updates the item’s workflow instance field and state field
Exactly one assignment must match per item. If zero match, the workflow is skipped. If multiple match, an error is logged and no instance is created.
Required collection fields
Two fields must exist in the collection: a Many-to-One link to daas_wf_instance and a Workflow State string field.
New collections — enable both switches in the collection creation wizard under System Fields → Workflow Fields:
| Switch | Field created | Details |
|---|---|---|
| Workflow Instance | workflow_instance | M2O to daas_wf_instance, nullable UUID |
| Workflow State | workflow_state | xtr-interface-workflow interface, read-only |
Existing collections — add the fields manually via Data Model → [Your Collection] → New Field:
| Field type | Interface | Purpose |
|---|---|---|
Many-to-One → daas_wf_instance | M2O | Stores the workflow instance ID |
| String | xtr-interface-workflow (Workflow State) | Stores the current state name |
Mark both as read-only in the field metadata — users should not edit them directly.
Execute a Transition
POST /api/workflow/transition{
"workflowInstanceId": "uuid",
"commandName": "Approve"
}Success (200):
{ "message": "Successfully transitioned workflow state" }Unauthorized (403):
{ "message": "You are not authorized to perform this transition" }The endpoint:
- Validates the command exists in the current state
- Checks the user holds at least one required policy UUID (directly or via role)
- Updates
current_stateindaas_wf_instance - Records the transition in
daas_wf_history - Updates the workflow state field in the target collection or version
- Fires all configured actions in sequence
Built-in Actions
xtr.item.promote
Promotes a content version to the main item. Only runs when the workflow instance is linked to a version (version_key is not null).
{ "name": "Promote to Main", "event_name": "xtr.item.promote", "parameters": {} }Custom actions
Register any event_name in a file-based extension or runtime extension:
export function register(sdk) {
sdk.emitter.onAction('xtr.notification.send-email', async (meta, context) => {
// action parameters are spread onto meta.payload[0] alongside workflow_instance
const { recipient, workflow_instance } = meta.payload[0];
await sendEmail(recipient, 'Workflow state changed');
});
}Workflow Assignments
Assignments connect a workflow definition to a collection with an optional filter rule:
{
"collection": "articles",
"workflow": "workflow-definition-uuid",
"filter_rule": { "category": { "_eq": "news" } }
}An empty filter_rule matches all items in the collection.
Version Workflows
Workflows can track content versions. When a version is created:
- The filter rule is tested against the parent item (not the version itself)
- The instance is linked with a
version_key - The
xtr.item.promoteaction applies the version delta to the main item
Best Practices
- One assignment per collection/filter combination — avoid overlapping filter rules
- Mark workflow fields as read-only — users should not manually edit
workflow_instanceorworkflow_state - Use empty
policiesarrays for commands that any authenticated user can trigger - Test filter rules with Supabase queries before production
REST API
| Method | Path | Description |
|---|---|---|
GET | /api/workflows | List workflow definitions |
POST | /api/workflows | Create workflow definition |
GET | /api/workflows/:id | Get workflow definition |
PATCH | /api/workflows/:id | Update definition |
DELETE | /api/workflows/:id | Delete definition |
GET | /api/workflow-instances | List instances |
GET | /api/workflow-instances/:id | Get instance |
GET | /api/workflow-instances/:id/history | List transition history for an instance |
GET | /api/workflow-assignments | List assignments |
POST | /api/workflow-assignments | Create assignment |
GET | /api/workflow-assignments/:id | Get assignment |
PATCH | /api/workflow-assignments/:id | Update assignment |
DELETE | /api/workflow-assignments/:id | Delete assignment |
POST | /api/workflow/transition | Execute transition |