Complete Examples
This section provides complete, real-world examples of workflow implementations showing design, ETL integration, and REST API usage.
Example 1: Leave Request Approval Workflow
A complete leave request approval system with email notifications, approval rules, and timeout handling.
Business Requirements
- Employees submit leave requests
- Manager approval required for all requests
- Senior manager approval required for > 5 days
- Auto-escalate if no response within 3 days
- Email notifications at each stage
- Audit trail for compliance
Workflow Design
States: 1. Start - Entry point 2. Draft - Employee creating request 3. Pending Manager Approval - Waiting for manager 4. Pending Senior Approval - Waiting for senior manager (>5 days only) 5. Approved - Request approved 6. Rejected - Request rejected 7. Cancelled - Employee cancelled 8. Stop - Exit point
Transitions: - submit - Draft → Pending Manager Approval - approve_manager - Pending Manager Approval → Approved (≤5 days) - approve_manager - Pending Manager Approval → Pending Senior Approval (>5 days) - reject_manager - Pending Manager Approval → Rejected - approve_senior - Pending Senior Approval → Approved - reject_senior - Pending Senior Approval → Rejected - cancel - Draft/Pending → Cancelled - escalate - Pending → Pending (loop for escalation) - close - Approved/Rejected/Cancelled → Stop
State Configuration
Draft State: - OnEntry: None - OnExit: Validate leave request data - OnAfter: None
Pending Manager Approval State: - OnEntry: Send notification to manager - OnExit: None - OnAfter: 3 days → escalate event
Pending Senior Approval State: - OnEntry: Send notification to senior manager - OnExit: None - OnAfter: 2 days → escalate event
Approved State: - OnEntry: - Send approval notification to employee - Update HR system - Set redirect to confirmation page - OnExit: None - OnAfter: None
Rejected State: - OnEntry: - Send rejection notification to employee - Set redirect to rejection page - OnExit: None - OnAfter: None
Transition Configuration
submit Transition: - Event: submit - Guard: None - OnTransition: Calculate leave days and validate dates
approve_manager Transition: - Event: approve - Guard: Check if days ≤ 5 OR user is senior manager - OnTransition: Record approval details
approve_manager (to Senior) Transition: - Event: approve - Guard: Check if days > 5 AND user is manager (not senior) - OnTransition: Record manager pre-approval
reject_manager Transition: - Event: reject - Guard: Check user is manager - OnTransition: Record rejection details
escalate Transition: - Event: escalate - Guard: None - OnTransition: Send escalation email, increment counter
ETL Chains
Chain: ValidateLeaveRequest
Purpose: Validate leave request data before submission
Used in: Draft state OnExit
Steps:
1. GetCurrentState
2. Transform: Extract dates
- startDate from elxPublic.startDate
- endDate from elxPublic.endDate
3. Validate: Check dates
- startDate must be future date
- endDate must be after startDate
- No overlapping leave requests
4. Conditional: If invalid
- Add error to elxPublic.errors
- Fail chain (blocks transition)
5. If valid: Continue
Chain: CalculateLeaveDays
Purpose: Calculate working days between dates
Used in: submit transition OnTransition
Steps:
1. GetCurrentState
2. Transform: Calculate Days
- Get startDate and endDate
- Calculate working days (exclude weekends/holidays)
- Calculate total calendar days
3. workflow.MergeToElxPublic
- Add workingDays field
- Add calendarDays field
Chain: NotifyManager
Purpose: Send email to manager for approval
Used in: Pending Manager Approval OnEntry
Steps:
1. GetCurrentState
2. Transform: Get Manager Email
- Query employee record for manager
- Get manager email address
3. Transform: Format Email
- Subject: "Leave Request Pending Approval"
- Body: Include employee, dates, days, reason
- Include approval/reject links
4. SendEmail
- To: manager email
- Include HTML formatted body
5. workflow.AddToElxPrivate
- field: "managerNotified"
- value: current timestamp
Chain: CheckApprovalAuthority
Purpose: Verify approver has authority
Used in: approve_manager transition Guard
Steps:
1. GetCurrentState
2. Transform: Get Leave Days
- Extract workingDays from elxPublic
3. Transform: Get User Role
- Get current user from context
- Query user roles
4. Conditional: Check Authority
- If days <= 5 AND user is manager: Success
- If days > 5 AND user is senior manager: Success
- Else: Fail
5. workflow.GuardEndPoint
Chain: UpdateHRSystem
Purpose: Update external HR system with approved leave
Used in: Approved state OnEntry
Steps:
1. GetCurrentState
2. Transform: Prepare HR Data
- Extract employee ID
- Extract leave dates
- Extract leave type
3. HTTP Request: POST to HR API
- Endpoint: /api/leave/approve
- Body: Leave details
- Auth: Service account token
4. Conditional: Check Response
- If success: Continue
- If failure: Log error, notify admin
5. workflow.MergeToElxPrivate
- Add hrConfirmationNumber
- Add hrSyncTimestamp
6. workflow.SetElxRedirect
- redirectUrl: "/leave-requests/confirmation"
Chain: SendEscalation
Purpose: Send escalation email
Used in: escalate transition OnTransition
Steps:
1. GetCurrentState
2. Transform: Get Escalation Count
- Get current count from elxPrivate.escalationCount
- Increment by 1
3. Transform: Get Email Recipients
- If count = 1: Manager + Senior Manager
- If count = 2: Senior Manager + Director
- If count >= 3: Director + HR
4. Transform: Format Escalation Email
- Subject: "ESCALATION: Leave Request Overdue"
- Body: Include all details + overdue duration
5. SendEmail
- To: Recipients based on count
- Mark as high priority
6. workflow.MergeToElxPrivate
- Update escalationCount
- Add escalationTimestamp
7. Conditional: Auto-Action
- If count >= 3: Auto-approve or escalate to HR
REST API Integration
Create Leave Request (Web Form):
async function submitLeaveRequest(formData) {
const response = await fetch('/api/workflow/create', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${getToken()}`
},
body: JSON.stringify({
workflowId: 'leave-request',
data: {
elxPublic: {
employeeId: getCurrentUser().id,
employeeName: getCurrentUser().name,
employeeEmail: getCurrentUser().email,
leaveType: formData.leaveType,
startDate: formData.startDate,
endDate: formData.endDate,
reason: formData.reason,
status: 'Draft'
}
}
})
});
const result = await response.json();
// Now submit the request
await sendEvent(result.instanceId, 'submit');
}
async function sendEvent(instanceId, eventName, data = {}) {
const response = await fetch('/api/workflow/event', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${getToken()}`
},
body: JSON.stringify({
workflowId: 'leave-request',
instanceId: instanceId,
event: {
name: eventName,
data: data
}
})
});
return await response.json();
}
Approve/Reject Actions:
async function approveLeaveRequest(instanceId, comments) {
return await sendEvent(instanceId, 'approve', {
approver: getCurrentUser().id,
approverName: getCurrentUser().name,
approvedAt: new Date().toISOString(),
comments: comments
});
}
async function rejectLeaveRequest(instanceId, reason) {
return await sendEvent(instanceId, 'reject', {
rejectedBy: getCurrentUser().id,
rejectedByName: getCurrentUser().name,
rejectedAt: new Date().toISOString(),
reason: reason
});
}
Manager Dashboard:
async function loadPendingApprovals() {
const response = await fetch(
'/api/workflow/instances/leave-request',
{
headers: {
'Authorization': `Bearer ${getToken()}`
}
}
);
const result = await response.json();
// Filter for pending manager approvals
const pending = result.instances.filter(instance => {
const state = instance.states[0].nodeId;
return state === 'PendingManagerApproval' ||
state === 'PendingSeniorApproval';
});
// Sort by submission date
pending.sort((a, b) =>
new Date(a.elxPublic.submittedAt) - new Date(b.elxPublic.submittedAt)
);
return pending;
}
Data Structure
elxPublic (visible to user):
{
"employeeId": "EMP001",
"employeeName": "Jane Doe",
"employeeEmail": "jane.doe@company.com",
"leaveType": "Annual",
"startDate": "2026-03-01",
"endDate": "2026-03-07",
"workingDays": 5,
"calendarDays": 7,
"reason": "Family vacation",
"status": "Approved",
"submittedAt": "2026-02-28T09:00:00Z",
"approvedAt": "2026-02-28T10:30:00Z",
"approvedBy": "Manager Smith"
}
elxPrivate (server-side only):
{
"managerId": "MGR001",
"managerEmail": "manager.smith@company.com",
"managerNotified": "2026-02-28T09:01:00Z",
"escalationCount": 0,
"hrConfirmationNumber": "HR-2026-001234",
"hrSyncTimestamp": "2026-02-28T10:31:00Z",
"approvalNotes": "Standard approval, no issues",
"budgetImpact": 2500.00
}
Complete Workflow JSON
{
"_id": "leave-request",
"name": "Leave Request",
"owner": "admin",
"database": "main",
"collection": "leaveRequests",
"chainsetId": "leave-request-chains",
"stateMachines": [
{
"id": "main",
"name": "Leave Request Flow",
"initZoom": 100,
"graph": {
"nodes": [
{
"id": "Start",
"label": "Start",
"type": "start"
},
{
"id": "Draft",
"label": "Draft",
"onEntry": null,
"onExit": "ValidateLeaveRequest",
"onAfter": null
},
{
"id": "PendingManagerApproval",
"label": "Pending Manager Approval",
"onEntry": "NotifyManager",
"onExit": null,
"onAfter": {
"units": "Days",
"time": 3,
"event": "escalate"
}
},
{
"id": "PendingSeniorApproval",
"label": "Pending Senior Approval",
"onEntry": "NotifySeniorManager",
"onExit": null,
"onAfter": {
"units": "Days",
"time": 2,
"event": "escalate"
}
},
{
"id": "Approved",
"label": "Approved",
"onEntry": "ApprovalActions",
"onExit": null,
"onAfter": null
},
{
"id": "Rejected",
"label": "Rejected",
"onEntry": "RejectionActions",
"onExit": null,
"onAfter": null
},
{
"id": "Stop",
"label": "Stop",
"type": "stop"
}
],
"edges": [
{
"from": "Start",
"to": "Draft",
"label": "create",
"event": "",
"guard": null,
"onTransition": null
},
{
"from": "Draft",
"to": "PendingManagerApproval",
"label": "submit",
"event": "submit",
"guard": null,
"onTransition": "CalculateLeaveDays"
},
{
"from": "PendingManagerApproval",
"to": "Approved",
"label": "approve_manager",
"event": "approve",
"guard": "CheckApprovalAuthority",
"onTransition": "RecordApproval"
},
{
"from": "PendingManagerApproval",
"to": "PendingSeniorApproval",
"label": "escalate_to_senior",
"event": "approve",
"guard": "RequiresSeniorApproval",
"onTransition": "RecordManagerPreApproval"
},
{
"from": "PendingManagerApproval",
"to": "Rejected",
"label": "reject_manager",
"event": "reject",
"guard": null,
"onTransition": "RecordRejection"
},
{
"from": "PendingSeniorApproval",
"to": "Approved",
"label": "approve_senior",
"event": "approve",
"guard": null,
"onTransition": "RecordApproval"
},
{
"from": "PendingSeniorApproval",
"to": "Rejected",
"label": "reject_senior",
"event": "reject",
"guard": null,
"onTransition": "RecordRejection"
},
{
"from": "PendingManagerApproval",
"to": "PendingManagerApproval",
"label": "escalate",
"event": "escalate",
"guard": null,
"onTransition": "SendEscalation"
},
{
"from": "Approved",
"to": "Stop",
"label": "close",
"event": "",
"guard": null,
"onTransition": null
},
{
"from": "Rejected",
"to": "Stop",
"label": "close",
"event": "",
"guard": null,
"onTransition": null
}
]
}
}
]
}
Example 2: Issue Tracking System
A complete issue tracking workflow with SLA monitoring using multiple state machines.
Business Requirements
- Track issues from creation to resolution
- Support assignment, reassignment, and escalation
- Monitor SLA compliance
- Allow reopening of closed issues
- Maintain complete audit trail
Workflow Design
This workflow uses two state machines: 1. Issue Lifecycle - Main issue states 2. SLA Tracker - Parallel SLA monitoring
State Machine 1: Issue Lifecycle
States: - Start - New - Open - In Progress - Resolved - Closed - Stop
Transitions: - create - Start → New - assign - New → Open - start_work - Open → In Progress - reassign - Open → Open (loop) - resolve - In Progress → Resolved - reopen - Resolved → Open - close - Resolved → Closed - reopen_closed - Closed → Open - archive - Closed → Stop
State Machine 2: SLA Tracker
States: - Start - On Time - Warning - Overdue - Stop
Transitions: - start_tracking - Start → On Time - warn - On Time → Warning (after 80% of SLA time) - overdue - Warning → Overdue (after 100% of SLA time) - complete - Any → Stop (when issue closed)
State Configuration
Issue Lifecycle - In Progress State: - OnEntry: Notify assignee, start timer - OnExit: Calculate time spent - OnAfter: 24 hours → check_progress event
SLA Tracker - Warning State: - OnEntry: Send warning email to assignee and manager - OnExit: None - OnAfter: Remaining SLA time → overdue event
SLA Tracker - Overdue State: - OnEntry: Send escalation email, create escalation ticket - OnExit: None - OnAfter: None
Guard Example: Prevent Closing Without Resolution
Guard Chain for “close” Transition:
1. GetCurrentState
2. workflow.LookupStates
- Check if in "Resolved" state
3. Conditional
- If in Resolved: Success
- Else: Fail with message "Must resolve before closing"
4. workflow.GuardEndPoint
Multiple State Machine Coordination
Guard for Issue Lifecycle using SLA State:
Purpose: Only allow certain actions if SLA is not overdue
Guard Type: State Machine Guard
- State Machine: SLA Tracker
- State: Not "Overdue"
- Action: If overdue, require manager approval
REST API Usage
Create Issue:
const result = await fetch('/api/workflow/create', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify({
workflowId: 'issue-tracker',
data: {
elxPublic: {
title: 'Login page not loading',
description: 'Users unable to access login page',
priority: 'High',
category: 'Bug',
reporter: 'john.doe',
reportedAt: new Date().toISOString()
},
elxPrivate: {
slaHours: 24, // High priority = 24 hour SLA
slaDeadline: calculateDeadline(24)
}
}
})
});
Query Overdue Issues:
const response = await fetch(
'/api/workflow/instances/issue-tracker',
{
headers: {
'Authorization': `Bearer ${token}`
}
}
);
const result = await response.json();
// Filter for overdue issues
const overdue = result.instances.filter(instance => {
// Check SLA Tracker state machine
const slaState = instance.states.find(s =>
s.stateMachineId === 'sla-tracker'
);
return slaState && slaState.nodeId === 'Overdue';
});
Example 3: Document Approval with Parallel Reviews
A document approval workflow where multiple reviewers must approve in parallel.
Business Requirements
- Multiple reviewers approve simultaneously
- All reviewers must approve before proceeding
- Any reviewer can reject
- Track individual review status
- Support revision and resubmission
Implementation Strategy
Use super states to model parallel reviews:
States: - Start - Draft - Under Review (Super State) - Review 1 (sub-state) - Review 2 (sub-state) - Review 3 (sub-state) - Approved - Rejected - Stop
Logic: - When entering “Under Review”, all sub-states become active - Each reviewer sends approve/reject event - Use guard to check if all reviews complete - Transition to Approved only when all approve - Transition to Rejected if any reject
ETL Chain: Check All Reviews Complete
Purpose: Guard to check if all reviewers have responded
Used in: Transition to Approved
Steps:
1. GetCurrentState
2. Transform: Extract Review Status
- Get review1Status from elxPrivate
- Get review2Status from elxPrivate
- Get review3Status from elxPrivate
3. Conditional: Check All Approved
- If all = "approved": Success
- If any = "rejected": Fail
- If any = "pending": Fail
4. workflow.GuardEndPoint
This pattern allows flexible parallel approval workflows.
See Also
- Core Concepts - Understanding workflows
- REST API - API reference
- ETL Integration - ETL step reference
- Advanced Features - Super states, history states