A generic, reusable pipeline engine for the LEO platform. Any object — a CRM opportunity, a support ticket, a provisioning request — can be enrolled in a configurable workflow and moved through ordered stages without touching the original table.
- Polymorphic — attach a pipeline to any platform object via
object_type/object_id - Multi-pipeline — the same object can participate in multiple pipelines simultaneously
- Custom fields — define pipeline-scoped columns (EAV) with typed validation
- Stage entry requirements — enforce that specific fields are filled before a stage transition
- Checklists — per-stage task lists tracked individually per item
- SLA tracking — configurable day limits per stage with breach detection
- Automations — fire named platform events on stage transitions, item creation, or SLA breach
- Audit trail — immutable stage history for every item
- Watchers — subscribe users to item updates
- Templates — define reusable pipeline blueprints and clone them per account
- PHP >= 8.2
- Laravel >= 10
- NextDeveloper Commons
- NextDeveloper IAM
- NextDeveloper Events
Install via Composer:
composer require nextdeveloper/flowRegister the service provider (if not using auto-discovery):
// config/app.php
'providers' => [
NextDeveloper\Flow\FlowServiceProvider::class,
],Publish the config file:
php artisan vendor:publish --provider="NextDeveloper\Flow\FlowServiceProvider" --tag="config"Run the migrations (managed at the application level — see your platform's migration set for flow_* tables).
| Table | Purpose |
|---|---|
flow_pipelines |
Pipeline definitions |
flow_stages |
Ordered stages per pipeline |
flow_columns |
Custom field definitions per pipeline |
flow_stage_required_columns |
Fields required before entering a stage |
flow_items |
Polymorphic object ↔ stage links |
flow_item_values |
EAV values for custom columns per item |
flow_stage_history |
Immutable audit log of all stage transitions |
flow_automations |
Event rules triggered on stage transitions |
flow_item_watchers |
Users following an item |
use NextDeveloper\Flow\Services\PipelinesService;
$pipeline = PipelinesService::create([
'name' => 'Sales Pipeline',
'object_type' => 'crm_opportunity',
'is_active' => true,
]);use NextDeveloper\Flow\Services\StagesService;
StagesService::create([
'flow_pipeline_id' => $pipeline->uuid,
'name' => 'Lead',
'position' => 0,
'color' => '#94a3b8',
'probability' => 10,
'sla_days' => 7,
]);
StagesService::create([
'flow_pipeline_id' => $pipeline->uuid,
'name' => 'Won',
'position' => 3,
'color' => '#22c55e',
'probability' => 100,
'is_won' => true,
]);use NextDeveloper\Flow\Services\ItemsService;
$item = ItemsService::create([
'flow_pipeline_id' => $pipeline->uuid,
'flow_stage_id' => $leadStage->uuid,
'object_type' => 'crm_opportunity',
'object_id' => $opportunity->id,
]);
// Initial stage history entry is recorded automatically.// The service validates required columns, resets the checklist,
// records history, fires automations and notifies watchers.
ItemsService::update($item->uuid, [
'flow_stage_id' => $qualifiedStage->uuid,
]);use NextDeveloper\Flow\Services\ItemValuesService;
ItemValuesService::upsert(
itemUuid: $item->uuid,
columnUuid: $contractValueColumn->uuid,
value: '42500'
);$livePipeline = PipelinesService::cloneFromTemplate($templateUuid);
// Stages, columns, entry requirements and automations are all copied.All endpoints are mounted under the /flow prefix. Every resource follows the same
REST pattern:
GET /flow/{resource} List (supports filters & pagination)
GET /flow/{resource}/{uuid} Show
POST /flow/{resource} Create
PATCH /flow/{resource}/{uuid} Update
DELETE /flow/{resource}/{uuid} Delete
POST /flow/{resource}/{uuid}/do/{action} Execute a named action
Resources: pipelines, stages, items, columns, item-values,
stage-required-columns, stage-history, automations, item-watchers
Filter parameters are passed as query strings. Add paginate=true for paginated
responses (per_page and page are also accepted).
For a full endpoint reference including request bodies and response shapes, see docs/UI.md.
When flow_stage_id is updated on an item the following happens automatically:
- Validate — checks
flow_stage_required_columnsfor the target stage. If any required column has no value inflow_item_values, the update is rejected with aNotAllowedExceptionlisting the missing column IDs. - Reset checklist —
checklist_stateis set tonullso the new stage's checklist starts fresh. - Timestamp —
last_stage_changed_atis set to now. - History — an entry is appended to
flow_stage_history. - Automations — active
stage_exitedautomations for the old stage andstage_enteredautomations for the new stage are fired via the Events system. - Watchers — a
item_stage_changed:NextDeveloper\Flow\Itemsevent is fired for any registered listeners to notify watchers.
| Trigger | When it fires |
|---|---|
item_created |
A new item is added to a pipeline |
stage_entered |
An item moves into a stage |
stage_exited |
An item moves out of a stage |
sla_breached |
An item has exceeded sla_days in its current stage |
Set flow_stage_id to null on an automation to make it fire for all stage transitions
in the pipeline.
Dispatch CheckSlaBreachesJob on a schedule (recommended: hourly) to detect and fire
sla_breached automations:
// app/Console/Kernel.php
$schedule->job(new \NextDeveloper\Flow\Jobs\CheckSlaBreachesJob)->hourly();The job finds all items where time in stage exceeds the stage's sla_days and fires
the matching automations. Stages with is_won = true or is_lost = true are excluded.
field_type |
Expected value format |
|---|---|
text |
Plain string |
number |
Numeric string, e.g. "42500" |
date |
ISO 8601, e.g. "2026-07-01" |
boolean |
"true" or "false" |
select |
One of the strings in column options |
multi_select |
JSON array string, e.g. '["High","Urgent"]' |
json |
Any valid JSON string |
All values are stored as TEXT. The field_type on flow_columns is the contract for
how consumers should cast and validate them.
After publishing, config/flow.php accepts global and per-model scope classes:
return [
'scopes' => [
'global' => [], // Applied to every flow model
'flow_items' => [], // Applied to Items only
// flow_pipelines, flow_stages, flow_columns, ...
],
];To enable or disable the module's routes:
// config/leo.php
'allowed_routes' => [
'flow' => true,
],| File | Contents |
|---|---|
| docs/Module.md | Architecture overview, data model, lifecycle queries |
| docs/UI.md | UI development guide — screens, API reference, interaction flows |
MIT — see LICENSE.
For questions, issues, or enterprise support:
Email: support@plusclouds.com
Please include your platform version, PHP version, and a description of the issue.