BPM End-to-End Walkthrough
BPMN Designer covers the designer's nodes and canvas; BPM Workflows covers how processes relate to Commands. This page connects those concepts to an example you can actually run: the OSS workflow-demo plugin.
workflow-demo is an open-source plugin (namespace wd) that is config-only plus a small backend jar. It uses a single "leave approval" business flow to exercise every part of BPM:
- Designer — the
wd_leave_approvalgraph covers start/end events, user tasks, exclusive gateways, plus AuraBoot's extended rule task, record-update task, and notification task. - Runtime — submitting a request makes Smart Engine instantiate the process and drive task assignment and routing by the graph.
- Rule engine — Drools rules decide who approves, and run a pre-flight validation before submission.
- SLA — approval tasks carry a deadline, warning, and escalation policy.
After this page you'll know what each piece looks like in config, and how to run it locally.
Demo scenario: leave approval
A leave request goes from draft to archive: validate, route to an approver by duration, get human approval, write the status back, notify the applicant. workflow-demo models this as a process definition wd_leave_approval, bound to the model wd_leave_request, triggered by the command wd:submit_leave_request.
draft
└─ wd:submit_leave_request
├─ pre-flight rule wd_leave_validation (balance / sick-leave attachment)
├─ start process wd_leave_approval (postActions.start_process)
└─ state transition draft|rejected → submitted
└─ engine runs the graph: rule route → gateway → approval task (with SLA)
→ result gateway → write status → notify → endThe full graph
The wd_leave_approval graph (the designer's designerJson) uses the nodes below. The BPMN Designer palette supports 12 node types in total; this example uses 7 of them, including 3 AuraBoot extension nodes.
| Node | Type (type) | Purpose |
|---|---|---|
Start (start_1) | startEvent | Process entry |
Routing Rule (svc_rule_route) | rule-task | Calls Drools rule wd_leave_routing, produces approverRole |
Approver Dispatch (gw_approver) | exclusiveGateway | Picks manager / hr branch by approverRole |
Manager Approve (task_manager_approve) | userTask | Assigned to role wd_manager, carries SLA wd_manager_approve_sla |
HR Approve (task_hr_approve) | userTask | Assigned to role wd_hr, carries SLA wd_hr_approve_sla |
Decision (gw_result) | exclusiveGateway | Picks approved / rejected branch by taskResult |
Set Status (svc_set_approved / svc_set_rejected) | record-update-task | Writes the wd_req_status field |
Notify Applicant (svc_notify_approved / svc_notify_rejected) | notification-task | Emits event wd_request_approved / wd_request_rejected |
Approved / Rejected (end_*) | endEvent | Process exit |
📷 Screenshot slot — BPMN Designer with
wd_leave_approvalopen, full-node canvas (host-first capture pending).
Designer: how nodes are configured
The graph is stored as designer JSON (nodes + edges + process-level aura policy) and compiled to BPMN 2.0 on publish. Here is how a few key nodes appear in designerJson.nodes.
Rule task — references a rule by ruleCode; factsVars declares which process variables become rule facts:
{
"id": "svc_rule_route",
"type": "rule-task",
"data": {
"label:en": "Routing Rule",
"ruleCode": "wd_leave_routing",
"factsVars": "days,type"
}
}User task — config.assignee declares the assignment strategy (by role here), slaKey links the task to an SLA, and taskActions defines the actions an approver can take:
{
"id": "task_manager_approve",
"type": "userTask",
"data": {
"label:en": "Manager Approve",
"formPageKey": "wd_leave_request_detail",
"slaKey": "wd_manager_approve_sla",
"config": { "assignee": { "type": "role", "roleIds": ["wd_manager"] } },
"taskActions": [
{ "key": "approve", "type": "complete", "resultVariable": "taskResult", "resultValue": "approved" },
{ "key": "reject", "type": "complete", "resultVariable": "taskResult", "resultValue": "rejected", "requireComment": true }
]
}
}Record-update task / notification task — AuraBoot extension nodes on top of standard BPMN, so the flow can write record fields and emit business events without hand-written serviceTask glue:
{
"id": "svc_set_approved",
"type": "record-update-task",
"data": { "modelCode": "wd_leave_request", "recordIdVar": "recordId", "fieldName": "wd_req_status", "fieldValue": "approved" }
}Edges carry condition expressions to branch. The approver-dispatch gateway's two outgoing edges are ${approverRole == 'manager'} and ${approverRole == 'hr'}; the result gateway uses ${taskResult == 'approved'} / ${taskResult == 'rejected'}.
Runtime: Smart Engine
AuraBoot embeds Smart Engine (an AuraBoot-maintained fork of the BPMN engine) as the process runtime. After deploy, instances are triggered by the Command Pipeline — the postActions of wd:submit_leave_request start the process once the state transition succeeds, and write the instance id back to the record field wd_req_process_instance:
{
"code": "wd:submit_leave_request",
"type": "state_transition",
"modelCode": "wd_leave_request",
"stateField": "wd_req_status",
"fromStates": ["draft", "rejected"],
"toState": "submitted",
"postActions": [
{
"type": "start_process",
"processKey": "wd_leave_approval",
"businessKey": "${recordId}",
"variables": { "days": "${payload.wd_req_days}", "type": "${payload.wd_req_type}", "recordId": "${recordId}", "applicantUserId": "${payload.wd_req_applicant}" },
"storeInstanceIdIn": "wd_req_process_instance"
}
]
}Once started, the engine advances the graph: evaluate rule task → gateway picks branch → create the approval task and assign by role → wait for human completion → result gateway → write status → notify → end. The Command Pipeline remains the single source of truth for data changes; Smart Engine only orchestrates who does the next step, and when.
Process definitions and runtime are exposed under /api/bpm/*. Key endpoints:
| Operation | Endpoint |
|---|---|
| Validate process JSON (before deploy) | POST /api/bpm/process-definitions/validate |
| Deploy process | POST /api/bpm/process-definitions/{pid}/deploy |
| Suspend / resume instance | POST /api/bpm/process-definitions/{pid}/suspend …/resume |
| Todo / completed tasks | GET /api/bpm/tasks/todo …/completed |
| Approve / reject | POST /api/bpm/tasks/{taskId}/approve …/reject |
Cancellation runs through the
wd:cancel_leave_requestcommand, whosepostActionsusewithdraw_processto close the running approval task.
Wiring in the rule engine
workflow-demo uses two Drools rules to show the two places a rule engine plugs in.
Pre-flight (before the command) — wd_leave_validation (ruleType: VALIDATION) runs before wd:submit_leave_request starts the process, blocking annual leave with insufficient balance and long sick leave without an attachment:
{
"ruleCode": "wd_leave_validation",
"ruleType": "VALIDATION",
"outputSchema": { "type": "object", "properties": { "valid": { "type": "boolean" }, "reason": { "type": "string" } } },
"ruleContentFile": "rules/wd_leave_validation.drl"
}In-process routing (rule-task) — wd_leave_routing (ruleType: CONDITION) is called by the svc_rule_route node, producing approverRole from the number of days for the downstream exclusive gateway:
rule "route_short_to_manager"
when
$req: Map( ((Number) this["days"]).doubleValue() < 3.0 )
then
((Map) $req.get("_ruleResult")).put("approverRole", "manager");
end
rule "route_long_to_hr"
when
$req: Map( ((Number) this["days"]).doubleValue() >= 3.0 )
then
((Map) $req.get("_ruleResult")).put("approverRole", "hr");
endRules are not compiled into the BPMN — the flow only stores a ruleCode reference, and the engine calls back to the rule service when it reaches the rule task. A rule can be tried independently via POST /api/bpm/rules/{pid}/evaluate, which makes it easy to debug decoupled from the flow.
Wiring in SLA
Each approval task carries an SLA (config/sla.json) to add time accountability: deadline, warning, overdue escalation, suspend policy.
{
"slaKey": "wd_manager_approve_sla",
"name:en": "Manager Approval SLA",
"targetType": "NODE",
"targetKey": "task_manager_approve",
"processKey": "wd_leave_approval",
"deadlineMode": "FIXED",
"deadlineValue": "PT30S",
"warningRules": [ { "beforeSeconds": 10, "eventType": "sla_warning", "notifyTargets": ["assignee"] } ],
"suspendPolicy": "pause",
"escalationTargetType": "role_parent",
"escalationTargetValue": "wd_manager",
"enabled": true
}What the fields mean:
targetType: NODE+targetKey— the SLA binds to a node in the flow (also supportsPROCESS/TASK).deadlineMode: FIXED+deadlineValue— an ISO-8601 duration sets the deadline. The demo usesPT30S(30 seconds) so E2E can observe escalation quickly; production should use a real value likePT24H.warningRules— emit a warning event and notify the listed targets N seconds before the deadline.suspendPolicy: pause— pause the timer while the process is suspended and resume it afterwards, so suspended time is not counted as overdue.escalationTargetType / escalationTargetValue— who the task escalates to after the deadline.
A task's SLA state is visible in the Task Center; the running SLA record updates as the task is claimed, completed, suspended, or resumed.
Run it yourself
workflow-demo is an OSS plugin and is imported by default with the open-source demo environment. To import and seed it manually:
# 1) Import the plugin (config-only + backend jar; build the backend jar first on first run)
aura plugin-import plugins/workflow-demo --conflict-strategy overwrite --yes
# 2) Seed demo data through product APIs (leave balances + requests + task history)
node scripts/seed-workflow-demo.mjsFor the import mechanics (plugin.json / resourceDirs / backend jar) see Config-only Plugins and Plugin Development.
Once running, enter from the Leave Demo sidebar group:
- My Requests (
/p/wd_leave_request) — click "Submit" on a draft row, confirm, and that fireswd:submit_leave_requestand starts the process. - Leave Balances (
/p/wd_leave_balance) — the balance data used by pre-flight validation. - Task Center — find the approval task for the matching
businessKey, click "Approve / Reject" to advance the flow, and watch the SLA state.
📷 Screenshot slot — Task Center approving a
wd_leave_approvaltask + SLA state (host-first capture pending).
Verification checklist
Running this flow end to end, you should be able to verify each of:
- Submitting annual leave that exceeds the remaining balance is blocked by
wd_leave_validation(the process does not start). - Submitting
days < 3routes to the manager;days >= 3routes to HR (rule + gateway take effect). - The approval task appears in the Task Center, assigned by role.
- Not acting before the deadline triggers an SLA warning / escalation.
- "Approve" writes
wd_req_statusback toapprovedand the applicant is notified; "Reject" writesrejected. - The audit trail records process_start + rule / gateway / userTask activity events + the approve operation.