@kodeme-io/next-core-workflow
v0.8.4
Published
Workflow, approval flows, and BPM for Next.js applications
Downloads
29
Maintainers
Readme
@kodeme-io/next-core-workflow
Workflow, approval flows, and BPM (Business Process Management) for Next.js applications with TypeScript support and real-time updates.
🚀 Features
- 🔄 Workflow Engine - Powerful workflow orchestration and state management
- ✅ Approval Flows - Multi-step approval processes with role-based assignments
- 🎯 Conditional Logic - Dynamic routing based on business rules
- 👥 Parallel Processing - Handle multiple approval paths simultaneously
- 📝 Activity Tracking - Complete audit trail of all workflow actions
- ⏰ SLA Management - Track deadlines and escalation rules
- 📊 Analytics - Workflow performance metrics and reporting
- 🔧 TypeScript Native - Full type safety and IntelliSense support
- 📱 Real-time Updates - Live workflow status updates
📦 Installation
npm install @kodeme-io/next-core-workflow
# or
yarn add @kodeme-io/next-core-workflow
# or
pnpm add @kodeme-io/next-core-workflow🎯 Quick Start
Basic Workflow Example
'use client'
import {
WorkflowEngine,
WorkflowProvider,
WorkflowViewer,
ApprovalActions,
WorkflowDefinition,
type ApprovalAction
} from '@kodeme-io/next-core-workflow'
const expenseApprovalWorkflow: WorkflowDefinition = {
id: 'expense-approval',
name: 'Expense Approval Workflow',
description: 'Process for approving employee expense reports',
steps: [
{
id: 'submission',
name: 'Employee Submission',
type: 'action',
status: 'completed',
completedAt: new Date(),
comments: 'Expense report submitted'
},
{
id: 'manager-approval',
name: 'Manager Approval',
type: 'approval',
assignee: '[email protected]',
status: 'pending'
},
{
id: 'finance-review',
name: 'Finance Review',
type: 'review',
assignee: '[email protected]',
status: 'draft'
}
],
currentStep: 1,
status: 'pending',
createdAt: new Date(),
updatedAt: new Date(),
createdBy: '[email protected]'
}
export default function ExpenseApprovalPage() {
const engine = new WorkflowEngine()
const [workflow, setWorkflow] = useState(expenseApprovalWorkflow)
const handleApproval = async (action: ApprovalAction) => {
try {
const result = await engine.processAction(workflow.id, action)
if (result.success) {
setWorkflow(result.workflow)
}
} catch (error) {
console.error('Approval action failed:', error)
}
}
return (
<WorkflowProvider engine={engine} workflowId={workflow.id}>
<div className="max-w-4xl mx-auto p-6">
<h1 className="text-2xl font-bold mb-6">Expense Approval</h1>
<WorkflowViewer workflow={workflow} />
<div className="mt-6">
<ApprovalActions
step={workflow.steps[workflow.currentStep!]}
onAction={handleApproval}
currentUserId="[email protected]"
/>
</div>
</div>
</WorkflowProvider>
)
}🎭 Real-World Use Cases
1. Employee Onboarding Workflow
const onboardingWorkflow: WorkflowDefinition = {
id: 'employee-onboarding',
name: 'Employee Onboarding',
description: 'Complete process for onboarding new employees',
steps: [
{
id: 'offer-acceptance',
name: 'Offer Acceptance',
type: 'action',
status: 'completed',
completedAt: new Date(),
comments: 'Offer accepted by candidate'
},
{
id: 'hr-paperwork',
name: 'HR Documentation',
type: 'approval',
assignee: '[email protected]',
status: 'pending'
},
{
id: 'it-setup',
name: 'IT Account Setup',
type: 'action',
assignee: '[email protected]',
status: 'draft'
},
{
id: 'facility-access',
name: 'Facility Access',
type: 'approval',
assignee: '[email protected]',
status: 'draft'
},
{
id: 'orientation',
name: 'Orientation Session',
type: 'review',
assignee: '[email protected]',
status: 'draft'
}
],
currentStep: 1,
status: 'pending',
createdAt: new Date(),
updatedAt: new Date(),
createdBy: '[email protected]'
}2. Purchase Order Approval
const purchaseOrderWorkflow: WorkflowDefinition = {
id: 'po-approval',
name: 'Purchase Order Approval',
description: 'Multi-level approval for purchase orders',
steps: [
{
id: 'po-creation',
name: 'Purchase Order Creation',
type: 'action',
status: 'completed',
completedAt: new Date(),
comments: 'PO created for office supplies'
},
{
id: 'manager-approval',
name: 'Manager Approval',
type: 'approval',
assignee: '[email protected]',
status: 'pending'
},
{
id: 'finance-approval',
name: 'Finance Approval',
type: 'approval',
assignee: '[email protected]',
status: 'draft'
},
{
id: 'procurement-review',
name: 'Procurement Review',
type: 'review',
assignee: '[email protected]',
status: 'draft'
}
],
currentStep: 1,
status: 'pending',
createdAt: new Date(),
updatedAt: new Date(),
createdBy: '[email protected]'
}
// Enhanced with amount-based conditional routing
const createPurchaseOrderWorkflow = (amount: number): WorkflowDefinition => {
const steps = [
{
id: 'po-creation',
name: 'Purchase Order Creation',
type: 'action' as const,
status: 'completed' as const,
completedAt: new Date(),
comments: `PO created for amount: ${amount}`
}
]
// Add approval levels based on amount
if (amount > 10000) {
steps.push({
id: 'manager-approval',
name: 'Manager Approval',
type: 'approval' as const,
assignee: '[email protected]',
status: 'pending' as const
})
}
if (amount > 50000) {
steps.push({
id: 'director-approval',
name: 'Director Approval',
type: 'approval' as const,
assignee: '[email protected]',
status: 'draft' as const
})
}
if (amount > 100000) {
steps.push({
id: 'executive-approval',
name: 'Executive Approval',
type: 'approval' as const,
assignee: '[email protected]',
status: 'draft' as const
})
}
steps.push({
id: 'procurement-review',
name: 'Procurement Review',
type: 'review' as const,
assignee: '[email protected]',
status: 'draft' as const
})
return {
id: `po-approval-${Date.now()}`,
name: 'Purchase Order Approval',
description: `Approval for purchase order of ${amount}`,
steps,
currentStep: 1,
status: 'pending' as const,
createdAt: new Date(),
updatedAt: new Date(),
createdBy: '[email protected]'
}
}3. Content Publishing Workflow
const contentPublishingWorkflow: WorkflowDefinition = {
id: 'content-publishing',
name: 'Content Publishing',
description: 'Blog post and article publishing workflow',
steps: [
{
id: 'content-creation',
name: 'Content Creation',
type: 'action',
status: 'completed',
completedAt: new Date(),
comments: 'Blog post draft completed'
},
{
id: 'editorial-review',
name: 'Editorial Review',
type: 'review',
assignee: '[email protected]',
status: 'pending'
},
{
id: 'legal-review',
name: 'Legal Review',
type: 'approval',
assignee: '[email protected]',
status: 'draft'
},
{
id: 'final-approval',
name: 'Final Approval',
type: 'approval',
assignee: '[email protected]',
status: 'draft'
},
{
id: 'publishing',
name: 'Publishing',
type: 'action',
assignee: '[email protected]',
status: 'draft'
}
],
currentStep: 1,
status: 'pending',
createdAt: new Date(),
updatedAt: new Date(),
createdBy: '[email protected]'
}4. IT Service Request Workflow
const itServiceRequestWorkflow: WorkflowDefinition = {
id: 'it-service-request',
name: 'IT Service Request',
description: 'IT support and service request workflow',
steps: [
{
id: 'request-submission',
name: 'Request Submission',
type: 'action',
status: 'completed',
completedAt: new Date(),
comments: 'Laptop replacement requested'
},
{
id: 'it-triage',
name: 'IT Triage',
type: 'review',
assignee: '[email protected]',
status: 'pending'
},
{
id: 'approval-required',
name: 'Manager Approval',
type: 'approval',
assignee: '[email protected]',
status: 'draft'
},
{
id: 'procurement',
name: 'Procurement',
type: 'action',
assignee: '[email protected]',
status: 'draft'
},
{
id: 'delivery-setup',
name: 'Delivery and Setup',
type: 'action',
assignee: '[email protected]',
status: 'draft'
}
],
currentStep: 1,
status: 'pending',
createdAt: new Date(),
updatedAt: new Date(),
createdBy: '[email protected]'
}📚 Core Concepts
Workflow Definition Structure
interface WorkflowDefinition {
id: string // Unique workflow identifier
name: string // Workflow name
description?: string // Optional description
steps: WorkflowStep[] // Workflow steps
currentStep?: number // Current active step index
status: WorkflowStatus // Overall workflow status
createdAt: Date // Creation timestamp
updatedAt: Date // Last update timestamp
createdBy: string // Workflow creator
}Workflow Step Types
action- User-performed actions (form submissions, uploads)approval- Single or multi-user approval stepsreview- Review steps without explicit approve/rejectcondition- Conditional branching logic
Workflow Status
draft- Workflow is being preparedpending- Workflow is active and awaiting actionapproved- Workflow completed successfullyrejected- Workflow was rejectedcancelled- Workflow was cancelled
Step Structure
interface WorkflowStep {
id: string // Unique step identifier
name: string // Step display name
type: StepType // Step type (action, approval, review, condition)
assignee?: string | string[] // Assigned user(s) or role(s)
status: WorkflowStatus // Step status
completedAt?: Date // Completion timestamp
comments?: string // Step comments/notes
}🎨 Components
WorkflowEngine
Core engine for managing workflow instances:
const engine = new WorkflowEngine({
notificationHandler: (notification) => {
// Handle workflow notifications
console.log('Workflow notification:', notification)
}
})
// Create new workflow instance
const workflow = engine.createWorkflow({
definition: workflowDefinition,
initiator: '[email protected]',
context: { amount: 1000, department: 'sales' }
})
// Process workflow actions
const result = await engine.processAction(workflow.id, {
stepId: 'manager-approval',
action: 'approve',
comments: 'Approved within budget',
userId: '[email protected]',
timestamp: new Date()
})WorkflowViewer
Visual component for displaying workflow status:
<WorkflowViewer
workflow={workflow}
showSteps={true}
showTimeline={true}
compact={false}
className="custom-workflow-viewer"
/>ApprovalActions
Interactive component for handling approvals:
<ApprovalActions
step={currentStep}
onAction={handleApproval}
currentUserId="[email protected]"
showComments={true}
requiredComments={false}
className="approval-actions"
/>WorkflowHistory
Component for displaying workflow activity:
<WorkflowHistory
history={workflowHistory}
showUser={true}
showTimestamp={true}
groupByDate={false}
className="workflow-history"
/>🔄 Advanced Workflow Patterns
Conditional Workflows
const conditionalWorkflow: WorkflowDefinition = {
id: 'conditional-approval',
name: 'Conditional Approval Workflow',
steps: [
{
id: 'initial-review',
name: 'Initial Review',
type: 'condition',
status: 'pending'
},
{
id: 'high-value-approval',
name: 'High Value Approval',
type: 'approval',
assignee: '[email protected]',
status: 'draft'
},
{
id: 'standard-approval',
name: 'Standard Approval',
type: 'approval',
assignee: '[email protected]',
status: 'draft'
}
],
currentStep: 0,
status: 'pending',
createdAt: new Date(),
updatedAt: new Date(),
createdBy: '[email protected]'
}
// Usage with context for conditional routing
const workflow = engine.createWorkflow({
definition: conditionalWorkflow,
initiator: '[email protected]',
context: { amount: 5000, department: 'sales' }
})Parallel Approvals
const parallelWorkflow: WorkflowDefinition = {
id: 'parallel-approval',
name: 'Parallel Approval Workflow',
steps: [
{
id: 'submission',
name: 'Document Submission',
type: 'action',
status: 'completed',
completedAt: new Date()
},
{
id: 'hr-approval',
name: 'HR Approval',
type: 'approval',
assignee: '[email protected]',
status: 'pending'
},
{
id: 'finance-approval',
name: 'Finance Approval',
type: 'approval',
assignee: '[email protected]',
status: 'pending'
},
{
id: 'final-approval',
name: 'Final Approval',
type: 'approval',
assignee: '[email protected]',
status: 'draft'
}
],
currentStep: 1,
status: 'pending',
createdAt: new Date(),
updatedAt: new Date(),
createdBy: '[email protected]'
}Multi-Level Escalation
const escalationWorkflow: WorkflowDefinition = {
id: 'escalation-workflow',
name: 'Escalation Workflow',
steps: [
{
id: 'level-1',
name: 'Level 1 Approval',
type: 'approval',
assignee: '[email protected]',
status: 'pending'
},
{
id: 'level-2',
name: 'Level 2 Approval',
type: 'approval',
assignee: '[email protected]',
status: 'draft'
},
{
id: 'level-3',
name: 'Level 3 Approval',
type: 'approval',
assignee: '[email protected]',
status: 'draft'
}
],
currentStep: 0,
status: 'pending',
createdAt: new Date(),
updatedAt: new Date(),
createdBy: '[email protected]'
}🔐 Permissions and Security
Role-Based Access Control
// Check user permissions
const canApprove = engine.canApproveStep(workflowId, stepId, userId)
const canView = engine.canViewWorkflow(workflowId, userId)
const canCancel = engine.canCancelWorkflow(workflowId, userId)
// Role-based assignments
const workflowWithRoles: WorkflowDefinition = {
id: 'role-based-workflow',
name: 'Role-Based Workflow',
steps: [
{
id: 'dept-approval',
name: 'Department Approval',
type: 'approval',
assignee: ['role:department-head', 'role:finance-manager'],
status: 'pending'
},
{
id: 'exec-approval',
name: 'Executive Approval',
type: 'approval',
assignee: 'role:executive',
status: 'draft'
}
],
// ... other properties
}User Assignment Strategies
// Dynamic assignment based on business rules
const assignStep = (workflowId: string, stepId: string, context: any) => {
const assignee = determineAssignee(context)
return engine.assignStep(workflowId, stepId, assignee)
}
function determineAssignee(context: any): string {
// Business logic for assignment
if (context.amount > 10000) {
return '[email protected]'
} else if (context.department === 'finance') {
return '[email protected]'
} else {
return '[email protected]'
}
}📊 Analytics and Reporting
Workflow Performance Metrics
const analytics = engine.getAnalytics(workflowId)
const metrics = {
totalWorkflows: analytics.totalCount,
averageCompletionTime: analytics.averageCompletionTime,
approvalRate: analytics.approvalRate,
rejectionRate: analytics.rejectionRate,
bottleneckSteps: analytics.bottleneckSteps,
slaCompliance: analytics.slaCompliance
}Custom Reporting
const generateReport = async (dateRange: { start: Date; end: Date }) => {
const report = await engine.generateReport({
workflowType: 'expense-approval',
dateRange,
metrics: ['completion-time', 'approval-rate', 'sla-compliance'],
groupBy: 'department'
})
return report
}🎣 React Hooks
useWorkflow Hook
The useWorkflow hook provides access to workflow context and state management:
import { useWorkflow } from '@kodeme-io/next-core-workflow'
function WorkflowComponent() {
const {
engine,
currentWorkflow,
setCurrentWorkflow,
processAction,
refreshWorkflow,
notifications,
clearNotifications
} = useWorkflow()
const handleApprove = async () => {
if (!currentWorkflow) return
const success = await processAction({
stepId: currentWorkflow.steps[currentWorkflow.currentStep!].id,
action: 'approve',
comments: 'Approved',
userId: '[email protected]',
timestamp: new Date()
})
if (success) {
console.log('Action processed successfully')
}
}
return (
<div>
{notifications.map((notif, idx) => (
<div key={idx} className="notification">
{notif.message}
</div>
))}
<button onClick={handleApprove}>Approve</button>
</div>
)
}Custom Hook Example
Create a custom hook for specific workflow types:
import { useWorkflow } from '@kodeme-io/next-core-workflow'
function useExpenseWorkflow() {
const { currentWorkflow, processAction } = useWorkflow()
const approveExpense = async (comments: string) => {
if (!currentWorkflow) return false
return await processAction({
stepId: currentWorkflow.steps[currentWorkflow.currentStep!].id,
action: 'approve',
comments,
userId: '[email protected]',
timestamp: new Date()
})
}
const rejectExpense = async (reason: string) => {
if (!currentWorkflow) return false
return await processAction({
stepId: currentWorkflow.steps[currentWorkflow.currentStep!].id,
action: 'reject',
comments: reason,
userId: '[email protected]',
timestamp: new Date()
})
}
return {
workflow: currentWorkflow,
approveExpense,
rejectExpense,
isPending: currentWorkflow?.status === 'pending',
currentStep: currentWorkflow?.steps[currentWorkflow?.currentStep || 0]
}
}🧪 Testing
The package includes comprehensive test coverage:
# Run tests
npm test
# Run with coverage
npm run test:coverage
# Run tests in watch mode
npm run test:watchTesting Workflow Logic
import { WorkflowEngine } from '@kodeme-io/next-core-workflow'
test('workflow approval process', async () => {
const engine = new WorkflowEngine()
const workflow = engine.createWorkflow({
definition: testWorkflow,
initiator: '[email protected]'
})
// Simulate approval
const action: ApprovalAction = {
stepId: 'manager-approval',
action: 'approve',
comments: 'Approved',
userId: '[email protected]',
timestamp: new Date()
}
const result = await engine.processAction(workflow.id, action)
expect(result.success).toBe(true)
expect(result.workflow.status).toBe('approved')
})🔧 API Reference
Core Classes
class WorkflowEngine {
constructor(options?: WorkflowEngineOptions)
// Workflow management
createWorkflow(options: CreateWorkflowOptions): WorkflowDefinition
getWorkflow(id: string): WorkflowDefinition
updateWorkflow(id: string, updates: Partial<WorkflowDefinition>): WorkflowDefinition
deleteWorkflow(id: string): boolean
// Action processing
processAction(workflowId: string, action: ApprovalAction): Promise<ProcessActionResult>
getNextStep(workflowId: string): WorkflowStep | null
getActiveSteps(workflowId: string): WorkflowStep[]
// Permissions
canViewWorkflow(workflowId: string, userId: string): boolean
canApproveStep(workflowId: string, stepId: string, userId: string): boolean
canRejectStep(workflowId: string, stepId: string, userId: string): boolean
canCancelWorkflow(workflowId: string, userId: string): boolean
// Analytics
getAnalytics(workflowId?: string): WorkflowAnalytics
generateReport(options: ReportOptions): Promise<WorkflowReport>
}Types
// Core types
export type WorkflowStatus = 'draft' | 'pending' | 'approved' | 'rejected' | 'cancelled'
export type StepType = 'approval' | 'review' | 'action' | 'condition'
export type ActionType = 'approve' | 'reject' | 'request_changes'
// Action interface
export interface ApprovalAction {
stepId: string
action: ActionType
comments?: string
userId: string
timestamp: Date
}
// History interface
export interface WorkflowHistory {
id: string
workflowId: string
actions: ApprovalAction[]
}Component Props
// WorkflowViewer props
export interface WorkflowViewerProps {
workflow: WorkflowDefinition
showSteps?: boolean
showTimeline?: boolean
compact?: boolean
className?: string
}
// ApprovalActions props
export interface ApprovalActionsProps {
step: WorkflowStep
onAction: (action: ApprovalAction) => void
currentUserId: string
showComments?: boolean
requiredComments?: boolean
className?: string
}🔍 Troubleshooting
Common Issues
Workflow Not Progressing
- Check if the current step is assigned to the correct user
- Verify the action is valid for the current step type
- Ensure workflow status allows progression
Permission Errors
- Verify user has required permissions for the action
- Check role assignments and user mappings
- Ensure workflow is not in a terminal state
Performance Issues
- Use workflow indexing for large datasets
- Implement pagination for workflow history
- Cache frequently accessed workflow data
Debug Mode
Enable debug logging:
const engine = new WorkflowEngine({
debug: true,
logLevel: 'verbose'
})🔄 Integration Examples
Database Integration
import { WorkflowEngine } from '@kodeme-io/next-core-workflow'
class DatabaseWorkflowEngine extends WorkflowEngine {
constructor(private db: Database) {
super({
notificationHandler: this.handleDatabaseNotifications.bind(this)
})
}
async createWorkflow(options: CreateWorkflowOptions): Promise<WorkflowDefinition> {
const workflow = super.createWorkflow(options)
// Save to database
await this.db.workflows.create({
data: {
id: workflow.id,
definition: workflow,
status: workflow.status,
createdAt: workflow.createdAt,
createdBy: workflow.createdBy
}
})
return workflow
}
async loadWorkflowsFromDatabase(): Promise<void> {
const workflows = await this.db.workflows.findMany()
workflows.forEach(dbWorkflow => {
this.workflows.set(dbWorkflow.id, dbWorkflow.definition)
})
}
private async handleDatabaseNotifications(notification: WorkflowNotification) {
await this.db.notifications.create({
data: {
type: notification.type,
workflowId: notification.workflowId,
userId: notification.userId,
message: notification.message,
timestamp: notification.timestamp
}
})
}
}Email/Notification Integration
import nodemailer from 'nodemailer'
const workflowEngine = new WorkflowEngine({
notificationHandler: async (notification) => {
// Send email notification
const transporter = nodemailer.createTransporter({
service: 'gmail',
auth: {
user: process.env.EMAIL_USER,
pass: process.env.EMAIL_PASS
}
})
await transporter.sendMail({
from: '[email protected]',
to: notification.userId,
subject: `Workflow Update: ${notification.message}`,
text: `Your workflow requires attention: ${notification.message}`
})
// Send push notification (if using push service)
if (notification.type === 'step_assigned') {
await sendPushNotification(notification.userId, {
title: 'New Task Assigned',
body: notification.message,
data: { workflowId: notification.workflowId }
})
}
}
})REST API Integration
// Next.js API route
import { NextApiRequest, NextApiResponse } from 'next'
import { WorkflowEngine } from '@kodeme-io/next-core-workflow'
const engine = new WorkflowEngine()
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
const { method } = req
const { workflowId, stepId } = req.query
switch (method) {
case 'POST':
// Process approval action
const { action, comments, userId } = req.body
const result = await engine.processAction(workflowId as string, {
stepId: stepId as string,
action,
comments,
userId,
timestamp: new Date()
})
return res.status(200).json(result)
case 'GET':
// Get workflow details
const workflow = engine.getWorkflow(workflowId as string)
if (!workflow) {
return res.status(404).json({ error: 'Workflow not found' })
}
return res.status(200).json(workflow)
default:
res.setHeader('Allow', ['GET', 'POST'])
return res.status(405).end(`Method ${method} Not Allowed`)
}
}🚀 Performance Tips
- Workflow Caching - Cache workflow definitions and instances
- Database Optimization - Use proper indexing for workflow queries
- Real-time Updates - Implement WebSocket connections for live updates
- Batch Operations - Process multiple workflow actions in batches
// Caching example
const workflowCache = new Map<string, WorkflowDefinition>()
const getCachedWorkflow = (id: string): WorkflowDefinition => {
if (workflowCache.has(id)) {
return workflowCache.get(id)!
}
const workflow = engine.getWorkflow(id)
workflowCache.set(id, workflow)
return workflow
}Database Performance Optimization
-- Add indexes for better performance
CREATE INDEX idx_workflows_status ON workflows(status);
CREATE INDEX idx_workflows_created_by ON workflows(created_by);
CREATE INDEX idx_workflows_created_at ON workflows(createdAt);
CREATE INDEX idx_workflow_actions_workflow_id ON workflow_actions(workflow_id);
CREATE INDEX idx_workflow_actions_user_id ON workflow_actions(user_id);Batch Processing Example
async function processBatchActions(
engine: WorkflowEngine,
actions: Array<{ workflowId: string; action: ApprovalAction }>
): Promise<ProcessActionResult[]> {
const results = await Promise.allSettled(
actions.map(({ workflowId, action }) =>
engine.processAction(workflowId, action)
)
)
return results.map(result =>
result.status === 'fulfilled'
? result.value
: { success: false, error: result.reason, workflow: {} as WorkflowDefinition }
)
}🤝 Contributing
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests for new functionality
- Submit a pull request
📄 License
MIT License - see LICENSE file for details
🔗 Related Packages
- @kodeme-io/next-core-forms - Form components and validation
- @kodeme-io/next-core-analytics - Analytics and reporting
- @kodeme-io/next-core-ui - UI components
📞 Support
- Documentation: Full documentation
- Issues: GitHub Issues
- Discord: Community Discord
