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