Skip to main content
Back to ScopeForged

ScopeForged Documentation

Technical documentation, guides, and feature references for the ScopeForged client portal.

System & Infrastructure/Workflow Automation

Workflow Automation Engine Guide

Last Updated: 2026-01-22 Status: Enhanced with Unified Notification Actions, Templates Gallery, Tooltips, Dry-Run & Validation, Discovery Workflows, State Duration Triggers, Test Sandbox Plan Reference: 031-workflow-automation-engine.md, 063-workflow-automation-enhancement.md, 119-enhanced-workflow-triggers.md, 125-client-stage-email-automation.md, 129-discovery-flow-email-notifications.md, 196-workflow-action-ux-improvements.md, 197-workflow-test-sandbox.md


Overview

The Workflow Automation Engine enables administrators to create automated workflows that trigger actions based on events in the portal. It supports conditional logic, multiple actions, and integrations with notifications, status updates, and external services.


Table of Contents

  1. Accessing Workflows
  2. Workflow Concepts
  3. How to Use
  4. Triggers & Actions
  5. Workflow Analytics
  6. Workflow Debugging
  7. Workflow Test Sandbox
  8. Workflow Templates
  9. Webhook Triggers
  10. Technical Architecture
  11. Related Features

Accessing Workflows

Access PointLocationURLRole
WorkflowsAdmin sidebar/admin/workflowsAdmin
Create WorkflowWorkflows page/admin/workflows/createAdmin
Workflow AnalyticsAdmin More menu/admin/workflows-analyticsAdmin
Workflow TemplatesAdmin More menu/admin/workflow-templatesAdmin
Test SandboxWorkflows page nav/admin/workflow-testsAdmin
Execution DebugExecution detail/admin/workflow-executions/{id}/debugAdmin

Permissions

ActionAdminClient User
View workflows
Create workflows
Edit workflows
Delete workflows
View execution logs

Workflow Concepts

Components

ComponentDescription
TriggerEvent that starts the workflow
ConditionsRules that must be met
ActionsTasks to execute
VariablesDynamic data from trigger

Workflow Flow

Trigger → Check Conditions → Execute Actions → Log Results

Example Workflow

"Send reminder when invoice is overdue":

  1. Trigger: Invoice due date passed
  2. Condition: Status is "sent" (not paid)
  3. Action: Send reminder email to client
  4. Action: Notify admin

How to Use

Creating a Workflow

  1. Navigate to Admin → Workflows
  2. Click "Create Workflow"
  3. Choose a Template (optional):
    • Browse the templates gallery at the top
    • Click a template to create a workflow from it
    • Or continue with a blank workflow
  4. Enter workflow name and description
  5. Select Trigger:
    • Choose trigger type (e.g., "Invoice status changed")
    • Configure trigger options
    • Hover over the help icon for guidance
  6. Add Conditions (optional):
    • Click "Add Condition"
    • Set field, operator, value
  7. Add Actions:
    • Click "Add Action"
    • Choose action type
    • Configure action parameters
  8. Preview Workflow (New):
    • Click "Preview Workflow" to see dry-run
    • View the execution flow: Trigger → Conditions → Actions
    • Verify the workflow logic before saving
  9. Enable workflow
  10. Click "Save Workflow" (validates before save)

The create workflow page now displays a gallery of templates at the top:

Features:

  • Shows up to 6 most popular templates
  • Displays template name, category, and usage count
  • One-click to create workflow from template
  • Link to full templates library

Access: Available at /admin/workflows/create

Inline Help Tooltips (New)

The workflow builder includes contextual help tooltips:

FieldTooltip Content
Name"Give your workflow a descriptive name..."
Trigger Type"When should this workflow run?..."
Model"Which type of record should trigger..."
Priority"Higher priority workflows run first..."
Active"Only active workflows will run..."
Conditions"Conditions filter when the workflow runs..."
Actions"Actions are what the workflow does..."
Action TypeDynamic based on selected type
Delay"Wait this many minutes before running..."

Component: Uses <x-tooltip> Blade component

Dry-Run Preview (New)

Preview how your workflow will execute before saving:

  1. Configure your workflow (trigger, conditions, actions)
  2. Click "Preview Workflow" button
  3. View the dry-run preview panel showing:
    • Step 1: Trigger description and model
    • Conditions: Logic operators and comparisons
    • Steps 2+: Each action with configuration
  4. Review the execution flow
  5. Close preview or make adjustments

Features:

  • Shows trigger type and target model
  • Displays all conditions with AND/OR logic
  • Lists each action with its delay time
  • Shows email recipients, webhook URLs, etc.

Client-Side Validation (New)

The workflow form validates before submission:

