Best Practices
This guide provides best practices for designing, implementing, and maintaining workflows.
Workflow Design
Keep States Focused
Each state should represent a single, well-defined stage in your process.
Good: - Draft - Pending Manager Approval - Pending Senior Approval - Approved
Poor: - Processing (too vague) - Waiting (waiting for what?) - Active (what kind of activity?)
Guidelines: - State names should be nouns or adjectives describing the condition - Anyone should understand what the state means - Avoid generic names like “Processing” or “Active” - Use consistent naming conventions
Use Meaningful Transition Names
Transition names should clearly indicate the action or event.
Good: - submit - approve - reject - escalate - timeout
Poor: - next - go - process - do
Guidelines: - Transition names should be verbs describing the action - Match business terminology - Be consistent across workflows - Keep names short but descriptive
Minimize State Count
Fewer states are easier to understand and maintain.
Guidelines: - Combine similar states when possible - Use state data to track variations instead of creating new states - Typical workflow: 5-10 states - If >15 states, consider splitting into multiple workflows or using super states
Example - Too Many States:
Draft → Pending Manager → Manager Approved → Pending Senior →
Senior Approved → Pending Director → Director Approved → Completed
Better - Use Guards:
Draft → Pending Approval → Approved → Completed
Guards determine which approval level based on amount/priority
Design for Auditability
Workflows should provide complete audit trails.
Best Practices: - Use descriptive event names - Store decision rationale in elxPrivate - Capture who, what, when for all actions - Leverage elxHistory for compliance - Add comments in OnTransition chains
Example:
// OnTransition chain for approve
{
"approver": getCurrentUser(),
"approvedAt": new Date().toISOString(),
"approvalReason": formData.reason,
"approvalLevel": "manager",
"delegatedFrom": formData.delegatedFrom || null
}
Handle Error States Explicitly
Don’t rely on implicit error handling.
Best Practices: - Create explicit error/failure states - Add timeout transitions - Handle cancellation explicitly - Provide recovery paths
Example:
Processing → Success
Processing → Failed (with error details)
Processing → TimedOut (after 1 hour)
Processing → Cancelled (user action)
Failed → Retry (with retry count)
Failed → Abandoned (after 3 retries)
Use Super States to Reduce Duplication
When multiple states share transitions, use super states.
Indicators you need super states: - Same transition appears on 3+ states - Common error handling across states - Shared timeout logic - Group of related states
Example:
All processing states can be cancelled
→ Create "Processing" super state
→ Add cancel transition to super state
→ All sub-states inherit cancellation
Security Considerations
Public vs Private Data
Choose carefully what goes in elxPublic vs elxPrivate.
elxPublic (visible to browser): - Display information - Form data - Non-sensitive business data - Status information - Public comments
elxPrivate (server-side only): - Sensitive information (SSN, salary, etc.) - Internal processing data - System-generated values - Approval notes - Audit metadata
Never in elxPublic: - Passwords or credentials - API keys or tokens - Personal identifiable information (PII) unless necessary - Financial account numbers - Internal system identifiers
Role-Based Access Control
Use roles and workgroups to control access.
Best Practices: - Assign workflows to appropriate workgroups - Use roles to control who can approve/reject - Implement guards to check user permissions - Log access attempts
Example Guard Chain:
1. GetCurrentState
2. Transform: Get current user role
3. Conditional: Check if user has required role
- Manager role for amounts < $10,000
- Director role for amounts >= $10,000
4. If unauthorized: Fail guard
5. workflow.GuardEndPoint
Audit Logging
Configure audit logging appropriately.
Configuration:
ambience.modules.workflow.audit {
public: true // Log elxPublic changes
private: false // Don't log elxPrivate (may contain sensitive data)
}
Guidelines: - Enable public logging for compliance - Enable private logging only if necessary - Review logs regularly - Implement log retention policies - Protect audit logs from tampering
Input Validation
Always validate user input before processing.
Best Practices: - Validate in OnExit chain before transition - Check data types and formats - Sanitize string inputs - Validate business rules - Fail transition if validation fails
Example Validation Chain:
1. GetCurrentState
2. Transform: Extract input data
3. Validate: Check required fields present
4. Validate: Check date formats
5. Validate: Check business rules
6. Conditional: If invalid
- Add errors to elxPublic.errors
- Fail chain (blocks transition)
Performance & Scalability
Database Strategy
Choose appropriate database and collection settings.
Best Practices: - Use separate collections for different workflow types - Consider separate databases for high-volume workflows - Implement collection naming conventions - Plan for data growth
Naming Convention:
{workflow-name}-{environment}
Examples:
- leave-requests-prod
- expense-claims-prod
- issue-tracker-dev
Instance Cleanup
Regularly clean up completed instances.
Strategies: - Archive instances to separate collection after completion - Delete instances after retention period - Use ETL chain for automated cleanup - Implement soft delete (mark as archived)
Example Cleanup ETL Chain:
1. workflow.GetAllInstances: workflowId = "leave-request"
2. Filter: Completed more than 90 days ago
3. Transform: Export to archive
4. workflow.CleanInstances: Delete old instances
ETL Chain Optimization
Keep ETL chains efficient.
Best Practices: - Keep OnEntry/OnExit chains lightweight - Move heavy processing to async operations - Cache external data when possible - Use batch operations for multiple instances - Avoid nested loops in chains
Example - Avoid:
For each workflow instance:
For each approval level:
Query external system
Send email
Better:
Batch query external system for all instances
For each workflow instance:
Use cached data
Queue email for batch send
Indexing
Create appropriate database indexes.
Recommended Indexes:
// Index on workflow ID and state for queries
db.leaveRequests.createIndex({ "workflowId": 1, "states.nodeId": 1 })
// Index on user for "my requests" queries
db.leaveRequests.createIndex({ "elxPublic.employeeId": 1 })
// Index on dates for date range queries
db.leaveRequests.createIndex({ "elxPublic.submittedAt": -1 })
// Compound index for common queries
db.leaveRequests.createIndex({
"states.nodeId": 1,
"elxPublic.submittedAt": -1
})
Testing Workflows
Design-Time Testing
Test workflows in the designer.
Process: 1. Create test workflow instance via REST API 2. Send events to progress through states 3. Verify state transitions 4. Check elxPublic and elxPrivate data 5. Review elxHistory for audit trail 6. Test error conditions
Example Test Script:
// Create instance
const instance = await createInstance('leave-request', testData);
// Test submit transition
await sendEvent(instance.id, 'submit');
assert(instance.state === 'PendingApproval');
// Test approval
await sendEvent(instance.id, 'approve', approvalData);
assert(instance.state === 'Approved');
// Verify audit trail
assert(instance.elxHistory.length === 2);
ETL Chain Testing
Test ETL chains independently.
Best Practices: - Test chains in ETL designer first - Use sample data matching workflow structure - Test success and failure paths - Verify guard chains return correct results - Test with edge cases
Guard Testing
Test all guard conditions.
Test Cases: - Condition true → transition fires - Condition false → transition blocked - Edge cases (null values, missing data) - Multiple guards in sequence - State machine guards with different states
Integration Testing
Test complete workflows end-to-end.
Test Scenarios: - Happy path (normal flow) - Error paths (rejections, failures) - Timeout scenarios - Escalation paths - Cancellation - Edge cases
Example Test Plan:
Scenario 1: Normal Approval
1. Create leave request
2. Submit for approval
3. Manager approves
4. Verify approved state
5. Check HR system updated
6. Verify email sent
Scenario 2: Rejection
1. Create leave request
2. Submit for approval
3. Manager rejects
4. Verify rejected state
5. Verify rejection email sent
Scenario 3: Timeout
1. Create leave request
2. Submit for approval
3. Wait 3 days (or simulate)
4. Verify escalation triggered
5. Check escalation email sent
Troubleshooting
Common Issues
Transition Not Firing
Symptoms: Event sent but workflow doesn’t transition
Possible Causes: 1. Event name doesn’t match transition 2. Guard condition failing 3. No matching transition from current state 4. Transition disabled
Debugging: 1. Check current state: GET /api/workflow/instance/{id} 2. Verify event name matches transition exactly (case-sensitive) 3. Check guard chain logs in ETL 4. Review transition configuration in designer 5. Check workflow is enabled
Guard Chain Not Working
Symptoms: Guard always passes or always fails
Possible Causes: 1. Missing workflow.GuardEndPoint step 2. Chain not returning success/failure correctly 3. Wrong chain assigned to transition 4. Chain execution error
Debugging: 1. Verify workflow.GuardEndPoint is present 2. Test chain independently in ETL designer 3. Check ETL logs for errors 4. Verify chain assigned to correct transition 5. Test with known good/bad data
OnEntry Chain Not Executing
Symptoms: State entered but OnEntry chain doesn’t run
Possible Causes: 1. Chain not assigned to state 2. Chain execution error 3. Wrong chainset configured 4. Permission issues
Debugging: 1. Verify chain assigned in state properties 2. Check ETL logs for errors 3. Verify chainset is correct 4. Test chain independently 5. Check user has permission to execute chain
Data Not Updating
Symptoms: State changes but data doesn’t update
Possible Causes: 1. ETL chain not modifying data 2. Wrong field paths 3. Data type mismatch 4. Instance not being saved
Debugging: 1. Check ETL chain logs 2. Verify field paths are correct 3. Check data types match 4. Verify workflow instance saves after transition 5. Test with simple data update
Performance Issues
Symptoms: Slow workflow execution
Possible Causes: 1. Heavy ETL chains 2. External API calls 3. Large data sets 4. Missing indexes 5. Too many state machines
Debugging: 1. Profile ETL chain execution time 2. Identify slow steps 3. Check external API response times 4. Review database query performance 5. Add appropriate indexes
Debugging Tools
View Instance State:
curl -X GET http://localhost:8080/api/workflow/instance/{workflowId}/{instanceId} \
-H "Authorization: Bearer TOKEN"
View Audit Log: - Navigate to Audit Log module - Filter by workflow collection - Review state transitions and data changes
ETL Logs: - Check ETL execution logs - Look for errors and warnings - Review execution times
Workflow History:
// elxHistory shows all transitions
instance.elxHistory.forEach(entry => {
console.log(`${entry.user}: ${entry.transitionEvent}`);
console.log(` ${entry.startState} → ${entry.endState}`);
console.log(` ${entry.ts}`);
});
Best Practices for Debugging
Add Logging: - Log entry/exit of states - Log guard evaluations - Log data transformations - Log external API calls
Use Descriptive Names: - Clear state names - Clear transition names - Clear event names - Clear field names
Document Assumptions: - Document expected data structure - Document guard conditions - Document business rules - Document external dependencies
Version Control: - Export workflows regularly - Track changes - Document modifications - Maintain changelog
Maintenance
Workflow Versioning
Manage workflow changes carefully.
Strategies: 1. Copy and Modify: Create new workflow, migrate instances 2. In-Place Update: Modify existing workflow (risky) 3. Version Field: Add version field to instances
Best Practice: - Test changes in development environment - Plan migration strategy for existing instances - Communicate changes to users - Maintain backward compatibility when possible
Documentation
Document your workflows.
What to Document: - Business purpose - State descriptions - Transition logic - Guard conditions - ETL chain purposes - Data structure - Integration points - Known limitations
Where to Document: - Workflow description field - State/transition labels - ETL chain comments - External documentation - Code comments in guards
Monitoring
Monitor workflow health.
Metrics to Track: - Instance creation rate - Average completion time - Error rate - Timeout rate - Escalation rate - State distribution
Alerts: - High error rate - Excessive timeouts - Stuck instances - Performance degradation
See Also
- Core Concepts - Understanding workflows
- Advanced Features - Super states, guards, etc.
- Configuration - System configuration
- Examples - Real-world examples