nganthoiba / laravel-dynamic-workflow
A dynamic graph-based workflow engine and visual designer for Laravel.
Package info
github.com/Nganthoiba/laravel-dynamic-workflow
Language:Blade
pkg:composer/nganthoiba/laravel-dynamic-workflow
Requires
- php: ^8.2
- illuminate/database: ^10.0|^11.0|^12.0
- illuminate/http: ^10.0|^11.0|^12.0
- illuminate/routing: ^10.0|^11.0|^12.0
- illuminate/support: ^10.0|^11.0|^12.0
- illuminate/view: ^10.0|^11.0|^12.0
Requires (Dev)
README
A powerful, dynamic graph-based workflow engine and visual designer for Laravel.
This package allows you to define complex business processes visually and execute them using a robust runtime workflow engine with support for dynamic routing, conditional branching, runtime task management, role-based authorization, and workflow history tracking.
Unlike traditional hardcoded approval systems, this package enables workflows to evolve dynamically over time without modifying application source code.
Features
- Visual Workflow Designer powered by LogicFlow
- Dynamic Graph-Based Workflow Engine
- Conditional Workflow Routing
- Nested Conditional Branching
- Runtime Task Inbox
- Role-Based Workflow Execution
- Workflow History and Audit Tracking
- Workflow Cancellation Support
- Configurable Workflow Actions
- Reusable StepAction Hooks
- Dynamic Step Addition/Removal
- Enterprise Workflow Architecture
- Vendor Agnostic User/Role Integration
- Composer Installable Laravel Package
Why Dynamic Workflows Matter
In real-world enterprise systems, workflows are rarely fixed permanently.
Business rules continuously evolve over time.
For example, a Purchase Order approval process may initially follow this flow:
Employee ↓ Assistant Manager ↓ Sales Director ↓ Admin Approval
However, organizational policies frequently change.
At any point in time:
- a new approval authority may be added
- an existing authority may be removed
- approval chains may become shorter or longer
- conditional routing rules may change
- different departments may follow different workflows
- workflows may vary based on amount, region, category, or risk level
Example: If amount > 5,00,000 → Finance Director Approval Required
Else → Skip Finance Director
Or: If region = HQ → Route to Central Admin
Else → Route to Regional Office
Traditional hardcoded approval systems become difficult to maintain in such scenarios because every workflow change requires:
- modifying source code
- redeploying the application
- database changes
- developer intervention
This package solves that problem by providing a fully dynamic graph-based workflow engine.
Dynamic Workflow Modification
One of the core strengths of this package is that workflows can be modified dynamically without changing application source code.
Administrators can:
- add new workflow steps
- remove existing workflow steps
- insert intermediate approvals
- modify routing conditions
- redesign the workflow graph visually
- change role assignments
- alter conditional branching
- redesign approval hierarchies
All of these changes can be performed visually using the Workflow Designer.
Example: A workflow can evolve from: Employee → Manager → Admin
to: Employee → Assistant Manager → Manager → Finance Director → Admin
without modifying the core business application.
Conditional Workflow Intelligence
The workflow engine supports intelligent runtime routing using Condition Nodes. These nodes dynamically determine the next workflow path based on runtime data.
How Conditions Work
A ConditionNode is always placed after a StepNode. For it to evaluate logic correctly, it requires specific data (keys and values) to be available in the evaluation context. Data can be provided in two ways:
- Client-Side Input (Blade Views): Data passed from the preceding step's Blade view as form input parameters. For example, a button like
<button name="action_result" value="approved">will provide theaction_resultkey to the following ConditionNode. - Model Attributes (Database): The engine can evaluate fields directly from the Eloquent model associated with the workflow. For instance, an
amountcolumn in thepurchase_orderstable can be used as an evaluation key.
Configuration
Available condition fields are defined in config/workflow_conditions.php. Any key used in your workflow design must either be passed from the client-side form or exist as an attribute on the associated database model.
For example, if action_result is used as a key in workflow_conditions.php, it must be passed from the client-side form as an input parameter. This is because action_result is not an attribute of the business model itself; it is a custom parameter passed directly from the client form to the ConditionNode.
Important
Why action_result is Compulsory:
Even if action_result is not explicitly used as a condition in workflow_conditions.php, developers must ensure this parameter is sent from the client-side form (for example, through button submission like name="action_result").
When completing a step, the workflow engine (specifically inside WorkflowInstanceService) uses it to record the exact user action in the execution history:
'action' => $context['action_result'] ?? $currentStep->workflow_action,
If action_result is omitted, the engine falls back to the step's default registered workflow_action code. Passing a distinct action value (e.g., approve, reject, or send_back) ensures that the precise decision made by the user is recorded in the task history audit trail and allows custom step actions (like ApproveOrderAction) to execute conditional business logic based on that selection.
Adding a New Condition Field
To make a new field available for conditional routing in the visual workflow designer, append its configuration array to the fields list within config/workflow_conditions.php.
Field Configuration Schema
| Key | Type | Required | Description |
|---|---|---|---|
key |
string |
Yes | The unique machine-readable identifier (e.g., amount, region) that the engine looks for in the evaluation context (from client form parameters or model columns). |
label |
string |
Yes | The human-readable name displayed in the visual designer's condition builder dropdown. |
type |
string |
Yes | The input value type for the UI. Supported types: number, string, date, enum. |
operators_json |
array |
Yes | List of allowed logical operators. Supported: =, !=, >, <, >=, <=, in, contains. |
options_json |
array |
Required if type is enum |
An array of option objects defining the dropdown values. Each option must contain value and label. |
Example: Adding a Department Condition
To register a new department condition field, update config/workflow_conditions.php as follows:
'fields' => [ // ... existing condition fields [ 'key' => 'department', 'label' => 'Department', 'type' => 'enum', 'operators_json' => ['=', '!='], 'options_json' => [ ['value' => 'sales', 'label' => 'Sales Dept'], ['value' => 'hr', 'label' => 'Human Resources'], ['value' => 'engineering', 'label' => 'Engineering'], ], ], ],
Once declared, this field will instantly populate the visual editor's condition node dropdown, enabling custom business flows (e.g. If department == sales → Route to Sales Director).
Examples
- Purchase Amount:
If amount > 100,000→ Route to Director. - Action Result:
If action_result == 'rejected'→ Route to Correction Step. - Region/Department:
If region == 'HQ'→ Route to Central Admin.
Nested conditional workflows are also supported (e.g., Amount > 100,000 → Region == 'HQ'), allowing for complex, enterprise-grade decision trees.
Designed for Enterprise Adaptability
This package is specifically designed for environments where workflow structures are not permanently fixed.
Suitable industries include:
- Government systems
- Excise and permit systems
- ERP systems
- Banking systems
- Manufacturing systems
- Universities and institutions
- Warehouse management
- Dispatch systems
- HR approval systems
- Procurement systems
- Compliance systems
The engine enables organizations to continuously evolve business processes without rewriting application logic.
Separation of Workflow and Business Logic
The package separates:
- workflow definition
- workflow routing
- runtime task execution
- business actions
- approval hierarchy
- UI rendering
This separation makes large systems significantly easier to maintain and extend. Business applications only define workflow actions, forms/views, and business operations, while the workflow engine dynamically controls routing, authorization, transitions, task assignment, and conditional branching.
Runtime Workflow Flexibility
The workflow runtime engine supports:
- active workflow instances
- pending task inboxes
- workflow cancellation
- workflow history tracking
- audit trails
- runtime role authorization
- task reassignment possibilities
- conditional execution paths
This allows the package to function as both a workflow engine and a business process management (BPM) system.
Visual Workflow Evolution
The built-in visual designer allows administrators to continuously evolve workflows as organizational requirements change. Instead of hardcoding approval chains, workflows become configurable operational assets.
This dramatically reduces maintenance overhead, release cycles, developer dependency, and operational rigidity, while improving flexibility, scalability, transparency, and auditability.
Workflow Architecture
The package uses a graph-based runtime architecture.
Supported node types:
- Start Node: Exactly one outgoing edge.
- Step Node: Exactly one outgoing edge. Represents an executable business task.
- Condition Node: Exactly two outgoing edges (TRUE and FALSE branch). May point to another condition node or a step node.
- End Node: No outgoing edges.
Workflow Runtime Design
The package separates workflow runtime into two major concepts:
1. Current Workflow State (workflow_instances)
Tracks the current active step, status, runtime state, and completion/cancellation.
Important: workflow_instances.current_step_id represents the CURRENT ACTIVE PENDING STEP, not the last completed step.
2. Workflow Execution History (workflow_instance_steps)
Tracks executed tasks, active tasks, comments, timestamps, audit trails, and user actions.
Important: A workflow task is considered OPEN if completed_at IS NULL, and COMPLETED if completed_at IS NOT NULL.
Visual Workflow Designer
The package includes an interactive drag-and-drop workflow designer powered by LogicFlow.
- draggable nodes
- resizable nodes
- directional workflow arrows
- nested conditional trees
- multiple graph directions
- runtime graph persistence
- visual workflow editing
Installation
Install the package via Composer:
composer require nganthoiba/laravel-dynamic-workflow
Publish Package Resources
php artisan vendor:publish --provider="Workflow\Providers\WorkflowServiceProvider"
Or you can publish specific resources using tags:
workflow-config: Package configurationworkflow-views: Management views (inbox, history, designer)workflow-step-views: Runtime action views (e.g., Approve and Forward)workflow-assets: JS and CSS assets
Run Migrations
php artisan migrate
Configuration
Update config/workflow.php:
'models' => [ 'role' => \App\Models\Role::class, 'user' => \App\Models\User::class, ],
Workflow Actions (Hooks)
Workflow actions define the executable business behavior of workflow steps. Each executable step references a workflow_action which determines the Blade view, Action class, and runtime behavior.
Creating Workflow Actions
Create a class implementing Workflow\Core\Contracts\StepActionInterface.
namespace App\Workflow\Actions; use Workflow\Core\Contracts\StepActionInterface; use Workflow\Models\WorkflowInstanceStep; use Illuminate\Database\Eloquent\Model; class ApproveOrderAction implements StepActionInterface { public function validate(array $data): array { return validator($data, [ 'remarks' => 'nullable|string|max:500', 'action_result' => 'nullable|string', ])->validate(); } public function execute( array $data, Model $model, WorkflowInstanceStep $workflowInstanceStep ): void { /** * Perform your business logic by getting the required parameters from * the $data. */ if($data['action_result'] == 'reject') { $model->update([ 'status' => 'rejected', 'remark' => $data['remarks'], ]); } else { $model->update([ 'status' => 'approved', 'remark' => $data['remarks'], ]); } logger()->info("Order {$model->id} approved."); } }
Registering Workflow Actions
- Register actions inside
config/workflow.php:
'workflow_actions' => [ 'approve_order' => [ 'label' => 'Approve Order', 'view' => 'approve_order_view', 'action' => \App\Workflow\Actions\ApproveOrderAction::class, ], ],
- Create the corresponding Blade view at
resources/views/workflow/steps/approve_order_view.blade.php. Every workflow step view MUST extend the package's task layout. You can include any number of custom fields within theform_fieldssection, as shown below:
@extends('vendor.workflow.task_layout') @section('form_fields') <div class="mb-3"> <label for="input_field1" class="form-label">Input 1</label> <input type="text" name="input_field1" id="input_field1" class="form-control"> </div> <div class="mb-3"> <label for="input_field2" class="form-label">Input 2</label> <input type="text" name="input_field2" id="input_field2" class="form-control"> </div> @endsection @section('form_actions') <button type="submit" name="action_result" value="rejected" class="btn btn-outline-danger"> Reject </button> <button type="submit" name="action_result" value="approved" class="btn btn-primary"> Approve & Forward </button> @endsection
The parameters passed in these fields will be handled at the action class that implements StepActionInterface for example in our case is ApproveOrderAction as defined earlier in the Workflow Actions (Hooks) section. The variable $data contains all the form data.
Reference Model Requirements
Important
Compulsory Status Field:
In the workflow_instances database table (represented by the WorkflowInstance model), there is a field called reference_type which can store the class name of any Eloquent model (e.g., App\Models\PurchaseOrder) that refers to a record in your application's database.
The database table associated with any Eloquent model used as a reference_type must compulsorily have a status column/field.
The dynamic workflow runtime engine, the inbox/outbox task management lists, and the main task auditing layouts (task_layout.blade.php) heavily rely on this reference table's status field to correctly track, validate, and visually render color-coded badge states (such as Approved, Completed, Rejected, or Cancelled) across the application workflow lifecycle.
Reference Summary Views
When a user opens a task in their inbox, they need to see the details of the business object (e.g., a Purchase Order) being processed. This package uses a dynamic view injection system for these summaries.
1. Create the Summary View
Create a Blade file in your application at resources/views/workflow/reference/. For example, for a PurchaseOrder model:
resources/views/workflow/reference/purchase_order.blade.php:
<div class="row"> <div class="col-md-6"> <p><strong>Order Number:</strong> {{ $model->order_number }}</p> <p><strong>Date:</strong> {{ $model->created_at->format('d M Y') }}</p> </div> <div class="col-md-6"> <p><strong>Total Amount:</strong> {{ number_format($model->total_amount, 2) }}</p> <p><strong>Vendor:</strong> {{ $model->vendor->name }}</p> </div> </div>
2. Register the Mapping
In config/workflow.php, map your business model class to its specific summary view:
'reference_views' => [ \App\Models\PurchaseOrder::class => 'workflow.reference.purchase_order', ],
The package will now automatically inject this view into the task execution layout (task_layout.blade.php) whenever a workflow task related to that model is being performed.
Convention Over Configuration (Fallback)
If you do not explicitly register a mapping in config/workflow.php, the package will automatically look for a view using a snake_case convention of the model's class name.
Example:
- Model Class:
App\Models\DispatchOrder - Default View Path:
resources/views/workflow/reference/dispatch_order.blade.php
This allows you to quickly add support for new models simply by creating the corresponding blade file in the workflow/reference directory.
Process Creation & Visual Workflow Designing
The package provides a complete administrative UI to define workflow metadata and visually design execution pipelines without editing code.
1. Managing & Creating Workflow Processes
Navigate to /workflow/processes to access the Workflow Management Dashboard. Here, all processes are listed with their metadata, unique codes, active/inactive statuses, and shortcuts to edit properties or launch the visual canvas.
Creating a New Process
- Click Create New Process to open the creation form (
/workflow/processes/create). - Process Name: A descriptive name for the process (e.g.,
Purchase Order Approval). - Machine Code: A unique uppercase identifier (e.g.
PURCHASE_ORDER_APPROVAL) used programmatically to launch workflows. The form automatically converts the name to a clean snake-case slug in real-time, but you can manually override it. - Description: Define the business scope and purpose of the process.
- Activate Process (Toggle): Choose whether to activate the process. Inactive processes cannot be used to start new workflow instances.
2. Designing Workflows Graphically on the Canvas
Click the blue Designer button beside any process in the list to open the visual editing canvas (/workflow/designer/{id}).
The canvas is powered by an interactive LogicFlow engine that enables full graph layout customization.
🧰 Toolbox (Left Sidebar Node Types)
Drag and drop any of the four standard shapes from the left sidebar toolbox onto the canvas:
- 🟢 Start Node (Green Ellipse): Marks the entry point of the workflow pipeline. Every process must have exactly one.
- 🔵 Step Node (Blue Split-Block Rectangle): Represents an executable task.
- Header: Displays the Step Name (up to 40 characters).
- Body: Dynamically displays the list of Assigned Roles (up to 45 characters).
- 🟡 Condition Node (Yellow Diamond): Performs logical evaluation to branch routing paths dynamically.
- 🔴 End Node (Red Ellipse): Marks a final termination point of the workflow process.
🎮 Interactive Canvas Controls
- Reposition Nodes: Click and hold a node to drag it anywhere on the grid.
- Resize Nodes: Single-click any node to select it. A blue dotted boundary will appear with 8 square drag-handles. Click and drag any handle to scale the node boundaries.
- Connect Nodes (Transitions): Hover your mouse over any node to reveal blue anchor circles. Click and drag from an anchor circle to any other node to draw a directional arrow (transition edge).
- Context Hover Menu: Hovering over a node reveals a floating tooltip with quick actions:
- 📝 Edit: Opens the properties panel.
- 🗑️ Delete: Instantly removes the node or connection.
- Zoom Controls: Use the subtract (
-), add (+), or aspect-ratio buttons in the header to scale the canvas viewport.
3. Configuring Properties (Offcanvas Sidebar)
Single-click any node or transition arrow to slide-open the Properties Offcanvas Panel from the right.
📝 Step Node Properties
- Step Name: The human-readable name of the step.
- Machine Code: The unique slug used to handle specific step transitions.
- Description: Description of the operational tasks expected at this step.
- Workflow Action: Select a registered workflow step hook (from
config/workflow.php). This binds the step to a specific Blade form view and its backendStepActionInterfaceexecution class. - Roles Authorization: A checklist of role requirements. Only users carrying a checked role are authorized to view and execute this task from their Inbox.
🔗 Transition Line (Edge) Properties
- Action Label: Text displayed directly on the transition line (e.g.
Approve,Reject,Submit). - Branch Type:
Default: Standard progressive path.True Branch/False Branch: The specific branches originating from a Condition Node.
- Default Fallback (Toggle): Mark as fallback transition route if other conditional paths are not matched.
⚡ Condition Node Logic Builder
For Condition Nodes, click the Edit Logic button in the properties panel to open the modal-based Condition Logic Builder:
- Click Add Rule to define evaluation statements.
- Select a registered field key (from
config/workflow_conditions.php). - Choose a logical operator (e.g.,
is exactly,is not,>,<,is one of,contains). - Enter the matching value (displays a dropdown for
enumkeys and standard text/number/date inputs for others). - Chain multiple rules using standard
ANDlogic to build robust multi-variable gates.
4. Saving Your Workflow
Once your graph design is complete:
- Ensure the layout connects all nodes logically from Start to End.
- Click Save Workflow in the top-right header.
- This persists the graph coordinates, step parameters, and transition pathways to the database (
stepsandstep_transitionstables), making your changes live instantly for all new instances.
Starting a Workflow
use Workflow\Models\Process; use Workflow\Services\WorkflowInstanceService; $process = Process::where('code', 'ORDER_APPROVAL')->first(); $order = Order::find(1); $service = app(WorkflowInstanceService::class); $instance = $service->start($process, $order); // If you are inside a controller, get context from request $context = $request->all(); // Or just an empty array if there is nothing to pass $service->proceed($instance, $context);
Workflow Inbox
The package provides a built-in runtime task inbox at /workflow/inbox. Users can view pending tasks, execute steps, approve/reject requests, and track history.
Workflow Outbox
The package also provides a built-in outbox at /workflow/outbox. Users can view tasks they have previously completed, along with the action taken and completion timestamp. Clicking "View" on an outbox task allows users to see the task details in a read-only mode.
Workflow Execution Flow
- User submits a task.
WorkflowControllerresolves the workflow action.StepAction::validate()executes.StepAction::execute()executes.- Workflow task is marked completed.
- Workflow engine resolves the next node and advances dynamically.
Role-Based Workflow Authorization
Steps support role-based execution. Only authorized users with matching roles can execute a workflow task.
Workflow Cancellation
Supports runtime cancellation with status tracking (running, completed, cancelled, rejected), closed tasks, and audit traces with reasons.
Custom Node Handlers
Advanced users may extend Workflow\Core\Handlers\NodeHandler to implement custom behavior like parallel approvals or synchronization nodes.
Package Technology Stack
- Laravel
- PHP
- LogicFlow
- Blade
- Bootstrap
- Eloquent ORM
Future Roadmap
- parallel workflow branches
- workflow versioning
- workflow templates
- notification engine
- websocket updates
- SLA tracking
- BPMN compatibility
Contributing
Contributions, architecture suggestions, and feature requests are welcome.
License
MIT License