Validations:

  • Workflow name is required
  • Model must be selected for model-based triggers
  • At least one action is required
  • Email actions require recipient and subject
  • Webhook actions require URL
  • Conditions require field name

Error Display:

  • Yellow warning box at top of form
  • Lists all validation errors
  • Scrolls to top when errors are found
  • Prevents form submission until fixed

Editing a Workflow

  1. Navigate to Admin → Workflows → [Workflow]
  2. Click "Edit"
  3. Modify trigger, conditions, or actions
  4. Save changes

Testing a Workflow

  1. Navigate to workflow detail
  2. Click "Test"
  3. Provide sample data
  4. View simulated execution
  5. Check for errors

Viewing Execution Logs

  1. Navigate to Admin → Workflows → [Workflow]
  2. Click "Logs" tab
  3. View execution history:
    • Trigger time
    • Conditions evaluated
    • Actions executed
    • Status (success/failed)

Triggers & Actions

Available Triggers

TriggerEvent
model_createdModel instance created
model_updatedModel instance updated
model_deletedModel instance deleted
client_stage_changedClient stage transition
project.status_changedProject status updated
invoice.createdNew invoice created
invoice.sentInvoice sent to client
invoice.overdueInvoice past due date
invoice.paidInvoice marked paid
file.uploadedFile uploaded
user.registeredNew user registered
scheduledTime-based trigger
client_state_durationClient in state for X days
webhookExternal webhook trigger
manualManual trigger

Client Stage Changed Trigger

The client_stage_changed trigger fires when a client transitions between lifecycle stages. Use trigger_config to filter by specific stage:

// Workflow definition
[
    'trigger_type' => 'client_stage_changed',
    'trigger_config' => ['stage' => 'qualified'],  // Only fires for this stage
]

Available Stages: prospect, questionnaire_pending, questionnaire_submitted, qualified, discovery_scheduled, discovery_completed, proposal_sent, proposal_accepted, active, completed, support, declined, churned

Client State Duration Trigger

The client_state_duration trigger fires for clients who have been in a specific stage for a certain number of days. This is ideal for follow-up reminders and time-based escalations.

// Workflow definition
[
    'trigger_type' => 'client_state_duration',
    'trigger_config' => [
        'stage' => 'questionnaire_pending',  // Which stage to monitor
        'min_days' => 3,                     // Minimum days in stage
        'max_days' => 7,                     // Maximum days (optional, null = no limit)
        'deduplication_hours' => 72,         // Prevent re-sending within X hours
    ],
]

Configuration Options:

OptionRequiredDefaultDescription
stageYes-Client stage to monitor
min_daysNo1Minimum days client must be in stage
max_daysNonullMaximum days (stops after this)
deduplication_hoursNo24Hours before same workflow can re-trigger

How It Works:

  1. The workflows:check-state-duration command runs hourly
  2. Finds all active workflows with client_state_duration trigger
  3. For each workflow, queries clients matching stage + duration criteria
  4. Checks deduplication (no execution within deduplication_hours)
  5. Triggers workflow for each matching client

Example Use Cases:

// Questionnaire reminder after 3 days
'trigger_config' => [
    'stage' => 'questionnaire_pending',
    'min_days' => 3,
    'max_days' => 6,  // 7-day reminder takes over
    'deduplication_hours' => 72,
],

// Proposal follow-up after 5 days
'trigger_config' => [
    'stage' => 'proposal_sent',
    'min_days' => 5,
    'max_days' => 12,
    'deduplication_hours' => 120,
],

// At-risk client alert after 30 days inactive
'trigger_config' => [
    'stage' => 'active',
    'min_days' => 30,
    'deduplication_hours' => 168,  // Weekly
],

Running Manually:

# Test what would be triggered (dry-run)
php artisan workflows:check-state-duration --dry-run

# Actually trigger workflows
php artisan workflows:check-state-duration

Scheduler: The command is scheduled to run hourly via routes/console.php.

Model Updated Trigger with Conditions

The model_updated trigger can be combined with conditions to detect specific field changes:

// Workflow with changed_to condition
$workflow = Workflow::create([
    'trigger_type' => 'model_updated',
    'trigger_model' => DiscoveryQuestionnaire::class,
]);

WorkflowCondition::create([
    'workflow_id' => $workflow->id,
    'field' => 'status',
    'operator' => 'changed_to',  // Detects field transition
    'value' => 'submitted',
]);

Trigger Variables

Each trigger provides variables for conditions and actions:

invoice.created:

{{invoice.id}}
{{invoice.number}}
{{invoice.total}}
{{invoice.due_date}}
{{client.name}}
{{client.email}}

Observed Models for Triggers

The workflow system observes the following models for model_created, model_updated, and model_deleted triggers:

