Skip to main content

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:

  1. Event Trigger - A Drupal event fires (entity saved, form submitted, API call, etc.)
  2. Workflow Invocation - FlowDrop retrieves the associated workflow configuration
  3. Node Processing - Nodes execute in dependency order
  4. Data Propagation - Output from one node becomes input for dependent nodes
  5. Result Output - Final output nodes produce results (side effects, return values)
  6. 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

  1. Navigate to Admin Automation Workflows FlowDrop
  2. Click Create new workflow
  3. Enter workflow name and description
  4. Choose trigger event (Drupal event)

Step 2: Add Nodes

  1. Click the Add Node button or use the node palette
  2. Select node type from available categories:
    • Data Input/Output
    • Transformations
    • Conditionals
    • AI/ML Operations
    • API Integrations
    • Custom Nodes
  3. Drag node to canvas
  4. Position and arrange nodes logically

Step 3: Configure Nodes

  1. Click on a node to select it
  2. Configure in the Node Properties panel:
    • Set input parameters
    • Define processing logic
    • Configure output mapping
  3. Use visual feedback to see expected data flow

Step 4: Connect Nodes

  1. Click the output port of a source node
  2. Drag to the input port of a target node
  3. Release to create a connection (wire)
  4. Connection visualizes data flow direction
  5. Multiple connections possible from single port

Step 5: Test and Deploy

  1. Use Test Workflow to validate logic
  2. Provide test input matching trigger event
  3. Review execution trace and results
  4. 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
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:

  1. Extends NodeProcessorBase
  2. Uses @FlowDropNodeProcessor plugin annotation
  3. Implements required methods (process, defaultConfiguration)
  4. 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:

  1. Trigger: Node created event
  2. Extract: Get title and body fields
  3. Generate Tags:
    • Input: content
    • LLM: "Generate 5 relevant tags"
    • Output: tag array
  4. Generate Summary:
    • Input: content
    • LLM: "Create 2-sentence summary"
    • Output: summary text
  5. Sentiment:
    • Input: content
    • LLM: "Analyze sentiment: positive/negative/neutral"
    • Output: sentiment + score
  6. Classify Topic:
    • Input: content + tags
    • LLM: "Classify into: [tech, business, lifestyle, etc.]"
    • Output: primary topic
  7. Validate: Check all results exist and meet quality thresholds
  8. Conditional Update:
    • If valid: Update multiple entity fields (tags, summary, topic, sentiment_score)
    • If invalid: Send email to content team
  9. 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:

  1. Navigate to Admin Configuration AI AI Providers
  2. Add provider credentials (API keys stored securely in Key module)
  3. Select default provider for LLM nodes
  4. 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:

  1. Trigger: Node create event (Article bundle)
  2. Extract: Get body field value
  3. AI: Generate Tags - LLM call
  4. Validate: Check tag count and validity
  5. Update: Set field_tags on node
  6. Save: Trigger node save
  7. 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

  1. Naming Convention: Use descriptive names

    • content_enrichment_article
    • user_onboarding_email
    • api_sync_external_system
  2. Documentation: Add descriptions for complex workflows

    • Purpose and trigger
    • Expected inputs/outputs
    • Error handling strategy
    • Contact person/team
  3. Versioning: Track workflow changes

    • Archive old versions
    • Date important modifications
    • Include changelog comments

Error Handling Strategy

  1. Fail-Safe Defaults

    • Always have fallback paths
    • Log errors for debugging
    • Notify admins of critical failures
  2. Data Validation

    • Validate inputs before processing
    • Check API responses
    • Handle missing/null values
  3. Retry Logic

    • Retry transient failures
    • Implement exponential backoff
    • Set max retry limits

Performance Optimization

  1. Caching

    • Cache LLM results for repeated prompts
    • Cache API responses when appropriate
    • Use entity caching for lookups
  2. Async Processing

    • Queue heavy operations
    • Use Drupal queue system
    • Process via cron
  3. Batch Operations

    • Process multiple items together
    • Reduce number of API calls
    • Improve efficiency

Security Considerations

  1. API Keys Management

    • Use Drupal Key module
    • Never expose keys in workflows
    • Rotate regularly
  2. Input Validation

    • Sanitize user inputs
    • Validate data types
    • Check against whitelist
  3. Rate Limiting

    • Implement rate limiting for APIs
    • Prevent denial of service
    • Monitor for abuse

Troubleshooting

Common Issues

Workflow Not Triggering

  1. Check trigger event: Verify event name matches Drupal event
  2. Enable workflow: Ensure workflow is enabled in admin UI
  3. Check permissions: Verify account executing workflow has permissions
  4. Review logs: Check watchdog logs for errors

Node Execution Failure

  1. Verify inputs: Confirm required inputs are provided
  2. Check configuration: Review node config for errors
  3. Test with sample data: Use workflow tester with known inputs
  4. Review node logs: Check node-specific error messages

Performance Issues

  1. Profile workflow: Identify slow nodes
  2. Optimize queries: Review database queries
  3. Cache results: Implement caching for repeated calls
  4. Consider async: Queue heavy operations

LLM Integration Problems

  1. Verify API keys: Check AI provider configuration
  2. Check rate limits: Monitor API usage
  3. Review prompts: Refine LLM prompts for better results
  4. Test directly: Use AI module explorer to test directly

Resources

Official Documentation

  • 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.