Complete Example: Leave Request System
This complete example demonstrates how to build an employee leave request system using forms, workflows, and ETL integration.
System Overview
What it does: - Employees submit leave requests via a form - Requests are routed to managers for approval - Approved requests go to HR for final approval - Email notifications sent at each step - Complete audit trail maintained - Leave balance tracked and updated
Components: - Leave request form (data entry) - Leave approval workflow (state management) - Validation ETL chain (business rules) - Notification ETL chains (emails) - Processing ETL chain (data updates)
Step 1: Create the Form
Form Structure
Leave Request Form
├── root
│ ├── Label: "Leave Request"
│ ├── Validator: leave-request-validation
│ └── Label Mode: Vertical
├── page1 (Main Request)
│ └── column1
│ ├── text-input (employeeName)
│ │ ├── Label: "Employee Name"
│ │ ├── Default Value: ${username}
│ │ ├── Disabled: true
│ │ └── Mandatory: true
│ ├── select (leaveType)
│ │ ├── Label: "Leave Type"
│ │ ├── Choices:
│ │ │ ├── annual: "Annual Leave"
│ │ │ ├── sick: "Sick Leave"
│ │ │ ├── personal: "Personal Leave"
│ │ │ └── unpaid: "Unpaid Leave"
│ │ └── Mandatory: true
│ ├── date-input (startDate)
│ │ ├── Label: "Start Date"
│ │ └── Mandatory: true
│ ├── date-input (endDate)
│ │ ├── Label: "End Date"
│ │ └── Mandatory: true
│ ├── text-area (reason)
│ │ ├── Label: "Reason"
│ │ ├── Rows: 4
│ │ └── Mandatory: true
│ ├── attachments (documents)
│ │ ├── Label: "Supporting Documents"
│ │ └── Mandatory: false
│ └── button-bar
│ └── Submit Button
├── page2 (Manager Approval)
│ └── column2
│ ├── html (requestSummary)
│ │ └── Display request details
│ ├── text-area (managerComments)
│ │ ├── Label: "Manager Comments"
│ │ └── Mandatory: false
│ └── button-bar
│ ├── Approve Button
│ └── Reject Button
├── page3 (HR Approval)
│ └── column3
│ ├── html (requestSummary)
│ │ └── Display request details
│ ├── text-area (hrComments)
│ │ ├── Label: "HR Comments"
│ │ └── Mandatory: false
│ └── button-bar
│ ├── Approve Button
│ └── Reject Button
├── page4 (Status View)
│ └── column4
│ ├── html (statusDisplay)
│ │ └── Show current status
│ ├── history (approvalHistory)
│ │ └── Display workflow history
│ └── button-bar
│ └── Close Button
├── workflow-state
│ ├── Workflow Id: leave-approval-workflow
│ └── Event: Submit
└── hidden (currentState)
└── Value: ${elxPublic.currentState}
Form Designer Steps
- Create the form:
- Go to Forms page
- Click Add
- Name: “Leave Request”
- Select Blank Form
- Add Page 1 (Employee Request):
- Drag Page onto root
- Add Column to page
- Add Text Input: employeeName
- Default Value:
${username} - Disabled: true
- Default Value:
- Add Select: leaveType
- Add choices (annual, sick, personal, unpaid)
- Add Date Input: startDate
- Add Date Input: endDate
- Add Text Area: reason
- Add Attachments: documents
- Add Button Bar with Submit
- Add Page 2 (Manager Approval):
- Drag Page onto root
- Add Column
- Add HTML: requestSummary (display request details)
- Add Text Area: managerComments
- Add Button Bar with Approve/Reject buttons
- Add Page 3 (HR Approval):
- Similar to Page 2
- Add Text Area: hrComments
- Add Button Bar with Approve/Reject buttons
- Add Page 4 (Status View):
- Add Column
- Add HTML: statusDisplay
- Add History component
- Add Button Bar with Close button
- Add Workflow State:
- Drag Workflow State onto root
- Select workflow: leave-approval-workflow
- Event: Submit
- Add Hidden Field:
- Drag Hidden onto root
- Id: currentState
- Value:
${elxPublic.currentState}
Step 2: Create Form Rules
Rule 1: Show Page 1 for New Requests
Rule: Show Employee Request Page
├── Conditions:
│ └── currentState == "" OR currentState == "Draft"
├── Actions:
│ ├── Show: page1
│ ├── Hide: page2
│ ├── Hide: page3
│ └── Hide: page4
└── Enabled: true
Rule 2: Show Page 2 for Manager Approval
Rule: Show Manager Approval Page
├── Conditions:
│ ├── currentState == "Manager Approval"
│ └── ${roles} contains "Manager"
├── Actions:
│ ├── Hide: page1
│ ├── Show: page2
│ ├── Hide: page3
│ └── Hide: page4
└── Enabled: true
Rule 3: Show Page 3 for HR Approval
Rule: Show HR Approval Page
├── Conditions:
│ ├── currentState == "HR Approval"
│ └── ${roles} contains "HR"
├── Actions:
│ ├── Hide: page1
│ ├── Hide: page2
│ ├── Show: page3
│ └── Hide: page4
└── Enabled: true
Rule 4: Show Page 4 for Status View
Rule: Show Status Page
├── Conditions:
│ └── currentState == "Approved" OR currentState == "Rejected"
├── Actions:
│ ├── Hide: page1
│ ├── Hide: page2
│ ├── Hide: page3
│ └── Show: page4
└── Enabled: true
Rule 5: Mandatory Medical Certificate for Sick Leave
Rule: Require Medical Certificate
├── Conditions:
│ └── leaveType == "sick"
├── Actions:
│ └── Make Mandatory: documents
└── Enabled: true
Step 3: Create Validation ETL Chain
Chainset: leave-request-validation
Purpose: Validate leave request before submission
Chain: Validate Leave Request
├── Step 1: Check Date Range
│ ├── Get startDate and endDate
│ ├── Verify endDate > startDate
│ └── If invalid, add validation issue
│
├── Step 2: Check Future Dates
│ ├── Get startDate
│ ├── Verify startDate >= today
│ └── If invalid, add validation issue
│
├── Step 3: Check Leave Balance
│ ├── Get employeeName and leaveType
│ ├── Query leave balance database
│ ├── Calculate requested days
│ ├── Verify balance >= requested days
│ └── If insufficient, add validation issue
│
├── Step 4: Check Blackout Dates
│ ├── Get startDate and endDate
│ ├── Query blackout dates
│ ├── Check for overlap
│ └── If overlap, add validation issue
│
├── Step 5: Check Medical Certificate
│ ├── If leaveType == "sick"
│ ├── Verify documents attached
│ └── If missing, add validation issue
│
└── Step 6: Validation Endpoint
└── Marker step
Validation Issues Format:
{
"validationIssues": [
{
"field": "endDate",
"message": "End date must be after start date"
},
{
"field": "startDate",
"message": "Start date cannot be in the past"
},
{
"field": "leaveType",
"message": "Insufficient leave balance (5 days requested, 3 days available)"
}
]
}
Step 4: Create the Workflow
Workflow: leave-approval-workflow
Leave Approval Workflow
├── State: Draft
│ └── Transition: Submit → Manager Approval
│ ├── OnTransition ETL: calculate-leave-days
│ └── Event: Submit
│
├── State: Manager Approval
│ ├── OnEntry ETL: notify-manager
│ ├── Transition: Approve → HR Approval
│ │ ├── Guard: check-manager-is-approver
│ │ └── Event: Approve
│ └── Transition: Reject → Rejected
│ ├── Guard: check-manager-is-approver
│ └── Event: Reject
│
├── State: HR Approval
│ ├── OnEntry ETL: notify-hr
│ ├── Transition: Approve → Approved
│ │ ├── Guard: check-hr-role
│ │ └── Event: Approve
│ └── Transition: Reject → Rejected
│ ├── Guard: check-hr-role
│ └── Event: Reject
│
├── State: Approved
│ ├── OnEntry ETL: process-approval
│ └── Final state
│
└── State: Rejected
├── OnEntry ETL: process-rejection
└── Final state
Step 5: Create ETL Chains for Workflow
Chain: calculate-leave-days
Trigger: OnTransition from Draft to Manager Approval
Calculate Leave Days
├── Step 1: Get start and end dates from elxPublic
├── Step 2: Calculate business days between dates
├── Step 3: Subtract holidays
├── Step 4: Store result in elxPublic.calculatedDays
└── Step 5: Continue workflow
Chain: notify-manager
Trigger: OnEntry to Manager Approval state
Notify Manager
├── Step 1: Get employee name from elxPublic
├── Step 2: Lookup manager from org chart
│ └── Query: SELECT manager FROM employees WHERE name = ?
├── Step 3: Store manager ID in elxPrivate.managerId
├── Step 4: Get manager email
├── Step 5: Compose email
│ ├── To: manager email
│ ├── Subject: "Leave Request from ${employeeName}"
│ └── Body: Include request details and approval link
├── Step 6: Send email
└── Step 7: Log notification
Chain: check-manager-is-approver
Trigger: Guard for Approve/Reject transitions
Check Manager Authorization
├── Step 1: Get current user ID
├── Step 2: Get manager ID from elxPrivate.managerId
├── Step 3: Compare user ID to manager ID
├── Step 4: Return true if match, false otherwise
└── If false, transition blocked
Chain: notify-hr
Trigger: OnEntry to HR Approval state
Notify HR
├── Step 1: Get request details from elxPublic
├── Step 2: Query HR team members
├── Step 3: For each HR member
│ ├── Compose email
│ └── Send notification
└── Step 4: Log notifications
Chain: check-hr-role
Trigger: Guard for HR Approve/Reject
Check HR Authorization
├── Step 1: Get current user roles
├── Step 2: Check if "HR" role present
├── Step 3: Return true if HR, false otherwise
└── If false, transition blocked
Chain: process-approval
Trigger: OnEntry to Approved state
Process Approval
├── Step 1: Get leave details from elxPublic
├── Step 2: Update leave balance database
│ └── Deduct calculated days from balance
├── Step 3: Create calendar entry
│ ├── Title: "${employeeName} - ${leaveType}"
│ ├── Start: startDate
│ └── End: endDate
├── Step 4: Notify employee
│ ├── Compose approval email
│ └── Send to employee
├── Step 5: Set redirect URL
│ └── elxRedirect: "/dashboard/my-leave"
└── Step 6: Log approval
Chain: process-rejection
Trigger: OnEntry to Rejected state
Process Rejection
├── Step 1: Get rejection details
│ ├── From elxPublic.managerComments or elxPublic.hrComments
│ └── Store reason
├── Step 2: Notify employee
│ ├── Compose rejection email
│ ├── Include rejection reason
│ └── Send to employee
├── Step 3: Set redirect URL
│ └── elxRedirect: "/dashboard/my-leave"
└── Step 4: Log rejection
Step 6: Configure Form Properties
- Root Properties:
- Label: “Leave Request”
- Validator: leave-request-validation
- Label Mode: Vertical
- Scroll To Error: true
- Workflow State Properties:
- Workflow Id: leave-approval-workflow
- Event: Submit
Step 7: Test the System
Test as Employee
- Open the form
- Fill in leave details
- Attach medical certificate (if sick leave)
- Click Submit
- Verify validation works
- Verify workflow instance created
- Verify redirect to status page
Test as Manager
- Receive email notification
- Click link to open form
- See Page 2 (Manager Approval)
- Review request details
- Add comments
- Click Approve or Reject
- Verify transition to next state
Test as HR
- Receive email notification
- Click link to open form
- See Page 3 (HR Approval)
- Review request and manager comments
- Add HR comments
- Click Approve or Reject
- Verify final state reached
Test Status View
- Open approved/rejected request
- See Page 4 (Status View)
- Verify history displays all transitions
- Verify status is clear
- Click Close
Step 8: Query Form Results
ETL Chain: Get Approved Leave Requests
Get Approved Requests
├── Step 1: form.ReadFormResults
│ ├── formId: "leave-request"
│ ├── filter: {"elxPublic.currentState": "Approved"}
│ ├── sort: {"elxPublic.startDate": 1}
│ └── limit: 100
├── Step 2: Extract relevant fields
├── Step 3: Format for display
└── Step 4: Return results
Generate Leave Report
Generate Monthly Leave Report
├── Step 1: form.ReadFormResults
│ ├── formId: "leave-request"
│ └── filter: {
│ "elxPublic.currentState": "Approved",
│ "elxPublic.startDate": {
│ "$gte": "2026-03-01",
│ "$lt": "2026-04-01"
│ }
│ }
├── Step 2: Group by department
├── Step 3: Calculate totals
├── Step 4: Generate report
└── Step 5: Email to management
Complete Data Flow
1. Employee opens form
↓
2. Form loads with Page 1 visible
↓
3. Employee fills details
↓
4. Employee clicks Submit
↓
5. Client validation (mandatory fields)
↓
6. Server validation (ETL chain)
↓
7. Workflow instance created (Draft state)
↓
8. Submit event sent to workflow
↓
9. Transition: Draft → Manager Approval
↓
10. calculate-leave-days ETL runs
↓
11. notify-manager ETL runs
↓
12. Manager receives email
↓
13. Manager opens form (Page 2 visible)
↓
14. Manager clicks Approve
↓
15. check-manager-is-approver guard runs
↓
16. Transition: Manager Approval → HR Approval
↓
17. notify-hr ETL runs
↓
18. HR receives email
↓
19. HR opens form (Page 3 visible)
↓
20. HR clicks Approve
↓
21. check-hr-role guard runs
↓
22. Transition: HR Approval → Approved
↓
23. process-approval ETL runs
↓
24. Leave balance updated
↓
25. Calendar entry created
↓
26. Employee notified
↓
27. Form redirects to dashboard
Enhancements
Add Auto-Approval for Short Leave
Modify workflow to auto-approve leave < 2 days:
State: Draft
├── Transition: Submit → Auto-Approved
│ ├── Guard: check-short-leave (days < 2)
│ └── Event: Submit
└── Transition: Submit → Manager Approval
├── Guard: check-long-leave (days >= 2)
└── Event: Submit
Add Escalation for Overdue Approvals
Add deferred event to Manager Approval state:
State: Manager Approval
├── OnAfter: 2 days
│ └── Send escalation email to manager's manager
└── OnAfter: 4 days
└── Auto-approve and notify
Add Leave Balance Display
Add to form:
Column
├── html (leaveBalance)
│ └── Display: "Available: ${elxPublic.availableLeave} days"
└── Script: Load balance on form load
Summary
This complete example demonstrates: - Multi-page form with conditional display - Workflow integration with state management - ETL validation with business rules - ETL processing at workflow transitions - Email notifications - Guard conditions for authorization - Audit trail with history - Form results querying - Role-based UI with rules
The system provides a complete, production-ready leave request solution with approval workflow, validation, notifications, and reporting.