CategoryModelsPurpose
Core EntitiesClient, Project, Invoice, UserPrimary business objects
Client IntakeDiscoveryQuestionnaire, DiscoveryCall, PaymentDiscovery and onboarding flow
Project ManagementProjectFile, ProjectMilestone, ProjectPlan, InvoiceItemProject tracking
CommunicationMessage, DocumentRequest, ConversationClient communication

This comprehensive model coverage enables workflows for the entire client lifecycle, from initial questionnaire submission through project completion.

Available Actions

ActionDescription
send_notificationUnified notification - supports email, in-app, SMS, Slack channels
update_fieldUpdate model field values
webhookHTTP webhook call
request_approvalPause workflow until approved
delayWait before next action

Note: The legacy action types send_email and send_template_email are still supported for backward compatibility but will be automatically mapped to send_notification with channel set to email.

Unified Send Notification Action

The send_notification action is the recommended way to send notifications through workflows. It supports multiple channels and offers a consistent configuration interface.

Configuration:

{
  "type": "send_notification",
  "config": {
    "channel": "email",
    "notification_template_id": 5,
    "recipient_type": "client",
    "subject": "Custom subject if no template",
    "body": "Custom message body if no template"
  }
}

Configuration Options:

FieldRequiredValuesDescription
channelYesemail, in_app, sms, slackNotification delivery channel
notification_template_idNoTemplate ID or nullUse predefined template
recipient_typeYesSee belowHow to determine recipient
recipient_emailIf customEmail or {variable}Custom email address
recipient_phoneIf SMSPhone numberFor SMS channel
subjectIf no templateStringEmail subject line
bodyIf no templateStringMessage body

Recipient Types:

TypeDescription
clientPrimary user associated with the client
all_client_usersAll users associated with the client
specific_userSpecific user by ID (requires recipient_id)
roleAll users with a role (requires recipient_role)
customCustom email/phone (requires recipient_email or recipient_phone)

Channel Support:

ChannelTemplate SupportCustom MessageRecipient Types
emailAll
in_appUser-based only
smsUser-based only
slackUser-based only

Example - Email with Template:

{
  "type": "send_notification",
  "config": {
    "channel": "email",
    "notification_template_id": 5,
    "recipient_type": "client"
  }
}

Example - Email without Template:

{
  "type": "send_notification",
  "config": {
    "channel": "email",
    "recipient_type": "custom",
    "recipient_email": "{client_email}",
    "subject": "Your invoice is ready",
    "body": "Dear {client_name}, your invoice #{invoice_number} is ready for review."
  }
}

Example - In-App Notification:

{
  "type": "send_notification",
  "config": {
    "channel": "in_app",
    "recipient_type": "role",
    "recipient_role": "admin",
    "subject": "New client registered",
    "body": "{client_name} has completed their questionnaire."
  }
}

Migrating Legacy Workflow Actions

A migration command is available to convert existing workflows using legacy action types to the unified send_notification format:

# Preview what would be migrated (dry-run)
php artisan workflows:migrate-notification-actions --dry-run

# Actually migrate the actions
php artisan workflows:migrate-notification-actions

The migration converts:

  • send_emailsend_notification with channel: email
  • send_template_emailsend_notification with channel: email

Note: This migration is optional. Legacy action types continue to work due to backward compatibility mapping in the WorkflowEngine.

Send Template Email Action (Legacy)

The send_template_email action sends emails using pre-defined NotificationTemplates, enabling reusable email content managed through the admin UI.

Configuration:

{
  "action": "send_template_email",
  "notification_template_id": 5,
  "to": "{client_email}"
}

Benefits:

  • Reusable email templates across multiple workflows
  • Templates editable in database without code changes
  • Variable substitution in both {var} and {{ var }} formats
  • Queue-based async execution

Usage:

  1. Create a NotificationTemplate in Admin → Notifications → Templates
  2. Create a workflow with your desired trigger
  3. Add action type: Send Template Email
  4. Select the template and set recipient to {client_email}
  5. Save and activate

Available Variables:

VariableDescription
{client}, {client_name}, {company_name}Client name
{client_email}, {client_phone}Client contact info
{stage}, {new_stage}Current client stage
{previous_stage}, {old_stage}Previous stage
{date}, {time}, {datetime}Current date/time

Action Configuration

Send Email:

{
  "action": "send_email",
  "to": "{{client.email}}",
  "subject": "Invoice {{invoice.number}} Reminder",
  "template": "invoice-reminder",
  "variables": {
    "invoice_number": "{{invoice.number}}",
    "amount": "{{invoice.total}}"
  }
}

Update Status:

{
  "action": "update_status",
  "entity": "project",
  "id": "{{project.id}}",
  "status": "completed"
}

Send Webhook:

