Package Exports
- @bernierllc/workflow-service
- @bernierllc/workflow-service/dist/index.js
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@bernierllc/workflow-service) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
@bernierllc/workflow-service
Orchestrates content workflow management with approval and notification systems
Features
- 🔄 Complete Workflow Orchestration - Manage content lifecycle from creation to publication
- ✅ Multi-Approver Support - Configure workflows with multiple approval requirements
- 🔔 Notification Management - Automated notifications via email, webhooks, and more
- 🎯 Role-Based Permissions - Integration with auth-service for access control
- 📊 State Machine Integration - Uses content-state-machine for reliable state transitions
- 🚀 Batch Operations - Approve or reject multiple workflows at once
- 📈 Workflow Analytics - Track workflow performance and bottlenecks
- 🔌 NeverHub Integration - Event-driven architecture with other services
Installation
npm install @bernierllc/workflow-serviceUsage
Quick Start
import { WorkflowService } from '@bernierllc/workflow-service';
import { WorkflowPriority, NotificationChannel } from '@bernierllc/workflow-service';
// Initialize the workflow service
const workflowService = new WorkflowService({
storage: {
type: 'memory' // or 'database' with connection string
},
notifications: {
enabled: true,
defaultChannels: [NotificationChannel.EMAIL],
webhookTimeout: 30000,
retryAttempts: 3,
templates: {}
},
permissions: {
requireAuth: true, // Enable permission checking
adminRoles: ['admin'],
approverRoles: ['approver', 'editor', 'admin']
},
defaults: {
approvalRequired: true,
approverCount: 2, // Require 2 approvals
autoSchedule: false,
priority: WorkflowPriority.MEDIUM,
notificationEnabled: true
}
});
// Create a workflow
const workflow = await workflowService.createWorkflow(
'article-123', // contentId
{
name: 'Blog Post Approval',
description: 'Two-stage approval for blog posts',
approvalRequired: true,
approverCount: 2,
notificationConfig: {
enabled: true,
channels: [NotificationChannel.EMAIL],
recipients: {
onSubmit: ['editor@company.com'],
onApproval: ['author@company.com'],
onPublish: ['marketing@company.com']
}
}
},
'author-456' // creator
);
// Submit for review
const submitResult = await workflowService.submitForReview(workflow.id, 'author-456');
console.log(`Submitted: ${submitResult.newState}`); // PENDING_REVIEW
// Assign approvers and request approval
await workflowService.assignApprover(workflow.id, 'editor-789');
await workflowService.assignApprover(workflow.id, 'manager-101');
const approvalRequest = await workflowService.requestApproval(
workflow.id,
['editor-789', 'manager-101']
);
// Handle approvals
const approval1 = await workflowService.approveContent(
workflow.id,
'editor-789',
'Content is well-written and factually accurate'
);
const approval2 = await workflowService.approveContent(
workflow.id,
'manager-101',
'Approved for publication'
);
console.log(`Final state: ${approval2.newState}`); // APPROVED
// Schedule for publication
await workflowService.scheduleContent(workflow.id, {
scheduledAt: new Date('2025-01-15T10:00:00Z'),
timezone: 'UTC',
autoPublish: true,
notifyBefore: 30 // minutes
});Workflow Configuration
Basic Workflow Config
interface WorkflowConfig {
name: string;
description?: string;
approvalRequired: boolean;
approverCount: number; // Required number of approvals
autoSchedule: boolean;
notificationConfig: NotificationConfig;
customRules?: WorkflowRule[];
}Notification Configuration
const notificationConfig = {
enabled: true,
channels: [
NotificationChannel.EMAIL,
NotificationChannel.WEBHOOK,
NotificationChannel.SLACK
],
recipients: {
onSubmit: ['editors@company.com'],
onApproval: ['author@company.com', 'manager@company.com'],
onRejection: ['author@company.com'],
onSchedule: ['marketing@company.com'],
onPublish: ['marketing@company.com', 'analytics@company.com'],
onDeadline: ['manager@company.com']
},
escalation: {
enabled: true,
timeoutHours: 24,
escalateTo: ['director@company.com'],
maxEscalations: 2
}
};API Reference
Core Workflow Methods
createWorkflow(contentId, config?, creator?)
Creates a new workflow for content management.
const workflow = await workflowService.createWorkflow('article-123', {
name: 'Article Review Workflow',
approverCount: 2,
approvalRequired: true
}, 'author-456');updateWorkflow(workflowId, updates, updater?)
Updates an existing workflow configuration.
const updatedWorkflow = await workflowService.updateWorkflow('workflow-789', {
approverCount: 3,
autoSchedule: true
}, 'manager-101');deleteWorkflow(workflowId, deleter?)
Deletes a workflow and cleans up associated state.
const deleted = await workflowService.deleteWorkflow('workflow-789', 'admin-555');State Transition Methods
submitForReview(workflowId, submitter)
Submits content for review, transitioning from DRAFT to PENDING_REVIEW.
const result = await workflowService.submitForReview('workflow-789', 'author-456');
if (result.success) {
console.log(`New state: ${result.newState}`);
}approveContent(workflowId, approver, notes?)
Approves content. May require multiple approvals based on workflow configuration.
const result = await workflowService.approveContent(
'workflow-789',
'editor-123',
'Content meets our quality standards'
);rejectContent(workflowId, rejector, reason)
Rejects content and provides feedback for revision.
const result = await workflowService.rejectContent(
'workflow-789',
'editor-123',
'Please add more sources and fact-check the statistics'
);scheduleContent(workflowId, schedule)
Schedules approved content for publication.
const result = await workflowService.scheduleContent('workflow-789', {
scheduledAt: new Date('2025-01-15T14:00:00Z'),
timezone: 'America/New_York',
autoPublish: true,
notifyBefore: 15,
recurring: {
pattern: 'weekly',
interval: 1,
daysOfWeek: [1, 3, 5], // Mon, Wed, Fri
endDate: new Date('2025-12-31T23:59:59Z')
}
});publishContent(workflowId)
Publishes scheduled content.
const result = await workflowService.publishContent('workflow-789');Approval Management
assignApprover(workflowId, approver)
Assigns an approver to a workflow.
await workflowService.assignApprover('workflow-789', 'senior-editor-456');requestApproval(workflowId, approvers)
Creates an approval request for multiple approvers.
const request = await workflowService.requestApproval('workflow-789', [
'editor-123',
'legal-456',
'marketing-789'
]);getPendingApprovals(approver)
Gets all pending approval requests for a user.
const pending = await workflowService.getPendingApprovals('editor-123');
console.log(`${pending.length} approvals pending`);Workflow Queries
getWorkflow(workflowId)
Retrieves a workflow by ID.
const workflow = await workflowService.getWorkflow('workflow-789');
if (workflow) {
console.log(`Current state: ${workflow.currentState}`);
}getWorkflowByContent(contentId)
Finds a workflow by its associated content ID.
const workflow = await workflowService.getWorkflowByContent('article-123');listWorkflows(filters?)
Lists workflows with optional filtering.
// Get all workflows assigned to a specific approver
const workflows = await workflowService.listWorkflows({
assignedTo: ['editor-123'],
state: [ContentState.PENDING_REVIEW],
priority: [WorkflowPriority.HIGH, WorkflowPriority.URGENT],
dateRange: {
start: new Date('2025-01-01'),
end: new Date('2025-01-31')
},
limit: 20,
offset: 0
});getWorkflowHistory(workflowId)
Gets the complete history of events for a workflow.
const history = await workflowService.getWorkflowHistory('workflow-789');
history.forEach(event => {
console.log(`${event.type} by ${event.actor} at ${event.timestamp}`);
if (event.reason) console.log(` Reason: ${event.reason}`);
});Batch Operations
bulkApprove(workflowIds, approver)
Approves multiple workflows at once.
const result = await workflowService.bulkApprove([
'workflow-1',
'workflow-2',
'workflow-3'
], 'manager-456');
console.log(`Approved ${result.summary.successful} out of ${result.summary.total}`);bulkReject(workflowIds, rejector, reason)
Rejects multiple workflows with the same reason.
const result = await workflowService.bulkReject([
'workflow-1',
'workflow-2'
], 'editor-123', 'Content needs major revision');Notification Management
sendWorkflowNotification(workflowId, type, recipients)
Sends custom notifications for a workflow.
await workflowService.sendWorkflowNotification(
'workflow-789',
NotificationType.EMAIL,
['stakeholder@company.com']
);Integration with Content State Machine
The workflow service uses @bernierllc/content-state-machine for reliable state transitions:
import { ContentState } from '@bernierllc/content-state-machine';
// Valid state transitions are enforced by the state machine
const states = [
ContentState.DRAFT, // Initial state
ContentState.PENDING_REVIEW, // After submission
ContentState.APPROVED, // After approval
ContentState.SCHEDULED, // After scheduling
ContentState.PUBLISHED, // After publication
ContentState.REJECTED // If rejected at any point
];Integration with Auth Service
Enable permission-based access control:
const workflowService = new WorkflowService({
// ... other config
permissions: {
requireAuth: true,
defaultPermissions: ['workflow:view'],
adminRoles: ['admin', 'workflow-admin'],
approverRoles: ['approver', 'editor', 'manager', 'admin']
},
integrations: {
auth: {
enabled: true,
provider: 'auth-service'
}
}
});
// Permissions are automatically checked for all operations
const result = await workflowService.approveContent(
'workflow-789',
'user-without-permission', // Will fail if user lacks 'workflow:approve' permission
'Approval notes'
);Notification Channels
Email Notifications
const config = {
notifications: {
enabled: true,
defaultChannels: [NotificationChannel.EMAIL],
templates: {
[WorkflowEventType.SUBMITTED]: 'Content "{{workflowName}}" submitted for review',
[WorkflowEventType.APPROVED]: 'Content "{{workflowName}}" has been approved',
[WorkflowEventType.REJECTED]: 'Content "{{workflowName}}" needs revision: {{reason}}'
}
}
};Webhook Notifications
const config = {
notifications: {
enabled: true,
defaultChannels: [NotificationChannel.WEBHOOK],
webhookTimeout: 30000,
retryAttempts: 3
},
integrations: {
webhook: {
enabled: true,
endpoints: [
'https://your-app.com/webhooks/workflow-events',
'https://analytics.company.com/workflow-webhook'
],
signatures: true // Include HMAC signatures
}
}
};Slack Integration
// Custom notification via Slack
await workflowService.sendWorkflowNotification(
'workflow-789',
NotificationType.SLACK,
['#editorial-team', '#marketing-updates']
);NeverHub Event Integration
The service publishes events to NeverHub for real-time coordination:
// Events published automatically
const events = [
'workflow.created',
'workflow.state.changed',
'workflow.approval.requested',
'workflow.approval.completed',
'workflow.notification.sent',
'workflow.escalated',
'workflow.deadline.missed'
];
// Subscribe to events from other services
const workflowService = new WorkflowService({
// ... config
integrations: {
neverhub: {
enabled: true,
events: [
WorkflowEventType.CREATED,
WorkflowEventType.APPROVED,
WorkflowEventType.PUBLISHED
]
}
}
});Advanced Configuration
Custom Workflow Rules
const customRules = [
{
id: 'urgent-priority-rule',
name: 'Urgent Priority Fast Track',
condition: {
type: 'content',
field: 'priority',
operator: 'equals',
value: WorkflowPriority.URGENT
},
action: {
type: 'assign',
parameters: {
approvers: ['director@company.com'],
skipNormalApproval: true
}
},
enabled: true
}
];
const workflow = await workflowService.createWorkflow('urgent-content', {
name: 'Urgent Content Workflow',
customRules
});Escalation Configuration
const escalationConfig = {
enabled: true,
timeoutHours: 48, // Escalate after 48 hours
escalateTo: ['director@company.com', 'ceo@company.com'],
maxEscalations: 3 // Maximum escalation levels
};
const workflow = await workflowService.createWorkflow('important-content', {
name: 'Important Content Workflow',
notificationConfig: {
enabled: true,
channels: [NotificationChannel.EMAIL, NotificationChannel.SLACK],
recipients: { /* ... */ },
escalation: escalationConfig
}
});Error Handling
try {
const result = await workflowService.approveContent(workflowId, approver);
if (!result.success) {
console.error(`Approval failed: ${result.error}`);
// Handle specific error cases
switch (result.error) {
case 'Workflow not found':
// Handle missing workflow
break;
case 'Invalid state transition':
// Handle invalid transition
break;
case 'Insufficient permissions':
// Handle permission error
break;
}
}
} catch (error) {
console.error('Unexpected error:', error);
}Performance Considerations
Batch Operations
// Instead of individual operations
for (const workflowId of workflowIds) {
await workflowService.approveContent(workflowId, approver);
}
// Use batch operations for better performance
const result = await workflowService.bulkApprove(workflowIds, approver);Filtering and Pagination
// Use filters to reduce data transfer
const recentWorkflows = await workflowService.listWorkflows({
dateRange: {
start: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000), // Last week
end: new Date()
},
state: [ContentState.PENDING_REVIEW],
limit: 50,
offset: 0
});Integration Status
- Logger: integrated - Uses @bernierllc/logger for structured logging of workflow events and state transitions
- NeverHub: integrated - Publishes workflow lifecycle events (created, state.changed, approval.requested, approval.completed, notification.sent, escalated, deadline.missed) via @bernierllc/neverhub-adapter
- Docs-Suite: ready - Complete API documentation with TypeScript interfaces, markdown format
Dependencies
@bernierllc/content-state-machine- State transition management@bernierllc/auth-service- Authentication and authorization@bernierllc/webhook-sender- Webhook delivery@bernierllc/permission-checker- Permission validation@bernierllc/neverhub-adapter- Event bus integration@bernierllc/logger- Structured logginguuid- Unique identifier generation
See Also
- @bernierllc/content-state-machine - State transition engine
- @bernierllc/auth-service - Authentication and authorization
- @bernierllc/webhook-sender - Webhook delivery system
- @bernierllc/content-scheduler-suite - Complete content scheduling solution
License
Copyright (c) 2025 Bernier LLC. All rights reserved.