A powerful Node.js library for building and executing configurable workflows with validation and task execution capabilities. This library provides a flexible way to intercept method calls, validate inputs, and execute ordered tasks based on configuration.
- 🔄 Method Interception: Automatically intercept and process method calls using decorators
- ✅ Validation Engine: Support for multiple validation types with configurable rules
- 🚀 Task Execution: Execute ordered tasks (currently API calls, extensible for other types)
- 📊 MongoDB Integration: Persistent storage for workflows and execution logs
- 🔁 Retry Mechanism: Built-in support for task retries and timeouts
- 📝 Comprehensive Logging: Detailed execution logs with MongoDB integration
npm install @dynamatix/cat-decision-engine
- Decorate your method:
import { WorkflowMethod } from '@dynamatix/cat-decision-engine';
class UserService {
@WorkflowMethod()
async createUser(userData: any) {
// Your business logic
}
}
- Configure your workflow:
{
"id": "user-creation-workflow",
"name": "User Creation Workflow",
"trigger": "UserService.createUser",
"validations": [
{
"id": "email-validation",
"name": "Email Format Check",
"condition": "data.email.includes('@')",
"message": "Invalid email format",
"onFail": "stop"
}
],
"tasks": [
{
"id": "notify-admin",
"type": "api_call",
"config": {
"url": "https://api.example.com/notify",
"method": "POST",
"body": {
"email": "{{data.email}}"
}
}
}
]
}
interface Workflow {
id: string;
name: string;
trigger: string;
validations: ValidationRule[];
tasks: Task[];
}
- Basic:
ClassName.methodName
- With Entity:
ClassName.methodName.entityType
- Field Conditions
{
"id": "age-check",
"name": "Age Validation",
"condition": "data.age >= 18",
"message": "User must be 18 or older",
"onFail": "stop"
}
- Regex Matching
{
"id": "phone-format",
"name": "Phone Number Format",
"condition": "/^\\+?[1-9]\\d{1,14}$/.test(data.phone)",
"message": "Invalid phone number format",
"onFail": "stop"
}
-
stop
: Halt workflow execution -
continue
: Proceed despite failure -
retry
: Attempt validation again -
fallback
: Execute alternative logic
Note: The validation engine currently evaluates conditions using JavaScript expressions. While the system supports various validation types in its architecture (FIELD_CONDITION, REGEX_MATCH, CUSTOM_FUNCTION, COMPOSITE, EXTERNAL_API), only field conditions and regex matching are fully implemented in the current version. Additional validation types are planned for future releases.
Tasks in a workflow can access results from previous tasks. This is particularly useful for building complex workflows where each task builds upon the results of previous tasks.
{
"id": "payment-processing-workflow",
"name": "Payment Processing Workflow",
"trigger": "PaymentService.processPayment",
"tasks": [
{
"id": "calculatefee",
"type": "api_call",
"order": 1,
"config": {
"url": "https://api.example.com/calculate-fee",
"method": "GET"
}
},
{
"id": "processpayment",
"type": "api_call",
"order": 2,
"config": {
"url": "https://api.example.com/process-payment",
"method": "POST",
"body": {
"amount": "{{data.initialAmount}}",
"fee": "{{calculatefee.output.data.fee}}",
"totalAmount": "{{calculatefee.output.data.fee + data.initialAmount}}"
}
}
}
]
}
In this example:
- The first task (
calculatefee
) calculates a fee for the payment - The second task (
processpayment
) uses the fee from the first task to calculate the total amount - Task results are automatically available in the context using the task ID as the key
- You can access task results using the format
{{taskId.output.data.fieldName}}
{
"id": "api-task",
"type": "api_call",
"config": {
"url": "https://api.example.com/endpoint",
"method": "POST",
"headers": {
"Authorization": "Bearer {{context.token}}"
},
"body": {
"userId": "{{data.id}}",
"action": "create"
},
"timeout": 5000,
"retries": 3
}
}
Tasks have access to:
- Original method input data
- Previous task results
- Workflow context
- Execution metadata
interface WorkflowLog {
executionId: string;
workflowId: string;
workflowName: string;
status: 'started' | 'completed' | 'failed';
validationResults: ValidationResult[];
taskResults: TaskResult[];
error?: any;
timestamp: Date;
}
// Example: Find failed executions
const failedExecutions = await workflowStore.findLogs({
status: 'failed',
startDate: new Date('2024-01-01'),
endDate: new Date()
});
The workflow engine can be used to handle dynamic form submissions with different entity types. This is particularly useful for applications that need to process various types of forms (loans, insurance, mortgages, etc.) with different validation rules and workflows.
import { WorkflowMethod } from '@your-org/workflow-engine';
export class DynamicFormUseCase {
constructor(
private readonly entityType: string // e.g., 'loan', 'insurance', 'mortgage'
) { }
@WorkflowMethod()
async processForm(data: any) {
// The decorator will:
// 1. Get the workflow from MongoDB using the class, method name, and entityType as trigger
// 2. Execute the workflow (validations and tasks)
// 3. Only call this method if the workflow succeeds
return {
success: true,
data: {
...data,
entityType: this.entityType,
status: 'PROCESSED',
message: `${this.entityType} form processed successfully`
}
};
}
}
export async function handleFormSubmission(entityType: string, formData: any) {
try {
// Create form handler for the specific entity type
const formHandler = new DynamicFormUseCase(entityType);
// Process the form
const result = await formHandler.processForm(formData);
return {
success: true,
data: result.data
};
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : 'Unknown error'
};
}
}
- Loan Application
const loanData = {
applicantName: 'John Doe',
loanAmount: 50000,
employmentStatus: 'employed',
annualIncome: 75000,
email: 'john.doe@example.com'
};
const result = await handleFormSubmission('loan', loanData);
- Insurance Application
const insuranceData = {
policyHolder: 'Jane Smith',
coverageType: 'health',
age: 35,
preExistingConditions: false,
email: 'jane.smith@example.com'
};
const result = await handleFormSubmission('insurance', insuranceData);
- Mortgage Application
const mortgageData = {
propertyValue: 300000,
downPayment: 60000,
creditScore: 720,
employmentHistory: '5 years',
email: 'mortgage.buyer@example.com'
};
const result = await handleFormSubmission('mortgage', mortgageData);
{
"id": "loan-application-workflow",
"name": "Loan Application Processing",
"trigger": "DynamicFormUseCase.processForm.loan",
"validations": [
{
"id": "loan-amount",
"name": "Minimum Loan Amount",
"condition": "data.loanAmount >= 10000",
"message": "Loan amount must be at least $10,000",
"onFail": "stop"
},
{
"id": "income-verification",
"name": "Income Verification",
"condition": "data.annualIncome >= 50000",
"message": "Annual income must be at least $50,000",
"onFail": "stop"
}
],
"tasks": [
{
"id": "notify-loan-officer",
"type": "api_call",
"config": {
"url": "https://api.example.com/notify-loan-officer",
"method": "POST",
"body": {
"applicantName": "{{data.applicantName}}",
"loanAmount": "{{data.loanAmount}}"
}
}
}
]
}
Note: The workflow trigger includes the entity type (
DynamicFormUseCase.processForm.loan
), allowing different workflows for different form types.
- Task Types: Currently limited to API calls
- Parallel Execution: No built-in support for parallel task execution
- Validation Security: Conditions are evaluated using Function constructor
- Configuration: No UI for workflow configuration (script-based only)
- Error Recovery: Limited support for complex error recovery scenarios
-
Additional Task Types
- Stored Procedure calls
- Email sending
- File operations
- Database operations
-
Enhanced Features
- Parallel task execution
- Workflow configuration UI
- Enhanced validation engine
- Workflow versioning
- Workflow templates
- Real-time monitoring dashboard
-
Security Enhancements
- Secure validation condition evaluation
- Role-based access control
- Audit trail improvements
sequenceDiagram
participant Client
participant Decorator
participant Engine
participant Validator
participant TaskExecutor
participant MongoDB
Client->>Decorator: Call @WorkflowMethod
Decorator->>Engine: Find Workflow
Engine->>MongoDB: Query Workflow Config
MongoDB-->>Engine: Return Config
Engine->>Validator: Execute Validations
Validator->>MongoDB: Log Validation Results
alt Validation Success
Engine->>TaskExecutor: Execute Tasks
loop For Each Task
TaskExecutor->>TaskExecutor: Create Context with Previous Results
TaskExecutor->>MongoDB: Log Task Results
TaskExecutor-->>Engine: Task Results
end
Engine-->>Decorator: Workflow Result
Decorator-->>Client: Original Method Result
else Validation Failure
Validator-->>Engine: Validation Error
Engine-->>Decorator: Workflow Error
Decorator-->>Client: Error Response
end
erDiagram
WORKFLOW {
ObjectId _id
string id
string name
string trigger
array validations
array tasks
date createdAt
date updatedAt
}
erDiagram
WORKFLOW_LOG {
ObjectId _id
string level
string message
object metadata
date timestamp
string workflowId
string workflowName
string executionId
string status
number duration
array validationResults
array taskResults
string error
}
-
workflow_logs
:{ timestamp: -1 }
{ workflowId: 1 }
{ level: 1 }
{ executionId: 1 }