{
  "action": "send_webhook",
  "url": "https://example.com/webhook",
  "method": "POST",
  "payload": {
    "event": "invoice_paid",
    "invoice_id": "{{invoice.id}}"
  }
}

Condition Operators

OperatorDescriptionExample
equalsExact matchstatus equals "active"
not_equalsNot equalstatus not_equals "draft"
containsString containsname contains "Corp"
greater_thanNumeric greatertotal > 1000
less_thanNumeric lessdays_overdue < 30
is_emptyNull or emptynotes is_empty
is_not_emptyHas valueemail is_not_empty

Combining Conditions

{
  "match": "all",
  "conditions": [
    {"field": "status", "operator": "equals", "value": "sent"},
    {"field": "days_overdue", "operator": "greater_than", "value": 7}
  ]
}

Workflow Analytics

The Workflow Analytics dashboard provides comprehensive insights into workflow performance and execution patterns.

Accessing Analytics

Navigate to Admin → More → Workflow Analytics or /admin/workflows-analytics.

Dashboard Metrics

MetricDescription
Total WorkflowsCount of all workflows in the system
Active WorkflowsWorkflows currently enabled
Executions This MonthNumber of executions in current month
Success RatePercentage of successful executions
Average Execution TimeMean execution duration in milliseconds

Top Workflows

The analytics dashboard shows:

  • Most frequently executed workflows
  • Success rates per workflow
  • Execution counts

Workflows Needing Attention

Automatically identifies workflows that:

  • Have high failure rates (>20%)
  • Have slow execution times (>5 seconds average)

Recommendations

The system provides automated recommendations:

  • Warning: Workflows with high failure rates
  • Info: Optimization suggestions

Performance Distribution

View execution patterns:

  • By trigger type
  • By time of day (hourly distribution)
  • Recent failures with error messages

Workflow Debugging

The debug view provides detailed execution analysis for troubleshooting.

Accessing Debug View

  1. Navigate to a workflow execution
  2. Click "Debug" or access /admin/workflow-executions/{id}/debug

Execution Summary

FieldDescription
StatusCurrent execution status
DurationTotal execution time in ms
Triggered ByWhat triggered the execution
Started AtExecution start timestamp

Performance Bottlenecks

Automatically identifies actions that:

  • Take longer than 1 second to execute
  • Consume disproportionate execution time

Error Analysis

When executions fail:

  • Shows which action failed
  • Displays error messages
  • Provides stack trace context

Action Timeline

Step-by-step visualization showing:

  • Action execution order
  • Duration per action
  • Status per action (completed/failed/skipped)
  • Error details if failed

Execution History

Quick access to recent executions for comparison:

  • Success/failure status
  • Execution times
  • Navigate between executions

Workflow Test Sandbox

The Workflow Test Sandbox provides a comprehensive testing environment for workflows, allowing you to simulate triggers, preview condition evaluations, and test workflow behavior without affecting production data.

Accessing the Test Sandbox

Navigate to Admin → Workflows → Test Sandbox or /admin/workflow-tests.

Features

FeatureDescription
Dry Run ModePreview what would happen without executing actions
Execute ModeRun workflow actions with notifications sent to you instead of actual recipients
Trigger SimulationSimulate different trigger scenarios (stage changes, model events)
Condition EvaluationSee detailed pass/fail status for each condition with actual vs expected values
Action PreviewPreview email content, webhooks, and other action outputs
Execution TimelineVisual timeline of action execution order with delays
Batch TestingTest workflow against multiple records to see pass rates
Value OverridesTest "what if" scenarios by overriding field values
Run HistoryTrack test runs and compare results over time

Creating a Test Configuration

  1. Navigate to the Test Sandbox
  2. Click "New Test"
  3. Enter a test name
  4. Select the workflow to test
  5. Choose run mode:
    • Dry Run: Safe preview mode, no actions executed
    • Execute Mode: Actions run, but notifications go to you
  6. Configure trigger simulation (if applicable)
  7. Select a test subject (Client, Project, etc.)
  8. Optionally add value overrides
  9. Save and run

Run Modes

Dry Run Mode (Recommended for testing):

  • Shows what would happen without executing
  • Displays condition evaluation with actual values
  • Previews action outputs (email content, webhook payloads)
  • Safe to run repeatedly

Execute Mode:

  • Actually runs workflow actions
  • Notifications are redirected to you instead of actual recipients
  • Useful for testing email formatting and delivery
  • Warning banner displayed before running

Trigger Simulation

Simulate different trigger scenarios based on the workflow's trigger type:

Trigger TypeSimulation Options
client_stage_changedSelect from/to stages
client_state_durationSet days in stage
model_createdProvide sample model data
model_updatedSpecify changed fields and values
webhookProvide webhook payload JSON

