drupal flowdrop integration guide
Drupal FlowDrop Integration Guide
Overview
FlowDrop is a visual, drag-and-drop workflow editor for Drupal that enables developers to build sophisticated automation workflows without extensive code. Built by Factorial GmbH, FlowDrop provides a modern alternative to traditional rules engines, combining visual workflow design with support for AI integration, data processing, and automated job execution.
FlowDrop is designed to work seamlessly with Drupal's ecosystem, particularly integrating with the ECA (Event-Condition-Action) module to create powerful, event-driven automation workflows.
Key Capabilities
- Visual Workflow Builder - Modern drag-and-drop interface for designing workflows
- AI & LLM Integration - Direct support for language model calls, embeddings, and semantic operations
- External API Connectivity - Connect to third-party services and APIs
- Data Processing - Transform, validate, and manipulate data within workflows
- Automated Execution - Run complex multi-step processes with conditional logic
- Plugin Architecture - Extensible attribute-based system for custom node processors
Project Status
- Created: July 2025
- Maintainers: d34dman, muschpusch, stmh (Factorial GmbH)
- Current Version: 1.x-dev (actively developed)
- Installation Status: 157 total issues, 97 open (as of Dec 2025)
- Security Note: Not covered by Drupal's security advisory policy - use at own risk in production
Architecture
Core Components
FlowDrop operates on a node-based, event-driven architecture similar to visual programming tools like Node-RED, LangFlow, and n8n.
1. Node System
Workflows are built from interconnected nodes, each representing a specific operation or data transformation:
- Input Nodes - Receive data from events, API calls, or manual triggers
- Processing Nodes - Transform, validate, and manipulate data
- Decision Nodes - Conditional logic to branch workflow execution
- Integration Nodes - Connect to external services (APIs, LLMs, databases)
- Output Nodes - Send results to Drupal entities, external services, or logs
- Loop Nodes - Iterate over collections with complex logic
Each node has:
- Input Ports - Data flowing into the node
- Output Ports - Data flowing out to other nodes
- Configuration - Node-specific settings via attributes
- Error Handling - Graceful failure and fallback logic
2. Data Flow
The visual representation in FlowDrop directly mirrors data flow during execution:
Event Trigger Input Nodes Processing Pipeline Decision Points Output Nodes
Extract Data Transform Data Route Data
Data flows through connections (wires) between nodes:
- Each connection carries data from one node's output port to another node's input port
- Nodes execute when all required inputs are available
- Data is typically JSON, allowing nested objects and arrays
- Context stacks support multiple data chains in parallel
3. Execution Engine
FlowDrop integrates with Drupal's event system and ECA:
- Event Trigger - A Drupal event fires (entity saved, form submitted, API call, etc.)
- Workflow Invocation - FlowDrop retrieves the associated workflow configuration
- Node Processing - Nodes execute in dependency order
- Data Propagation - Output from one node becomes input for dependent nodes
- Result Output - Final output nodes produce results (side effects, return values)
- Completion - Workflow marks completion with status and results
4. Plugin Architecture
FlowDrop uses Drupal's attribute-based plugin system for extensibility:
/** * Defines a FlowDrop node processor plugin. * * @FlowDropNodeProcessor( * id = "my_custom_processor", * label = @Translation("My Custom Processor"), * description = @Translation("Processes custom data"), * category = "custom" * ) */ class MyCustomProcessor extends NodeProcessorBase { public function process(array $inputs): array { // Implementation } }
Creating Workflows
Visual Workflow Creation
Step 1: Access the Workflow Builder
- Navigate to Admin Automation Workflows FlowDrop
- Click Create new workflow
- Enter workflow name and description
- Choose trigger event (Drupal event)
Step 2: Add Nodes
- Click the Add Node button or use the node palette
- Select node type from available categories:
- Data Input/Output
- Transformations
- Conditionals
- AI/ML Operations
- API Integrations
- Custom Nodes
- Drag node to canvas
- Position and arrange nodes logically
Step 3: Configure Nodes
- Click on a node to select it
- Configure in the Node Properties panel:
- Set input parameters
- Define processing logic
- Configure output mapping
- Use visual feedback to see expected data flow
Step 4: Connect Nodes
- Click the output port of a source node
- Drag to the input port of a target node
- Release to create a connection (wire)
- Connection visualizes data flow direction
- Multiple connections possible from single port
Step 5: Test and Deploy
- Use Test Workflow to validate logic
- Provide test input matching trigger event
- Review execution trace and results
- Deploy when satisfied with behavior
Example Workflow: Content Enrichment with AI
This example demonstrates using FlowDrop to automatically enrich content with AI-generated summaries:
[Node 1: Entity Event Trigger]
(passes: entity data)
[Node 2: Extract Field Data]
Input: entity.body.value
[Node 3: AI LLM Call - Generate Summary]
Input: body content
Model: gpt-4 (via AI module)
Prompt: "Create a 2-sentence summary"
[Node 4: Validate Summary Length]
Condition: length > 10 && length < 500
True branch
[Node 5: Update Entity Field]
Set: entity.summary = AI output
False branch
[Node 6: Log Error]
Result: error handling
[Node 7: Save Entity & Log Success]
[Workflow Complete]
Example Workflow: Multi-Step API Orchestration
Demonstrating complex data processing and external service integration:
[Trigger: Node API Call Received]
(passes: request body)
[Parse JSON Input]
[For Each Item in Array]
[Call External API - Geocoding]
Input: address from item
Output: coordinates
[Call External API - Weather]
Input: coordinates
Output: weather data
[AI LLM - Generate Report]
Input: combined geocoding + weather
Output: human-readable report
[Aggregate Result]
Append to results array
[Return Aggregated Results]
[Workflow Complete]
Node Types
Data Input/Output Nodes
Entity Event Trigger
Purpose: Initiates workflow based on Drupal entity events
Events: entity_created, entity_updated, entity_deleted, entity_view
Output: entity object, entity_id, changed fields
Configuration:
- Entity type (node, user, term, etc.)
- Bundle (optional)
- Operations (create, update, delete)
API Request Input
Purpose: Accepts data from HTTP requests
Trigger: Incoming POST/GET/PUT/DELETE
Output: request body, headers, query parameters
Configuration:
- HTTP method(s)
- Endpoint path
- Authentication required
- Request schema validation
Extract Data
Purpose: Extract specific fields/values from data
Input: any object/array
Output: extracted values
Configuration:
- Path expression (JSON path, tokens)
- Default values
- Type coercion (string, number, boolean)
Example: Extract $entity.field_title.value
Return Data
Purpose: Output workflow results
Input: any data
Output: HTTP response / side effects
Configuration:
- Return format (JSON, HTML, redirect)
- Status code
- Headers to include
- Response transformation
Processing & Transformation Nodes
Text Transformation
Purpose: Manipulate text data
Operations:
- Trim, uppercase, lowercase, reverse
- Concatenate, split, replace
- Truncate, pad, format
Input: text, transformation options
Output: transformed text
Object Transformation
Purpose: Restructure and map data objects
Input: source object, mapping configuration
Output: target object
Configuration:
- Field mapping (source target)
- Nested object support
- Array flattening/grouping
- Type conversions
Data Validation
Purpose: Validate data against schema
Input: data to validate, validation rules
Output: validation result + errors
Rules: required, min/max, pattern, type, custom
Configuration:
- Schema definition (JSON schema compatible)
- Error handling behavior
- Return errors vs. fail workflow
Filter/Map Array
Purpose: Process arrays element by element
Input: array, filter/map logic
Output: filtered/mapped array
Configuration:
- Filter condition (keep items matching)
- Map transformation (apply to each item)
- Sort order
Conditional & Logic Nodes
If/Then/Else
Purpose: Conditional branching
Input: condition value
Configuration:
- Condition: true/false, comparison, expression
Output:
- True branch If True Output
- False branch If False Output / No output
Multiple conditions can be chained
Switch/Case
Purpose: Multi-way branching
Input: value to switch on
Configuration:
- Cases: value output port
- Default: fallback output
Output: one of multiple branches
Loop (For Each)
Purpose: Iterate over collections
Input: array/object
Configuration:
- Current item variable name
- Index variable name
- Iteration limit (prevent infinite loops)
Output: multiple outputs (one per iteration)
Note: Can nest loops for complex iterations
AI/ML Integration Nodes
LLM Call (AI Provider Integration)
Purpose: Call language models via Drupal AI module
Input: prompt, optional context
Output: LLM response
Configuration:
- AI Provider (OpenAI, Anthropic, Google, Azure, etc.)
- Model selection
- Prompt template
- Temperature (creativity)
- Max tokens
- System message/role
Error handling: Fallback, retry, error output
Embedding Generation
Purpose: Create embeddings for semantic search
Input: text to embed
Output: embedding vector
Configuration:
- AI Provider + embedding model
- Vector dimension
- Normalization
Error handling: Fallback values
Semantic Search
Purpose: Find similar content via embeddings
Input: query text or embedding
Output: matching entities with similarity scores
Configuration:
- Vector database (Milvus, Pinecone, etc.)
- Search limit
- Similarity threshold
- Content source (Drupal entities, external)
Content Classification
Purpose: AI-powered categorization
Input: content to classify
Output: predicted category + confidence
Configuration:
- Classification model/categories
- AI Provider
- Confidence threshold
- Multi-label support
API & External Service Nodes
HTTP Request
Purpose: Call external APIs
Input: URL, method, body, headers
Output: response status, body, headers
Configuration:
- URL (can use variables/tokens)
- HTTP method (GET, POST, PUT, PATCH, DELETE)
- Request body (JSON, form-encoded)
- Authentication (bearer, API key, basic)
- Headers (custom, content-type)
- Timeout
- Retry logic
Error handling: Fallback URL, error output branch
Database Query
Purpose: Execute database queries
Input: query parameters
Output: result set (rows)
Configuration:
- Query type (select, insert, update, delete)
- Table/view
- Conditions/filters
- Parameters (safe substitution)
- Result format
Drupal Entity Operations
Purpose: CRUD operations on entities
Operations:
- Load: Get entity by ID or properties
- Create: Create new entity
- Update: Modify existing entity
- Delete: Remove entity
- Query: Load multiple entities with filters
Input: entity type, ID/properties
Output: entity object or result status
Configuration: Operation-specific options
Output & Notification Nodes
Log Message
Purpose: Write to Drupal logs
Input: message, level, context
Output: log entry created
Configuration:
- Log level (debug, info, warning, error)
- Message template
- Context variables
Send Email
Purpose: Send email messages
Input: recipient, subject, body
Output: email sent/failed status
Configuration:
- From address
- To/CC/BCC (can use variables)
- Subject template
- Body (HTML/plain text)
- Attachments
Send Webhook
Purpose: Trigger external webhooks
Input: event data
Output: webhook delivery status
Configuration:
- Webhook URL
- HTTP method
- Headers
- Request format
- Retry strategy
Update Entity Field
Purpose: Set entity field values
Input: entity, field name, new value
Output: updated entity
Configuration:
- Field name
- Value transformation
- Only update if changed
- Trigger re-save hooks
ECA Integration
Understanding ECA
ECA (Event-Condition-Action) is a powerful automation engine that FlowDrop extends and enhances:
Event (Trigger) Conditions (Validation) Actions (Execution)
- Events: Drupal happenings (entity saved, form submitted, etc.)
- Conditions: Boolean logic (validate if action should run)
- Actions: Operations to execute (modify data, send messages, etc.)
FlowDrop provides a visual interface for building complex ECA models through workflows.
How FlowDrop Works with ECA
1. FlowDrop as ECA Modeller
FlowDrop acts as a visual modeller for ECA:
- Without FlowDrop: ECA models are stored as YAML/configuration code
- With FlowDrop: Users build workflows visually, which get compiled into ECA models
- Under the hood: FlowDrop exports to ECA configuration format
2. Integration Points
// Example: ECA model generated from FlowDrop workflow $model = [ 'id' => 'content_enrichment_workflow', 'event' => 'entity.saved.node.article', 'conditions' => [ [ 'id' => 'entity_bundle_check', 'settings' => ['bundle' => 'article'] ] ], 'actions' => [ [ 'id' => 'flowdrop_execute_workflow', 'settings' => [ 'workflow_id' => 'ai_summary_generator', 'pass_entity' => true, 'store_result' => 'ai_output' ] ] ] ];
3. Event System
FlowDrop workflows can be triggered by ECA events:
Standard Drupal Events:
- Entity events (create, update, delete, view)
- Form events (submit, validate)
- User events (login, logout)
- Custom module events
FlowDrop-Specific Events:
- Webhook received
- API endpoint called
- Scheduled trigger (cron)
- Manual trigger (admin UI)
Extending ECA with FlowDrop
Adding Custom ECA Events
// In your module: mymodule.module use Drupal\eca\Plugin\ECA\Event\EventBase; /** * Custom event for FlowDrop workflows. * * @EcaEvent( * id = "my_custom_event", * label = @Translation("My Custom Event"), * description = @Translation("Fires when X happens"), * deriver = "Drupal\my_module\Plugin\ECA\Event\MyCustomEventDeriver" * ) */ class MyCustomEvent extends EventBase { public function canExecuteEdge(ConfigurationInterface $config): bool { // Determine if this event should trigger return true; } public function getContextValue(string $token): mixed { // Provide data to workflow return $this->event->getContextValue($token); } }
Creating Custom ECA Actions for FlowDrop
// In your module's Plugin/ECA/Action directory use Drupal\eca\Plugin\ECA\Action\ActionBase; use Drupal\Core\Form\FormStateInterface; /** * Custom action executable by FlowDrop workflows. * * @EcaAction( * id = "my_custom_action", * label = @Translation("My Custom Action"), * description = @Translation("Performs custom operation") * ) */ class MyCustomAction extends ActionBase { protected function execute(): bool { // Get configuration $config = $this->configuration; // Perform action // Access event context via $this->event return true; // Success } public static function defaultConfiguration(): array { return [ 'param1' => 'default_value', 'param2' => 'another_default', ]; } public function buildConfigurationForm( array $form, FormStateInterface $form_state ): array { // Configuration form for the action $form['param1'] = [ '#type' => 'textfield', '#title' => $this->t('Parameter 1'), '#default_value' => $this->configuration['param1'], ]; return $form; } }
FlowDrop Event Propagation
FlowDrop nodes can act as ECA events:
Drupal Event (entity.saved)
ECA Model triggers
FlowDrop Workflow executes
Workflow nodes process
Final node triggers new ECA event
Downstream ECA models execute
This enables chaining workflows across modules and building complex automation sequences.
Custom Node Development
Node Processor Plugin System
FlowDrop uses Drupal's plugin system with attributes for defining custom node processors.
Basic Node Processor Structure
// mymodule/src/Plugin/FlowDropNodeProcessor/MyCustomNode.php namespace Drupal\my_module\Plugin\FlowDropNodeProcessor; use Drupal\flowdrop\Plugin\FlowDropNodeProcessor\NodeProcessorBase; use Drupal\Core\Form\FormStateInterface; /** * Custom FlowDrop node processor. * * @FlowDropNodeProcessor( * id = "my_custom_node", * label = @Translation("My Custom Node"), * description = @Translation("Performs custom processing"), * category = "custom", * icon = "folder", * inputs = { * "data" = @Translation("Input Data") * }, * outputs = { * "result" = @Translation("Processing Result"), * "error" = @Translation("Error Output") * } * ) */ class MyCustomNode extends NodeProcessorBase { /** * Process inputs and produce outputs. * * @param array $inputs * Input data keyed by input port name. * @param array $config * Node configuration from workflow definition. * * @return array * Output data keyed by output port name. * Example: ['result' => $data, 'error' => null] */ public function process(array $inputs, array $config): array { try { $input_data = $inputs['data'] ?? null; if (!$input_data) { return [ 'result' => null, 'error' => 'No input data provided' ]; } // Perform processing $result = $this->customProcessing($input_data, $config); return [ 'result' => $result, 'error' => null ]; } catch (\Exception $e) { return [ 'result' => null, 'error' => $e->getMessage() ]; } } /** * Custom processing logic. */ private function customProcessing($data, $config) { // Implementation return $data; } /** * Default configuration for this node. */ public static function defaultConfiguration(): array { return [ 'option1' => 'default_value', 'enable_validation' => true, ]; } /** * Configuration form for workflow builder UI. */ public function buildConfigurationForm( array $form, FormStateInterface $form_state ): array { $form['option1'] = [ '#type' => 'textfield', '#title' => $this->t('Option 1'), '#description' => $this->t('Configure this option'), '#default_value' => $this->configuration['option1'], ]; $form['enable_validation'] = [ '#type' => 'checkbox', '#title' => $this->t('Enable Validation'), '#default_value' => $this->configuration['enable_validation'], ]; return $form; } /** * Validate configuration form submission. */ public function validateConfigurationForm( array &$form, FormStateInterface $form_state ): void { if (empty($form_state->getValue('option1'))) { $form_state->setError( $form['option1'], $this->t('Option 1 is required.') ); } } }
LLM Integration Node Example
// mymodule/src/Plugin/FlowDropNodeProcessor/LLMAnalyzer.php namespace Drupal\my_module\Plugin\FlowDropNodeProcessor; use Drupal\flowdrop\Plugin\FlowDropNodeProcessor\NodeProcessorBase; use Drupal\ai\AiProviderInterface; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; use Symfony\Component\DependencyInjection\ContainerInterface; /** * LLM Analysis node using Drupal AI module. * * @FlowDropNodeProcessor( * id = "llm_analyzer", * label = @Translation("LLM Content Analyzer"), * description = @Translation("Analyze content using LLM"), * category = "ai", * icon = "brain", * inputs = { * "content" = @Translation("Content to Analyze") * }, * outputs = { * "analysis" = @Translation("Analysis Result"), * "error" = @Translation("Error") * } * ) */ class LLMAnalyzer extends NodeProcessorBase implements ContainerFactoryPluginInterface { protected AiProviderInterface $aiProvider; public static function create( ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition ) { $instance = new static( $configuration, $plugin_id, $plugin_definition ); $instance->aiProvider = $container->get('ai.provider'); return $instance; } public function process(array $inputs, array $config): array { try { $content = $inputs['content'] ?? ''; if (empty($content)) { return ['analysis' => null, 'error' => 'No content provided']; } // Call LLM $prompt = $config['prompt_template'] ?? 'Analyze this: {content}'; $prompt = str_replace('{content}', $content, $prompt); $response = $this->aiProvider->generate( $prompt, [ 'model' => $config['model'] ?? 'gpt-4', 'temperature' => $config['temperature'] ?? 0.7, 'max_tokens' => $config['max_tokens'] ?? 1000, ] ); return [ 'analysis' => $response, 'error' => null ]; } catch (\Exception $e) { return [ 'analysis' => null, 'error' => $e->getMessage() ]; } } public static function defaultConfiguration(): array { return [ 'model' => 'gpt-4', 'temperature' => 0.7, 'max_tokens' => 1000, 'prompt_template' => 'Analyze this: {content}', ]; } public function buildConfigurationForm( array $form, FormStateInterface $form_state ): array { $form['model'] = [ '#type' => 'select', '#title' => $this->t('LLM Model'), '#options' => [ 'gpt-4' => 'GPT-4', 'gpt-3.5-turbo' => 'GPT-3.5 Turbo', 'claude-3-opus' => 'Claude 3 Opus', ], '#default_value' => $this->configuration['model'], ]; $form['temperature'] = [ '#type' => 'number', '#title' => $this->t('Temperature (Creativity)'), '#min' => 0, '#max' => 2, '#step' => 0.1, '#default_value' => $this->configuration['temperature'], '#description' => $this->t('Higher = more creative, Lower = more deterministic'), ]; $form['max_tokens'] = [ '#type' => 'number', '#title' => $this->t('Max Tokens'), '#min' => 1, '#max' => 4000, '#default_value' => $this->configuration['max_tokens'], ]; $form['prompt_template'] = [ '#type' => 'textarea', '#title' => $this->t('Prompt Template'), '#description' => $this->t('Use {content} for dynamic content substitution'), '#default_value' => $this->configuration['prompt_template'], ]; return $form; } }
Database Query Node Example
// mymodule/src/Plugin/FlowDropNodeProcessor/DatabaseQuery.php namespace Drupal\my_module\Plugin\FlowDropNodeProcessor; use Drupal\flowdrop\Plugin\FlowDropNodeProcessor\NodeProcessorBase; use Drupal\Core\Database\Connection; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; use Symfony\Component\DependencyInjection\ContainerInterface; /** * Execute database queries in workflows. * * @FlowDropNodeProcessor( * id = "database_query", * label = @Translation("Database Query"), * description = @Translation("Execute custom database queries"), * category = "data", * icon = "database", * inputs = { * "params" = @Translation("Query Parameters") * }, * outputs = { * "rows" = @Translation("Query Results"), * "error" = @Translation("Error") * } * ) */ class DatabaseQuery extends NodeProcessorBase implements ContainerFactoryPluginInterface { protected Connection $database; public static function create( ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition ) { $instance = new static( $configuration, $plugin_id, $plugin_definition ); $instance->database = $container->get('database'); return $instance; } public function process(array $inputs, array $config): array { try { $params = $inputs['params'] ?? []; $query_string = $config['query'] ?? ''; if (empty($query_string)) { return ['rows' => [], 'error' => 'No query provided']; } // Build and execute query $results = $this->database->query($query_string, $params)->fetchAll(); return [ 'rows' => $results, 'error' => null ]; } catch (\Exception $e) { return [ 'rows' => [], 'error' => $e->getMessage() ]; } } public static function defaultConfiguration(): array { return [ 'query' => 'SELECT * FROM {users} WHERE uid = :uid', 'query_type' => 'select', ]; } public function buildConfigurationForm( array $form, FormStateInterface $form_state ): array { $form['query'] = [ '#type' => 'textarea', '#title' => $this->t('SQL Query'), '#description' => $this->t('Use {table} for table substitution and :param for parameters'), '#default_value' => $this->configuration['query'], '#rows' => 6, ]; return $form; } }
Registering Custom Nodes
FlowDrop discovers nodes via plugin discovery. Ensure your node class:
- Extends
NodeProcessorBase - Uses
@FlowDropNodeProcessorplugin annotation - Implements required methods (
process,defaultConfiguration) - Is in correct namespace:
Drupal\{module}\Plugin\FlowDropNodeProcessor
Testing Custom Nodes
// mymodule/tests/src/Unit/Plugin/FlowDropNodeProcessor/MyCustomNodeTest.php namespace Drupal\Tests\my_module\Unit\Plugin\FlowDropNodeProcessor; use Drupal\Tests\UnitTestCase; use Drupal\my_module\Plugin\FlowDropNodeProcessor\MyCustomNode; class MyCustomNodeTest extends UnitTestCase { public function testProcess() { $node = new MyCustomNode([], 'my_custom_node', []); $inputs = ['data' => 'test input']; $config = ['option1' => 'value1']; $result = $node->process($inputs, $config); $this->assertIsArray($result); $this->assertArrayHasKey('result', $result); $this->assertArrayHasKey('error', $result); } }
AI Agent Workflows
Patterns for AI-Powered Automation
FlowDrop excels at building intelligent workflows that combine AI with Drupal's capabilities.
Pattern 1: Content Enrichment Pipeline
Automatically enhance user-generated content with AI-powered features:
[Content Created]
[Extract Content & Metadata]
[LLM: Generate Tags]
[LLM: Create Summary]
[Parallel: LLM Sentiment Analysis + Topic Classification]
(merge results)
[Validate Quality Metrics]
[If Valid: Update Entity Fields]
[If Invalid: Send Notification to Reviewer]
[Log & Complete]
Workflow Steps:
- Trigger: Node created event
- Extract: Get title and body fields
- Generate Tags:
- Input: content
- LLM: "Generate 5 relevant tags"
- Output: tag array
- Generate Summary:
- Input: content
- LLM: "Create 2-sentence summary"
- Output: summary text
- Sentiment:
- Input: content
- LLM: "Analyze sentiment: positive/negative/neutral"
- Output: sentiment + score
- Classify Topic:
- Input: content + tags
- LLM: "Classify into: [tech, business, lifestyle, etc.]"
- Output: primary topic
- Validate: Check all results exist and meet quality thresholds
- Conditional Update:
- If valid: Update multiple entity fields (tags, summary, topic, sentiment_score)
- If invalid: Send email to content team
- Complete: Log workflow execution with results
Pattern 2: Intelligent Content Routing
Use AI to automatically categorize and route content to appropriate channels:
[Content Item]
[LLM: Analyze Content Type & Urgency]
[Decision: Route Based on Analysis]
High Priority
[AI: Summarize for Exec Team]
[Send Email to Executives]
Technical Content
[AI: Extract Code Examples]
[Post to Dev Forum]
General Interest
[AI: Create Social Media Post]
[Queue for Social Distribution]
[Log Routing Decision & Complete]
Pattern 3: Customer Support Automation
AI-assisted support ticket triage and response:
[Support Ticket Submitted]
[Extract Ticket Details]
[LLM: Classify Ticket Category]
FAQ Match: Search Knowledge Base
Found: [LLM: Generate Response from KB]
[Send Auto-Response + Mark as Resolved]
Not Found: [Continue to Human Review]
Technical Issue: [LLM: Generate Diagnostic Steps]
[Suggest Steps to Requester]
Feature Request: [Route to Product Team]
[Create Product Backlog Item]
[Notify Support Agent of Status]
Pattern 4: Multilingual Content Syndication
Translate and adapt content for global audiences:
[Article Published]
[Detect Language & Extract Content]
[For Each Target Language:]
[LLM: Translate Content]
[LLM: Adapt for Cultural Context]
[Validate Translation Quality]
[If Valid: Create Translated Node]
[If Invalid: Queue for Human Review]
[Link Translations Together]
[Update Language Metadata]
[Complete & Log]
Pattern 5: Data Synchronization with External Systems
Orchestrate complex multi-system data workflows:
[Trigger: Data Update in Drupal]
[Validate Data Quality]
[Transform to External Format]
[Parallel API Calls:]
[Call System A API]
[Call System B API]
[Call System C API]
[Aggregate Results]
[Check for Conflicts]
If Conflict: [LLM: Determine Resolution]
[Apply Resolution Logic]
If Clean: [Merge Results]
[Update Drupal with Results]
[Audit Log & Complete]
Best Practices for AI Workflows
1. Error Handling & Fallbacks
Always include fallback paths for AI operations:
[LLM Call]
Success
[Use AI Output]
Failure
[Use Default Value or Skip Step]
[Continue Workflow]
2. Cost Management
Optimize API calls to avoid excessive costs:
- Cache results: Don't re-process same content
- Batch operations: Process multiple items in single LLM call
- Selective processing: Use lighter models for simple tasks
- Rate limiting: Prevent overwhelming external APIs
3. Quality Control
Validate AI outputs before using in production:
[LLM Call: Generate Summary]
[Validate Output:]
Length check (min/max)
Toxicity check
Relevance score > threshold
Grammar validation
[If Valid: Use Output]
[If Invalid: Flag for Review or Use Fallback]
4. Transparency & Auditing
Track all AI decisions for compliance:
[Before AI Call: Log Input]
[Execute LLM]
[After AI Call: Log Output + Decision]
[Track: Cost, Latency, Model Used]
[Store Audit Trail for Compliance]
5. Progressive Enhancement
Enhance features gradually without breaking existing functionality:
[Content Item]
Core Fields Always Available
AI-Enhanced Fields (Optional)
If AI Succeeds: Use AI Output
If AI Fails: Omit Field (don't break content)
Integration with drupal/ai
AI Module Integration
FlowDrop integrates seamlessly with Drupal's AI module for LLM capabilities:
Supported AI Providers
The AI module connects to 48+ providers:
- OpenAI: GPT-4, GPT-3.5-Turbo, Embeddings
- Anthropic: Claude 3 family (Opus, Sonnet, Haiku)
- Google: Gemini Pro, PaLM
- AWS: Bedrock (Claude, Llama, etc.)
- Azure: OpenAI models via Azure endpoints
- Open Source: Ollama, Hugging Face, LLaMA
- Specialized: Groq, Together.AI, Mistral
Configuring AI Providers
In FlowDrop workflow builder:
- Navigate to Admin Configuration AI AI Providers
- Add provider credentials (API keys stored securely in Key module)
- Select default provider for LLM nodes
- Configure per-provider settings (temperature, token limits, etc.)
Using AI in Custom Nodes
use Drupal\ai\AiProviderInterface; class MyAINode extends NodeProcessorBase implements ContainerFactoryPluginInterface { protected AiProviderInterface $aiProvider; public function process(array $inputs, array $config): array { $prompt = $inputs['prompt']; // Call AI provider $response = $this->aiProvider->generate( $prompt, [ 'model' => $config['model'], 'temperature' => $config['temperature'], 'max_tokens' => $config['max_tokens'], 'provider' => $config['provider'], // Override default ] ); return ['response' => $response]; } }
Vector Database Integration
For semantic search in workflows:
[Create Embedding]
[Store in Vector DB: Milvus/Pinecone]
[Later: Query Similar Content]
[LLM: Rerank Results]
[Return Top-K Matches]
Code Examples
Example 1: Content Auto-Tagging Workflow
Goal: Automatically generate relevant tags for published articles using AI
FlowDrop Setup:
- Trigger: Node create event (Article bundle)
- Extract: Get body field value
- AI: Generate Tags - LLM call
- Validate: Check tag count and validity
- Update: Set field_tags on node
- Save: Trigger node save
- Log: Record action
Configuration:
// Workflow configuration (JSON format) { "id": "auto_tag_articles", "label": "Auto-Tag Articles with AI", "trigger": { "event": "entity.created.node.article" }, "nodes": [ { "id": "extract_body", "type": "extract_data", "config": { "path": "body.value" } }, { "id": "generate_tags", "type": "llm_call", "config": { "model": "gpt-4", "prompt": "Generate 5 relevant tags for this article:\n\n{content}", "temperature": 0.7, "max_tokens": 100 } }, { "id": "parse_tags", "type": "text_transformation", "config": { "operation": "split", "delimiter": "," } }, { "id": "validate_tags", "type": "data_validation", "config": { "rules": { "required": true, "min_items": 3, "max_items": 5 } } }, { "id": "update_entity", "type": "entity_update", "config": { "field": "field_tags", "value_source": "validate_tags" } } ], "connections": [ ["trigger", "extract_body"], ["extract_body", "generate_tags"], ["generate_tags", "parse_tags"], ["parse_tags", "validate_tags"], ["validate_tags", "update_entity"] ] }
Example 2: Multi-Step API Orchestration
Goal: Enrich user data with weather and location information
Workflow:
[Trigger: User Location Update]
[Extract: Address from User Profile]
[Call: Geocoding API - Get Coordinates]
[Call: Weather API - Get Current Conditions]
[Call: Timezone API - Get User Timezone]
[Aggregate: Combine All Data]
[Validate: Check All APIs Succeeded]
Success: Update User Entity with Enriched Data
Failure: Send Alert to Admin
Custom Node: API Aggregator
namespace Drupal\my_module\Plugin\FlowDropNodeProcessor; use Drupal\flowdrop\Plugin\FlowDropNodeProcessor\NodeProcessorBase; use Drupal\Core\Form\FormStateInterface; use GuzzleHttp\ClientInterface; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; use Symfony\Component\DependencyInjection\ContainerInterface; /** * Aggregate multiple API responses. * * @FlowDropNodeProcessor( * id = "api_aggregator", * label = @Translation("API Response Aggregator"), * description = @Translation("Combine multiple API responses"), * category = "integration", * inputs = { * "geo" = @Translation("Geocoding Response"), * "weather" = @Translation("Weather Response"), * "timezone" = @Translation("Timezone Response") * }, * outputs = { * "enriched_data" = @Translation("Aggregated Data"), * "validation_errors" = @Translation("Errors") * } * ) */ class ApiAggregator extends NodeProcessorBase { public function process(array $inputs, array $config): array { $errors = []; $enriched = [ 'geo' => null, 'weather' => null, 'timezone' => null, 'last_updated' => time(), ]; // Validate and parse each API response if (!empty($inputs['geo'])) { try { $enriched['geo'] = json_decode($inputs['geo'], true); } catch (\Exception $e) { $errors[] = 'Geocoding API error: ' . $e->getMessage(); } } if (!empty($inputs['weather'])) { try { $enriched['weather'] = json_decode($inputs['weather'], true); } catch (\Exception $e) { $errors[] = 'Weather API error: ' . $e->getMessage(); } } if (!empty($inputs['timezone'])) { try { $enriched['timezone'] = json_decode($inputs['timezone'], true); } catch (\Exception $e) { $errors[] = 'Timezone API error: ' . $e->getMessage(); } } return [ 'enriched_data' => $enriched, 'validation_errors' => $errors ?: null ]; } }
Example 3: Conditional Email Notification
Goal: Send different emails based on content type and priority
Workflow Configuration:
{ "id": "intelligent_notifications", "trigger": "entity.created.node", "nodes": [ { "id": "classify_content", "type": "llm_call", "config": { "prompt": "Classify content priority (high/medium/low) and type (technical/business/general):\n\n{title}\n{body}" } }, { "id": "route_by_priority", "type": "switch_case", "cases": { "high": "notify_executives", "medium": "notify_team", "low": "notify_general" } }, { "id": "notify_executives", "type": "send_email", "config": { "to": "executives@example.com", "subject": "HIGH PRIORITY: {title}", "body": "Executive Summary:\n{summary}" } }, { "id": "notify_team", "type": "send_email", "config": { "to": "team@example.com", "subject": "Team Update: {title}", "body": "Team Summary:\n{summary}" } }, { "id": "notify_general", "type": "send_email", "config": { "to": "updates@example.com", "subject": "Update: {title}", "body": "New Update:\n{summary}" } } ] }
Example 4: Extending ECA with FlowDrop
Custom ECA Event for FlowDrop:
// In mymodule/src/Plugin/ECA/Event/ namespace Drupal\my_module\Plugin\ECA\Event; use Drupal\eca\Plugin\ECA\Event\EventBase; use Drupal\eca\ConfigurationInterface; /** * Event: FlowDrop Workflow Complete * * @EcaEvent( * id = "flowdrop_workflow_complete", * label = @Translation("FlowDrop Workflow Complete"), * description = @Translation("Triggered when a FlowDrop workflow completes") * ) */ class FlowDropWorkflowComplete extends EventBase { public function canExecuteEdge(ConfigurationInterface $config): bool { $event = $this->event; // Only trigger for specific workflow $workflow_id = $config->get('workflow_id'); if ($workflow_id && $event->getWorkflowId() !== $workflow_id) { return false; } // Only trigger for successful completions (optional) $success_only = $config->get('success_only'); if ($success_only && !$event->isSuccessful()) { return false; } return true; } public function getContextValue(string $token): mixed { $event = $this->event; switch ($token) { case 'workflow_id': return $event->getWorkflowId(); case 'workflow_result': return $event->getResult(); case 'execution_time': return $event->getExecutionTime(); case 'status': return $event->isSuccessful() ? 'success' : 'failed'; } return $event->getContextValue($token); } }
Configuration Best Practices
Workflow Organization
-
Naming Convention: Use descriptive names
content_enrichment_articleuser_onboarding_emailapi_sync_external_system
-
Documentation: Add descriptions for complex workflows
- Purpose and trigger
- Expected inputs/outputs
- Error handling strategy
- Contact person/team
-
Versioning: Track workflow changes
- Archive old versions
- Date important modifications
- Include changelog comments
Error Handling Strategy
-
Fail-Safe Defaults
- Always have fallback paths
- Log errors for debugging
- Notify admins of critical failures
-
Data Validation
- Validate inputs before processing
- Check API responses
- Handle missing/null values
-
Retry Logic
- Retry transient failures
- Implement exponential backoff
- Set max retry limits
Performance Optimization
-
Caching
- Cache LLM results for repeated prompts
- Cache API responses when appropriate
- Use entity caching for lookups
-
Async Processing
- Queue heavy operations
- Use Drupal queue system
- Process via cron
-
Batch Operations
- Process multiple items together
- Reduce number of API calls
- Improve efficiency
Security Considerations
-
API Keys Management
- Use Drupal Key module
- Never expose keys in workflows
- Rotate regularly
-
Input Validation
- Sanitize user inputs
- Validate data types
- Check against whitelist
-
Rate Limiting
- Implement rate limiting for APIs
- Prevent denial of service
- Monitor for abuse
Troubleshooting
Common Issues
Workflow Not Triggering
- Check trigger event: Verify event name matches Drupal event
- Enable workflow: Ensure workflow is enabled in admin UI
- Check permissions: Verify account executing workflow has permissions
- Review logs: Check watchdog logs for errors
Node Execution Failure
- Verify inputs: Confirm required inputs are provided
- Check configuration: Review node config for errors
- Test with sample data: Use workflow tester with known inputs
- Review node logs: Check node-specific error messages
Performance Issues
- Profile workflow: Identify slow nodes
- Optimize queries: Review database queries
- Cache results: Implement caching for repeated calls
- Consider async: Queue heavy operations
LLM Integration Problems
- Verify API keys: Check AI provider configuration
- Check rate limits: Monitor API usage
- Review prompts: Refine LLM prompts for better results
- Test directly: Use AI module explorer to test directly
Resources
Official Documentation
- FlowDrop Project: https://www.drupal.org/project/flowdrop
- ECA Module: https://www.drupal.org/project/eca
- ECA Guide: https://ecaguide.org
- Drupal AI Module: https://www.drupal.org/project/ai
Related Modules
- eca_bpmn_io: BPMN visual modeller for ECA
- eca_ai: ECA integration with AI module
- flowdrop: Visual workflow builder
- key: Secure API key storage
Community
- Drupal.org issue queue
- Slack #drupal-automation channel
- Factorial GmbH community forums
Summary
FlowDrop represents a paradigm shift in Drupal automation, combining visual workflow design with powerful AI integration capabilities. By leveraging node-based architecture, ECA integration, and Drupal's plugin system, developers can create sophisticated automation workflows that enhance content management, integrate external services, and provide intelligent, AI-powered functionality.
Key takeaways:
- Visual Builder: Use drag-and-drop interface for complex workflows
- Node System: Extend with custom processors for domain-specific logic
- ECA Integration: Leverage event-condition-action architecture
- AI Ready: Direct support for 48+ LLM providers
- Enterprise Grade: Security, error handling, and audit trails built-in
Start with simple workflows and gradually introduce AI and complex logic as your team becomes proficient with the platform.