@bernierllc/content-workflow-service
v0.1.3
Published
Workflow orchestration service for content management
Downloads
213
Readme
@bernierllc/content-workflow-service
Workflow orchestration service for content management.
Overview
This package provides a service layer for orchestrating editorial workflows in content management systems. It builds on top of the @bernierllc/content-editorial-workflow core package to provide workflow execution, permission checking, notifications, and event handling.
Features
- Workflow Orchestration: Execute and manage editorial workflows
- Permission Checking: Enforce permissions for stage transitions
- Event Handling: Comprehensive event system for workflow operations
- Notifications: Send notifications for workflow events
- Statistics: Track workflow performance and usage
- Hooks System: Extensible hooks for custom processing
- TypeScript Support: Full type safety and IntelliSense
Installation
npm install @bernierllc/content-workflow-serviceQuick Start
import { ContentWorkflowService } from '@bernierllc/content-workflow-service';
import { WorkflowTemplates } from '@bernierllc/content-editorial-workflow';
// Create workflow service
const service = new ContentWorkflowService({
enabled: true,
permissions: {
enabled: true,
defaultPermissions: ['content.edit', 'content.publish']
},
notifications: {
enabled: true,
channels: ['email', 'internal']
}
});
// Register a workflow
const workflow = WorkflowTemplates.writeAndPublish();
await service.registerWorkflow(workflow);
// Create content in workflow
const content = await service.createContent('content-1', 'write-and-publish', {
contentId: 'content-1',
userId: 'user-123',
userPermissions: ['content.edit', 'content.publish'],
contentMetadata: { type: 'text', title: 'My Article' }
});
// Transition content to next stage
const result = await service.transitionStage({
contentId: 'content-1',
targetStageId: 'publish',
userId: 'user-123',
reason: 'Ready to publish'
});
if (result.success) {
console.log('Content moved to publish stage');
}API Reference
ContentWorkflowService
The main service class for managing content workflows.
Constructor
new ContentWorkflowService(config?: Partial<ContentWorkflowServiceConfig>)Configuration Options
interface ContentWorkflowServiceConfig {
enabled: boolean; // Whether the service is enabled
defaultWorkflowId?: string; // Default workflow for new content
publishEvents: boolean; // Whether to publish events
logOperations: boolean; // Whether to log operations
permissions: {
enabled: boolean; // Whether to enforce permissions
defaultPermissions: string[]; // Default permissions
};
notifications: {
enabled: boolean; // Whether to send notifications
channels: string[]; // Notification channels
};
}Methods
registerWorkflow(workflow)
Register a new workflow.
const workflow = WorkflowTemplates.writeAndPublish();
await service.registerWorkflow(workflow);createContent(contentId, workflowId, context)
Create content in a workflow.
const content = await service.createContent('content-1', 'workflow-1', {
contentId: 'content-1',
userId: 'user-123',
userPermissions: ['content.edit'],
contentMetadata: { type: 'text', title: 'My Article' }
});transitionStage(request)
Transition content to a different stage.
const result = await service.transitionStage({
contentId: 'content-1',
targetStageId: 'publish',
userId: 'user-123',
reason: 'Ready to publish'
});getContentStatus(contentId)
Get workflow status for content.
const status = service.getContentStatus('content-1');
console.log('Current stage:', status.currentStageId);
console.log('Can publish:', status.canPublish);
console.log('Available transitions:', status.availableTransitions);checkPermissions(contentId, targetStageId, userId)
Check permissions for stage transition.
const permissionCheck = await service.checkPermissions('content-1', 'publish', 'user-123');
if (!permissionCheck.allowed) {
console.log('Missing permissions:', permissionCheck.missingPermissions);
}Event System
Listen to workflow service events.
service.onEvent((event) => {
switch (event.type) {
case 'workflow_registered':
console.log('Workflow registered:', event.data.workflowId);
break;
case 'stage_transitioned':
console.log('Stage transitioned:', event.data.contentId);
break;
case 'permission_denied':
console.log('Permission denied:', event.data.reason);
break;
}
});Hooks System
Add custom processing for workflow events.
service.addHook({
name: 'audit-log',
hook: async (event) => {
// Log workflow events for audit
auditLogger.log(event.type, {
timestamp: event.timestamp,
userId: event.userId,
data: event.data
});
},
priority: 1,
enabled: true,
eventTypes: ['stage_transitioned', 'permission_denied']
});Examples
Basic Workflow Management
import { ContentWorkflowService } from '@bernierllc/content-workflow-service';
import { WorkflowTemplates } from '@bernierllc/content-editorial-workflow';
class ContentManager {
private workflowService: ContentWorkflowService;
constructor() {
this.workflowService = new ContentWorkflowService({
enabled: true,
permissions: {
enabled: true,
defaultPermissions: ['content.edit', 'content.publish']
}
});
// Set up event handling
this.workflowService.onEvent((event) => {
this.handleWorkflowEvent(event);
});
}
async initialize() {
// Register default workflow
const workflow = WorkflowTemplates.writeAndPublish();
await this.workflowService.registerWorkflow(workflow);
}
async createContent(contentId: string, userId: string, contentData: any) {
const content = await this.workflowService.createContent(contentId, 'write-and-publish', {
contentId,
userId,
userPermissions: await this.getUserPermissions(userId),
contentMetadata: contentData
});
return content;
}
async publishContent(contentId: string, userId: string) {
const result = await this.workflowService.transitionStage({
contentId,
targetStageId: 'publish',
userId,
reason: 'Publishing content'
});
if (result.success) {
// Update UI to show published status
this.updateContentStatus(contentId, 'published');
}
return result;
}
private handleWorkflowEvent(event: any) {
switch (event.type) {
case 'stage_transitioned':
this.notifyUser(`Content ${event.data.contentId} moved to ${event.data.newStageId}`);
break;
case 'permission_denied':
this.notifyUser(`Permission denied: ${event.data.reason}`);
break;
}
}
}Advanced Permission Management
class PermissionAwareContentManager {
constructor(private workflowService: ContentWorkflowService) {}
async transitionWithPermissionCheck(
contentId: string,
targetStageId: string,
userId: string,
reason: string
) {
// Check permissions first
const permissionCheck = await this.workflowService.checkPermissions(
contentId,
targetStageId,
userId
);
if (!permissionCheck.allowed) {
return {
success: false,
error: `Permission denied: ${permissionCheck.error}`,
missingPermissions: permissionCheck.missingPermissions
};
}
// Proceed with transition
return this.workflowService.transitionStage({
contentId,
targetStageId,
userId,
reason
});
}
async getUserPermissions(userId: string): Promise<string[]> {
// In a real implementation, this would fetch from a permissions service
const user = await this.getUser(userId);
return user.permissions || [];
}
}Notification Integration
class NotificationEnabledContentManager {
constructor(private workflowService: ContentWorkflowService) {
// Set up notification hooks
this.workflowService.addHook({
name: 'notification-hook',
hook: async (event) => {
if (event.type === 'stage_transitioned') {
await this.sendNotification(event);
}
},
priority: 1,
enabled: true,
eventTypes: ['stage_transitioned']
});
}
private async sendNotification(event: any) {
const { contentId, newStageId, userId } = event.data;
// Send email notification
await this.emailService.send({
to: await this.getUserEmail(userId),
subject: 'Content Status Changed',
body: `Your content ${contentId} has moved to stage ${newStageId}`
});
// Send internal notification
await this.internalNotificationService.send({
userId,
type: 'content_status_changed',
data: { contentId, newStageId }
});
}
}Statistics and Analytics
class ContentAnalytics {
constructor(private workflowService: ContentWorkflowService) {}
getWorkflowReport() {
const stats = this.workflowService.getStatistics();
return {
totalWorkflows: stats.totalWorkflows,
totalContent: stats.totalContent,
contentByStage: stats.contentByStage,
recentActivity: {
transitionsLast24h: stats.transitionsLast24h,
permissionDenialsLast24h: stats.permissionDenialsLast24h,
notificationsSentLast24h: stats.notificationsSentLast24h
},
performance: {
averageStageTime: stats.averageStageTime
}
};
}
getStagePerformanceAnalysis() {
const stats = this.workflowService.getStatistics();
return Object.entries(stats.contentByStage).map(([stageId, count]) => ({
stageId,
contentCount: count,
percentage: (count / stats.totalContent) * 100,
averageTime: stats.averageStageTime[stageId] || 0
}));
}
}Integration with Existing Services
class IntegratedContentManager {
constructor(
private workflowService: ContentWorkflowService,
private contentService: ContentService,
private userService: UserService
) {
// Set up integration hooks
this.workflowService.addHook({
name: 'content-sync',
hook: async (event) => {
if (event.type === 'stage_transitioned') {
await this.syncContentStatus(event.data.contentId, event.data.newStageId);
}
},
priority: 1,
enabled: true,
eventTypes: ['stage_transitioned']
});
}
async createContentWithWorkflow(contentData: any, userId: string) {
// Create content in content service
const content = await this.contentService.create(contentData);
// Create workflow entry
const workflowContent = await this.workflowService.createContent(
content.id,
'default-workflow',
{
contentId: content.id,
userId,
userPermissions: await this.userService.getPermissions(userId),
contentMetadata: content
}
);
return { content, workflow: workflowContent };
}
private async syncContentStatus(contentId: string, stageId: string) {
// Update content status in content service
await this.contentService.updateStatus(contentId, stageId);
// Update user notifications
await this.userService.addNotification(contentId, `Content moved to ${stageId}`);
}
}Integration Status
- Logger: integrated - Uses @bernierllc/logger for operation logging and event tracking
- NeverHub: integrated - Provides service discovery and event bus capabilities when available
- Docs-Suite: ready - Full API documentation and examples available in markdown format
TypeScript Support
This package is written in TypeScript and provides full type definitions. All interfaces and types are exported for use in your own code.
License
UNLICENSED - See LICENSE file for details.
Contributing
Contributions are welcome! Please see the contributing guidelines for more information.
Support
For support and questions, please open an issue on GitHub.