Condition Evaluation Display

For each condition, the test results show:

FieldDescription
FieldThe condition field being evaluated
OperatorComparison operator (equals, contains, etc.)
ExpectedThe value configured in the condition
ActualThe real value from the test subject
StatusPass or Fail indicator
Failure ReasonHuman-readable explanation of why it failed

Batch Testing

Test a workflow against multiple records to understand its reach:

  1. Navigate to a test configuration
  2. Click "Batch Test"
  3. Configure filters (optional):
    • For Clients: stage, status
    • For Projects: status
    • For Invoices: status
  4. Select number of records (up to 100)
  5. Run batch test

Batch Results:

  • Total tested count
  • Would trigger count
  • Would not trigger count
  • Pass rate percentage
  • Per-record breakdown with failing reasons
  • Export to CSV option

Value Overrides

Test "what if" scenarios without modifying actual data:

  1. In the test configuration, expand "Value Overrides"
  2. Add override entries:
    • Field name (e.g., stage, total, status)
    • Override value
  3. The workflow evaluates as if the subject has these values

Example: Testing a workflow that triggers when stage = qualified:

  • Override stage to qualified
  • Run dry run to see if the workflow would execute

Run History

Track all test runs for comparison:

  1. Navigate to test configuration
  2. Click "View History"
  3. See all runs with:
    • Timestamp
    • Mode (dry run / execute)
    • Result status
    • Conditions pass count
  4. Compare two runs side-by-side

Technical Details

Models:

  • WorkflowTest - Saved test configurations
  • WorkflowTestRun - Individual test run results

Services:

  • TriggerSimulator - Generates simulation fields and context
  • WorkflowBatchTester - Handles batch testing against multiple records
  • WorkflowEngine::dryRun() - Non-destructive workflow evaluation

Routes:

GET  /admin/workflow-tests              # List tests
GET  /admin/workflow-tests/create       # Create form
POST /admin/workflow-tests              # Store test
GET  /admin/workflow-tests/{test}/edit  # Edit form
POST /admin/workflow-tests/{test}/run   # Run test
GET  /admin/workflow-tests/{test}/{run} # View results
GET  /admin/workflow-tests/{test}/history # Run history
GET  /admin/workflow-tests/{test}/batch # Batch testing
GET  /admin/workflow-tests/{test}/compare # Compare runs

Seeding Test Data:

The WorkflowTestSeeder creates test configurations for all seeded workflows:

php artisan db:seed --class=WorkflowTestSeeder

The seeder:

  • Creates a dry run test for each workflow
  • Creates execute tests for ~50% of workflows
  • Auto-generates value overrides from workflow conditions
  • Handles changed_to conditions with proper context
  • Configures trigger simulation based on workflow type

Workflow Templates

Workflow templates allow you to save and reuse workflow configurations.

Accessing Templates

Navigate to Admin → More → Workflow Templates or /admin/workflow-templates.

Creating Templates

  1. Navigate to a workflow detail page
  2. Click "Save as Template"
  3. Provide a name and optional category
  4. Click "Save"

Using Templates

  1. Navigate to Workflow Templates
  2. Find the desired template
  3. Click "Use Template"
  4. A new workflow is created from the template
  5. Customize and activate

Template Categories

Templates can be organized by category:

  • Filter by category on the templates page
  • Categories are user-defined

Template Information

Each template shows:

  • Name and description
  • Category tag
  • Trigger type
  • Number of actions
  • Number of conditions
  • Usage count
  • Creator

Webhook Triggers

Workflows can be triggered by external webhooks for integration with third-party services.

Enabling Webhook Triggers

  1. Create or edit a workflow
  2. Set trigger type to "Webhook"
  3. Save the workflow
  4. A unique webhook URL is generated

Getting Webhook URL

  1. Navigate to the workflow detail
  2. Click "Get Webhook URL"
  3. Copy the provided URL

Webhook URL Format

https://your-domain.com/api/webhooks/workflows/{token}

Regenerating Webhook Token

For security, you can regenerate the webhook token:

  1. Navigate to workflow detail
  2. Click "Regenerate Webhook"
  3. Update any integrations with the new URL

Webhook Request Format

Send a POST request to the webhook URL:

curl -X POST https://your-domain.com/api/webhooks/workflows/{token} \
  -H "Content-Type: application/json" \
  -d '{"key": "value"}'

The request body becomes available as trigger data.


Technical Architecture

Models

Workflow Model: app/Models/Workflow.php

class Workflow extends Model
{
    protected $fillable = [
        'name',
        'description',
        'trigger',
        'trigger_config',
        'conditions',
        'actions',
        'is_active',
    ];

