UNPKG

@directus/api

Version:

Directus is a real-time API and App dashboard for managing SQL database content

541 lines (449 loc) 12.9 kB
Manage automation flows that enable event-driven data processing and task automation. Flows consist of a trigger and a series of operations forming a data chain. <flow_concepts> ## Key Concepts **Flow** = Trigger + Operations + Data Chain - Each flow has ONE trigger that starts execution - Operations execute sequentially, passing data through the chain - Data chain accumulates results from each step After creating a flow, use the `operations` tool to add individual operations with detailed operation syntax, positioning, and data chain usage. </flow_concepts> <core_fields> ## Flow Data Structure All flows share these core fields for creation: - `name` (required) - Flow display name - `trigger` (required) - Trigger type: `event`, `webhook`, `schedule`, `operation`, `manual` - `status` - `active` or `inactive` (default: `active`) - `accountability` - `all`, `activity`, or `null` (default: `all`) - `icon` - Icon identifier (optional) - `color` - Hex color code (optional) - `description` - Flow description (optional) - `options` - Trigger-specific configuration object (optional) - `operation` - UUID of first operation (optional, set after creating operations) </core_fields> <crud_actions> ## Actions - ALWAYS show the flow URL if it is present in the result ### `read` - List/Query Flows ```json { "action": "read", "query": { "fields": ["id", "name", "status", "trigger", "operations"], "filter": { "status": { "_eq": "active" } }, "limit": 10 } } ``` ### `create` - Create New Flow **Required**: `name`, `trigger` ```json { "action": "create", "data": { "name": "Send email when new post is published", "icon": "bolt", // Optional icon "color": "#FFA439", // Optional hex color "description": "checks if new post is published and emails admin", "status": "active", // active|inactive "accountability": "all", // all|activity|null "trigger": "event", // event|webhook|schedule|operation|manual "options": { // Trigger-specific configuration "type": "action", "scope": ["items.create"], "collections": ["posts"] } } } ``` ### `update` - Modify Existing Flow ```json { "action": "update", "key": "flow-uuid", "data": { "status": "inactive", "description": "Updated description" } } ``` ### `delete` - Remove Flow ```json { "action": "delete", "key": "flow-uuid" } ``` </crud_actions> <trigger_types> ## Trigger Types & Options ### Event Hook Trigger Responds to data changes and system events ```json { "trigger": "event", "options": { "type": "filter", // filter (blocking) | action (non-blocking) "scope": ["items.create", "items.update"], "collections": ["orders", "products"], "return": "process_data" // For filter only: <operationKey>|$all|$last (avoid $last) } } ``` **Common Scopes**: - `items.create`, `items.update`, `items.delete` - Data operations - `auth.login` - User authentication - **Note**: Multiple scopes trigger flow for ANY matching event ### Webhook Trigger ```json { "trigger": "webhook", "options": { "method": "POST", // GET|POST "async": false, // true = immediate response, false = wait for completion "return": "transform_result", // Response body: <operationKey>|$all|$last (avoid $last) "cache": false // Cache GET responses } } ``` ### Schedule Trigger (CRON) ```json { "trigger": "schedule", "options": { "cron": "0 */15 * * * *" // Every 15 minutes } } ``` **CRON Format**: `second minute hour day month weekday` **Examples**: - `"0 0 9 * * *"` - Daily at 9 AM - `"0 30 * * * *"` - Every 30 minutes (note: runs at :30 of each hour) - `"0 */15 * * * *"` - Every 15 minutes ### Manual Trigger UI button that users click to start flows ```json { "trigger": "manual", "options": { "collections": ["posts", "products"], "location": "item", // item|collection|both "requireSelection": false, // Default true - requires item selection "requireConfirmation": true, "confirmationDescription": "AI Ghostwriter", "async": true, // Run in background "fields": [ { "field": "prompt", "type": "text", "name": "Prompt", "meta": { "interface": "input-multiline", "note": "Describe what you want to create.", "width": "full", "required": true } }, { "field": "voice", "type": "json", "name": "Tone Of Voice", "meta": { "interface": "tags", "options": { "presets": ["friendly", "professional", "casual"] } } }, { "field": "colors", "type": "json", "name": "Color Palette", "meta": { "interface": "list", "options": { "fields": [ { "field": "color", "type": "string", "meta": { "interface": "select-color" } }, { "field": "name", "type": "string", "meta": { "interface": "input" } } ] } } } ] } } // Access confirmation inputs: {{ $trigger.body.prompt }}, {{ $trigger.body.voice }} ``` **Field Options**: Supports non-relational Directus interfaces - `input`, `input-multiline`, `input-rich-text-md`, `tags`, `list`, `select-color`, `select-radio`, `collection-item-dropdown`, etc. ### Operation Trigger (Another Flow) ```json { "trigger": "operation", "options": { "return": "final_result" // Data to return to calling flow: <operationKey>|$all|$last (avoid $last) } } ``` </trigger_types> <operations_integration> ## Working with Operations **Use the `operations` tool for complete details on:** - Creating and linking operations - 14x14 grid positioning system - Data chain variable syntax - Operation-specific configuration **Critical Workflow - Follow This Order:** 1. Create flow first (using `flows` tool) 2. Create all operations with null resolve/reject initially (using `operations` tool) 3. Link operations together using UUIDs from step 2 4. Update flow to set first operation as entry point **Why This Order:** Operations must exist before they can be referenced. UUIDs only available after creation. **Complete Example:** ```json // Step 1: Create flow {"action": "create", "data": { "name": "Email on Post Published", "trigger": "event", "options": {"type": "action", "scope": ["items.create"], "collections": ["posts"]} }} // Returns: {"id": "flow-uuid-123"} // Step 2: Create operations with null connections {"action": "create", "data": { "flow": "flow-uuid-123", "key": "check_status", "type": "condition", "position_x": 19, "position_y": 1, "options": {"filter": {"$trigger": {"payload": {"status": {"_eq": "published"}}}}}, "resolve": null, "reject": null }} // Returns: {"id": "condition-uuid-456"} {"action": "create", "data": { "flow": "flow-uuid-123", "key": "send_email", "type": "mail", "position_x": 37, "position_y": 1, "options": {"to": ["admin@example.com"], "subject": "New post", "body": "{{$trigger.payload.title}}"}, "resolve": null, "reject": null }} // Returns: {"id": "email-uuid-789"} // Step 3: Link operations via UUIDs {"action": "update", "key": "condition-uuid-456", "data": { "resolve": "email-uuid-789" }} // Step 4: Set flow entry point {"action": "update", "key": "flow-uuid-123", "data": { "operation": "condition-uuid-456" }} ``` </operations_integration> <flow_chaining> ## 🔗 Flow Chaining **When to Chain**: Reusable utilities, complex multi-step workflows, conditional branching **How to Chain**: 1. Child flow: `"trigger": "operation"`, `"return": "final_key"` or `"$last"` 2. Parent flow: Use `trigger` operation with child flow UUID and payload 3. Access child results: `{{ trigger_operation_key }}` **Common Utility Patterns**: ```json // Utils → Get Globals (called by multiple flows) { "name": "Utils → Get Globals", "trigger": "operation", "options": { "return": "$last" } } // Utils → Send Email (reusable email sender) { "name": "Utils → Send Email", "trigger": "operation", "options": { "return": "$last" } } // Main flow calls utility { "type": "trigger", "key": "globals", "options": { "flow": "utils-globals-uuid" } } // Access: {{ globals.openai_api_key }} ``` **Multi-Chain Example** (Form Notifications): ```json // Chains: Read Form → Format → Render Template → Send Email { "type": "trigger", "key": "render", "options": { "flow": "utils-render-template-uuid", "payload": "{{ format }}" } } ``` **Best Practices**: - Name utilities with "Utils →" prefix for clarity - Use `$last` return for simple utilities, specific keys for complex ones - Chain utilities together for modular, reusable workflows - Keep each utility focused on single responsibility </flow_chaining> <data_chain_warning> ## Data Chain Access Operations can access data using `{{ variable }}` syntax: - `{{ $trigger.payload }}` - Trigger data - `{{ $accountability.user }}` - User context - `{{ $env.VARIABLE_NAME }}` - Environment variables - `{{ operation_key }}` - Result from specific operation (recommended) - `{{ operation_key.field }}` - Specific field from operation result - `{{ $last }}` - Previous operation result (⚠️ avoid - breaks when reordered) **Always use operation keys** for reliable flows. If you reorder operations, `$last` will reference a different operation. </data_chain_warning> <real_world_examples> ## Real-World Examples ### Post Approval Email (Event-Driven) ```json { "action": "create", "data": { "name": "[Website] Post Approval", "icon": "mark_email_read", "color": "#18222F", "description": "Send email when posts are ready for review", "status": "active", "trigger": "event", "accountability": "all", "options": { "type": "action", // Non-blocking "scope": ["items.update"], "collections": ["posts"] } } } // Then add operations: Check Status → Send Email ``` ### Auto-Generate Slugs (Event-Driven) ```json { "action": "create", "data": { "name": "[Website] Slugify", "icon": "link", "color": "#18222F", "description": "Generate slugs for pages, posts, and categories", "status": "active", "trigger": "event", "accountability": "all", "options": { "type": "action", "scope": ["items.create"], "collections": ["pages", "posts", "categories"] } } } ``` ### Create Scheduled Task ```json { "action": "create", "data": { "name": "Daily Report", "trigger": "schedule", "status": "active", "options": { "cron": "0 0 9 * * *" // 9 AM daily } } } ``` ### Project Creator with Template (Manual + Confirmation) ```json { "action": "create", "data": { "name": "[Projects] Create Project", "trigger": "manual", "status": "active", "options": { "collections": ["os_projects", "organizations"], "requireSelection": false, // Can trigger without selection "requireConfirmation": true, "confirmationDescription": "Create a New Project 🚀", "fields": [ { "field": "name", "type": "string", "name": "Project Name", "meta": { "interface": "input", "required": true } }, { "field": "organization", "type": "json", "name": "Organization", "meta": { "interface": "collection-item-dropdown", "required": true, "options": { "selectedCollection": "organizations" } } } ] } } } ``` ### Utility Flow (Operation Trigger) ````json { "action": "create", "data": { "name": "[Util] Get Globals", "trigger": "operation", "accountability": "all", "options": { "return": "global_data" // Returns data to calling flow: <operationKey>|$all|$last } } } // Called by other flows using trigger operation ``` </real_world_examples> <important_notes> ## Important Notes - **Admin Required**: This tool requires admin permissions - **Data Format**: Pass `data` as native objects, NOT stringified JSON - **Flow Execution**: Flows with `operations` array will include their operations - **Webhook URL**: After creating webhook trigger, URL is `/flows/trigger/<flow-id>` - **Event Blocking**: Filter events pause transaction until flow completes - **Logs**: Flow executions are logged (check `accountability` setting) </important_notes> <common_mistakes> ## Common Mistakes to Avoid 1. **DO NOT** create operations here - use the `operations` tool 2. **DO NOT** trigger flows here - use the `trigger-flow` tool 3. **DO NOT** pass stringified JSON in data parameter 4. **DO NOT** forget required fields: `name` and `trigger` for creation 5. **DO NOT** put options outside of data - it goes inside the flow object: ```json // ✅ CORRECT { "action": "create", "data": { "name": "My Flow", "trigger": "event", "options": { "type": "action" } } } // ❌ WRONG { "action": "create", "data": { "name": "My Flow", "trigger": "event" }, "options": { "type": "action" } } ``` </common_mistakes> ````