    protected $casts = [
        'trigger_config' => 'array',
        'conditions' => 'array',
        'actions' => 'array',
        'is_active' => 'boolean',
    ];
}

WorkflowExecution Model: app/Models/WorkflowExecution.php

class WorkflowExecution extends Model
{
    protected $fillable = [
        'workflow_id',
        'trigger_data',
        'status',
        'results',
        'error',
        'started_at',
        'completed_at',
    ];
}

Services

Location: app/Services/Workflow/

WorkflowEngine

Core workflow execution engine.

class WorkflowEngine
{
    public function trigger(string $event, array $data): void
    {
        $workflows = Workflow::active()
            ->where('trigger', $event)
            ->get();

        foreach ($workflows as $workflow) {
            ExecuteWorkflowJob::dispatch($workflow, $data);
        }
    }

    public function execute(Workflow $workflow, array $data): WorkflowExecution
    {
        $execution = WorkflowExecution::create([
            'workflow_id' => $workflow->id,
            'trigger_data' => $data,
            'status' => 'running',
            'started_at' => now(),
        ]);

        try {
            if ($this->evaluateConditions($workflow->conditions, $data)) {
                $results = $this->executeActions($workflow->actions, $data);
                $execution->update([
                    'status' => 'completed',
                    'results' => $results,
                    'completed_at' => now(),
                ]);
            } else {
                $execution->update([
                    'status' => 'skipped',
                    'completed_at' => now(),
                ]);
            }
        } catch (Exception $e) {
            $execution->update([
                'status' => 'failed',
                'error' => $e->getMessage(),
                'completed_at' => now(),
            ]);
        }

        return $execution;
    }
}

WorkflowDebugger

Debugging and analysis service for workflow executions.

class WorkflowDebugger
{
    public function startSession(WorkflowExecution $execution): array;
    public function logStep(int $executionId, string $step, array $data): void;
    public function logCondition(int $executionId, array $condition, bool $result): void;
    public function logAction(int $executionId, string $action, array $data): void;
    public function logError(int $executionId, string $error, array $context): void;
    public function endSession(int $executionId, string $status): void;
    public function analyzeExecution(WorkflowExecution $execution): array;
    public function getExecutionHistory(Workflow $workflow, int $limit): array;
}

WorkflowAnalyticsService

Analytics and insights service for workflow metrics.

class WorkflowAnalyticsService
{
    public function getDashboardStats(): array;
    public function getPerformanceMetrics(int $days = 30): array;
    public function getTopWorkflows(int $limit = 10): array;
    public function getWorkflowsNeedingAttention(): array;
    public function getTriggerTypeStats(): Collection;
    public function getActionTypeStats(): Collection;
    public function getHourlyDistribution(): array;
    public function getRecentFailures(int $limit = 10): array;
    public function getRecommendations(): array;
}

Event Integration

// In EventServiceProvider or Observer
Event::listen(InvoiceCreated::class, function ($event) {
    app(WorkflowEngine::class)->trigger('invoice.created', [
        'invoice' => $event->invoice->toArray(),
        'client' => $event->invoice->client->toArray(),
    ]);
});

Controller

Location: app/Http/Controllers/Admin/WorkflowController.php

MethodRouteDescription
index()GET /admin/workflowsList workflows
create()GET /admin/workflows/createCreate form
store()POST /admin/workflowsSave workflow
show()GET /admin/workflows/{id}View workflow
edit()GET /admin/workflows/{id}/editEdit form
update()PUT /admin/workflows/{id}Update workflow
destroy()DELETE /admin/workflows/{id}Delete workflow
test()POST /admin/workflows/{id}/testTest run
logs()GET /admin/workflows/{id}/logsExecution logs
analytics()GET /admin/workflows-analyticsAnalytics dashboard
debugExecution()GET /admin/workflow-executions/{id}/debugDebug execution
templates()GET /admin/workflow-templatesTemplate library
saveAsTemplate()POST /admin/workflows/{id}/save-as-templateSave as template
createFromTemplate()POST /admin/workflow-templates/{id}/useCreate from template
getWebhookUrl()GET /admin/workflows/{id}/webhook-urlGet webhook URL
regenerateWebhook()POST /admin/workflows/{id}/regenerate-webhookRegenerate webhook

Routes

// Workflow resource routes
Route::resource('workflows', WorkflowController::class);
Route::post('/workflows/{workflow}/test', [WorkflowController::class, 'test']);
Route::post('/workflows/{workflow}/toggle', [WorkflowController::class, 'toggle']);

// Workflow analytics and debugging
Route::get('/workflows-analytics', [WorkflowController::class, 'analytics']);
Route::get('/workflow-executions/{execution}/debug', [WorkflowController::class, 'debugExecution']);

// Workflow templates
Route::get('/workflow-templates', [WorkflowController::class, 'templates']);
Route::post('/workflows/{workflow}/save-as-template', [WorkflowController::class, 'saveAsTemplate']);
Route::post('/workflow-templates/{template}/use', [WorkflowController::class, 'createFromTemplate']);

// Webhook management
Route::get('/workflows/{workflow}/webhook-url', [WorkflowController::class, 'getWebhookUrl']);
Route::post('/workflows/{workflow}/regenerate-webhook', [WorkflowController::class, 'regenerateWebhook']);

Database Tables

Table: workflows

ColumnTypeDescription
idbigintPrimary key
namestringWorkflow name
descriptiontextDescription
trigger_typestringTrigger event
trigger_modelstringModel for trigger
trigger_configjsonTrigger options
is_activebooleanEnabled status
webhook_tokenstringUnique webhook token
visual_configjsonVisual editor config
versionstringVersion number
priorityintegerExecution priority
execution_countintegerTotal executions
last_executed_attimestampLast execution time
created_attimestampCreated date

Table: workflow_executions

ColumnTypeDescription
idbigintPrimary key
workflow_idbigintWorkflow FK
subject_typestringSubject model type
subject_idbigintSubject model ID
statusstringpending/running/completed/failed
duration_msintegerExecution duration in ms
step_logsjsonStep-by-step logs
triggered_bystringTrigger source
contextjsonExecution context
error_messagetextError message
started_attimestampStart time
completed_attimestampEnd time

Table: workflow_templates

ColumnTypeDescription
idbigintPrimary key
namestringTemplate name
descriptiontextDescription
categorystringCategory name
definitionjsonWorkflow definition
is_publicbooleanPublic visibility
usage_countintegerTimes used
created_bybigintCreator user ID
created_attimestampCreated date

Discovery Flow Workflows

The system includes pre-built workflows for automating email notifications throughout the client discovery process.

Available Discovery Workflows

WorkflowTriggerConditionEmail Template
Discovery: Questionnaire Submittedmodel_updated on DiscoveryQuestionnairestatus changed_to 'submitted'discovery_questionnaire_received
Discovery: Lead Qualifiedclient_stage_changedstage = 'qualified'discovery_lead_qualified
Discovery: Lead Declinedclient_stage_changedstage = 'declined'discovery_lead_declined
Discovery: Call Scheduledmodel_updated on DiscoveryCallstatus changed_to 'scheduled'discovery_call_booked
Discovery: Call Completedmodel_updated on DiscoveryCallstatus changed_to 'completed'discovery_call_completed
Discovery: Proposal Sentclient_stage_changedstage = 'proposal_sent'discovery_proposal_sent
Discovery: Proposal Acceptedclient_stage_changedstage = 'proposal_accepted'discovery_proposal_accepted

Seeding Discovery Workflows

# First, seed the notification templates
php artisan db:seed --class=DiscoveryNotificationTemplatesSeeder

# Then, seed the workflows
php artisan db:seed --class=DiscoveryWorkflowsSeeder

Discovery Variable Resolution

The WorkflowVariableResolver supports DiscoveryQuestionnaire and DiscoveryCall models:

DiscoveryQuestionnaire Variables:

{{ client_name }}
{{ client_email }}
{{ client_phone }}
{{ questionnaire_id }}
{{ submitted_at }}

DiscoveryCall Variables:

{{ client_name }}
{{ client_email }}
{{ client_phone }}
{{ call_id }}
{{ scheduled_at }}      (e.g., "Monday, January 20, 2026 at 2:00 PM")
{{ scheduled_date }}    (e.g., "January 20, 2026")
{{ scheduled_time }}    (e.g., "2:00 PM")
{{ meeting_url }}

Scheduled Call Reminders

In addition to workflow-triggered emails, time-based reminders are sent via a scheduled command:

# Test what reminders would be sent
php artisan discovery:send-call-reminders --dry-run

# Actually send reminders
php artisan discovery:send-call-reminders

The command runs every 15 minutes and sends:

  • 24-hour reminders: For calls scheduled 23-25 hours away
  • 1-hour reminders: For calls scheduled 30-90 minutes away

Reminder tracking columns (reminder_24h_sent_at, reminder_1h_sent_at) prevent duplicate sends.


Example Workflows

Auto-Complete Project on Final Payment

{
  "name": "Complete project on payment",
  "trigger": "invoice.paid",
  "conditions": [
    {"field": "invoice.is_final", "operator": "equals", "value": true}
  ],
  "actions": [
    {
      "type": "update_status",
      "entity": "project",
      "id": "{{invoice.project_id}}",
      "status": "completed"
    },
    {
      "type": "send_email",
      "to": "{{client.email}}",
      "template": "project-completed"
    }
  ]
}

Send Overdue Reminders

{
  "name": "Send overdue reminder",
  "trigger": "scheduled",
  "trigger_config": {"cron": "0 9 * * *"},
  "conditions": [],
  "actions": [
    {
      "type": "query",
      "model": "Invoice",
      "where": [
        ["status", "=", "sent"],
        ["due_date", "<", "{{now}}"]
      ],
      "each": [
        {
          "type": "send_email",
          "to": "{{item.client.email}}",
          "template": "invoice-overdue"
        }
      ]
    }
  ]
}

Dependencies

FeatureRelationship
Background JobsAsync execution
NotificationsEmail actions
WebhooksWebhook actions

Complementary Features

FeatureDescription
Activity LoggingLogs executions
Admin ToolsManagement tools
Client Intake & Portal FlowDiscovery workflows and email notifications

Workflow Versioning

Track changes to workflows with version history and rollback capability.

Creating Versions

Versions are automatically created when making significant changes. You can also manually create a version before making changes.

Version History

Navigate to a workflow and click "Version History" to see all versions:

FieldDescription
VersionVersion number (v1, v2, etc.)
Change NotesDescription of changes
Created ByUser who created the version
PublishedWhether this version is active
Created AtWhen version was created

Rolling Back

  1. Navigate to workflow version history
  2. Find the version you want to restore
  3. Click "Rollback to this version"
  4. Confirm the rollback

The workflow will be restored to the exact state captured in that version.

Technical Details

// Create a version before changes
$versionService = app(WorkflowVersionService::class);
$version = $versionService->createVersion($workflow, 'Before major changes');

// Publish a version (make it active)
$versionService->publish($version);

// Rollback to a specific version number
$versionService->rollback($workflow, 1);

// Get version history
$history = $versionService->getHistory($workflow);

// Compare two versions
$diff = $versionService->compare($version1, $version2);

A/B Testing Workflows

Test different workflow configurations to optimize performance.

Setting Up an A/B Test

  1. Navigate to workflow detail
  2. Click "Enable A/B Testing"
  3. Add variants with different configurations
  4. Set weights for each variant (e.g., 50/50 split)
  5. Enable the workflow

Variant Configuration

FieldDescription
NameVariant name (e.g., "Control", "Variant A")
WeightSelection probability (1-100)
Is ControlMark as the baseline variant
DefinitionVariant-specific workflow configuration

Monitoring Results

View variant statistics:

  • Execution Count: Times this variant was used
  • Success Rate: Percentage of successful executions
  • Average Duration: Mean execution time
  • vs Control: Comparison with control variant

Statistical Significance

The system calculates statistical significance to determine if results are meaningful:

  • Minimum 100 executions recommended for significance
  • 95% confidence level indicates significant results

Promoting a Winner

Once you have significant results:

  1. Review comparison statistics
  2. Click "Promote Variant" on the best performer
  3. The variant configuration becomes the main workflow
  4. A/B testing is automatically disabled

Technical Details

// Create variants
$abService = app(WorkflowABTestService::class);
$control = $abService->createVariant($workflow, 'Control', $definition, 50, true);
$variantA = $abService->createVariant($workflow, 'Variant A', $altDefinition, 50, false);

// Select variant for execution (weighted random)
$variant = $abService->selectVariant($workflow);

// Get comparison statistics
$comparison = $abService->compareVariants($workflow);

// End test and optionally promote winner
$winner = $abService->endTest($workflow, promoteWinner: true);

Parallel Branch Execution

Execute multiple workflow branches simultaneously for improved performance.

Defining Parallel Branches

In the workflow definition, create a parallel step:

{
  "type": "parallel",
  "branches": [
    {
      "name": "Email Branch",
      "steps": [
        {"type": "send_email", "config": {...}}
      ]
    },
    {
      "name": "Webhook Branch",
      "steps": [
        {"type": "webhook", "config": {...}}
      ]
    }
  ]
}

Branch Execution

  • All branches execute concurrently using Laravel job batching
  • Each branch tracks its own status and results
  • Execution continues after all branches complete (or fail)

Monitoring Branches

View branch status in execution details:

  • Individual branch status (pending/running/completed/failed)
  • Per-branch execution duration
  • Error messages for failed branches

Best Practices

  1. Test workflows before enabling
  2. Use specific conditions to avoid unintended triggers
  3. Monitor execution logs regularly
  4. Document complex workflows
  5. Set up alerts for failed workflows

Troubleshooting

IssueSolution
Workflow not triggeringCheck trigger event and is_active
Actions not executingReview condition logic
Email not sendingCheck email configuration
Performance issuesLimit workflow scope

See Also