@duabalabs/workflow-builder-server
v1.0.0
Published
Parse Server plugin for workflow execution engine with built-in DPS and PMO node packs
Maintainers
Readme
@duabalabs/workflow-builder-server
Parse Server plugin providing a complete workflow execution engine with built-in node packs for web deployment (DPS) and physical project management (PMO).
Features
- Workflow Engine: Execute sync, async, and human-in-the-loop tasks
- Node Registry: Extensible node type system with JSON/YAML definitions
- Validation: Schema-based validation with business rules enforcement
- Built-in Node Packs:
- Shared: Common logic (if/else), HTTP requests, notifications
- DPS: Web deployment automation (repo checkout, build, deploy, DNS, monitoring)
- PMO: Physical project workflows (land registration, farm management, logistics)
- Templates: Pre-built workflows for common use cases
- Parse Integration: Cloud Functions, ACLs, Parse Classes
Installation
npm install @duabalabs/workflow-builder-server
# or
pnpm add @duabalabs/workflow-builder-serverQuick Start
Basic Setup
// In your Parse Server cloud/main.js
import { initialize } from '@duabalabs/workflow-builder-server';
// Initialize with default options
await initialize(Parse, {
initSchema: true, // Create Parse classes
loadDefaultPacks: true // Load shared, DPS, PMO packs
});Manual Setup
import {
registerWorkflowFunctions,
initializeSchema,
loadPacks
} from '@duabalabs/workflow-builder-server';
import { sharedPack } from '@duabalabs/workflow-builder-server/packs/shared';
import { dpsPack } from '@duabalabs/workflow-builder-server/packs/dps';
import { pmoPack } from '@duabalabs/workflow-builder-server/packs/pmo';
// Register Cloud Functions
registerWorkflowFunctions(Parse);
// Initialize Parse schema
await initializeSchema(Parse);
// Load node packs
await loadPacks([sharedPack, dpsPack, pmoPack]);Cloud Functions
Version Check
const { version } = await Parse.Cloud.run('version');Node Registry
// List node definitions
const defs = await Parse.Cloud.run('listNodeDefs', {
scope: 'dps', // optional: 'shared', 'dps', 'pmo'
category: 'action' // optional
});
// List node packs
const packs = await Parse.Cloud.run('listNodePacks');Workflow CRUD
// Create workflow
const { workflowId } = await Parse.Cloud.run('createWorkflow', {
projectId: 'proj_123',
workflow: {
meta: { name: 'My Workflow', version: '1.0.0' },
graph: {
nodes: [
{ id: 'n1', type: 'repo.checkout', data: { repoUrl: '...' } }
],
edges: []
},
rules: {}
}
});
// Update workflow
await Parse.Cloud.run('updateWorkflow', {
workflowId,
patch: { meta: { name: 'Updated Name' } }
});
// Validate workflow
const validation = await Parse.Cloud.run('validateWorkflow', {
workflowId
});Execution
// Execute workflow
const { runId } = await Parse.Cloud.run('execute', {
workflowId,
inputs: { environment: 'production' }
});
// Check status
const { run, tasks } = await Parse.Cloud.run('runStatus', { runId });
// Cancel run
await Parse.Cloud.run('cancelRun', { runId });
// List runs
const runs = await Parse.Cloud.run('listRuns', {
workflowId,
status: 'completed',
limit: 50
});Templates
// List templates
const templates = await Parse.Cloud.run('listTemplates', {
scope: 'dps'
});
// Instantiate template
const workflow = await Parse.Cloud.run('instantiateTemplate', {
projectId: 'proj_123',
templateKey: 'dps.web-deploy',
parameters: { siteName: 'my-site' }
});Secrets
// Store secret
await Parse.Cloud.run('putSecret', {
projectId: 'proj_123',
key: 'NETLIFY_TOKEN',
value: 'secret_value_here',
scope: 'project'
});
// Get secret metadata (never returns plaintext)
const secrets = await Parse.Cloud.run('getSecretMeta', {
projectId: 'proj_123'
});Human Tasks
// Submit human task
await Parse.Cloud.run('submitHumanTask', {
taskId: 'task_123',
formData: {
officerName: 'John Doe',
date: '2024-01-15'
},
artifactIds: ['artifact_123']
});Node Packs
Shared Pack
- logic.ifElse: Conditional branching
- data.http: HTTP requests
DPS Pack (Digital Platform Services)
- repo.checkout: Clone Git repository
- build.react: Build React application
- deploy.netlify: Deploy to Netlify
PMO Pack (Project Management Office)
- land.titleSearch: Land title search (human task)
- land.deedRegistration: Deed registration (human task)
Creating Custom Nodes
import { NodeDefinition, NodeHandler, ExecutionContext } from '@duabalabs/workflow-builder-server';
// Define node
const myNodeDef: NodeDefinition = {
defId: 'custom.myNode',
name: 'My Custom Node',
category: 'action',
version: '1.0.0',
scope: 'shared',
inputs: [
{ key: 'input1', type: 'string', required: true }
],
outputs: [
{ key: 'result', type: 'string' }
],
execution: {
type: 'async',
handlerKey: 'custom.myNode',
timeoutSec: 60
}
};
// Implement handler
const myNodeHandler: NodeHandler = async (ctx: ExecutionContext) => {
const input = ctx.inputs.input1;
ctx.logger.info('Processing', { input });
// Your logic here
const result = `Processed: ${input}`;
return {
success: true,
outputs: { result }
};
};
// Create custom pack
const customPack = {
name: 'custom',
version: '1.0.0',
scope: 'shared',
definitions: [myNodeDef],
handlers: {
'custom.myNode': myNodeHandler
}
};
// Load pack
await loadPacks([customPack]);Templates
DPS Web Deploy Template
name: Deploy Web Application
scope: dps
graph:
nodes:
- id: n1
type: repo.checkout
data: { repoUrl: "..." }
- id: n2
type: build.react
data: { nodeVersion: "18" }
- id: n3
type: deploy.netlify
data: { token: "${NETLIFY_TOKEN}" }
edges:
- { source: n1, target: n2 }
- { source: n2, target: n3 }PMO Farm Project Template
name: Farm Establishment Project
scope: pmo
graph:
nodes:
- id: n1
type: land.titleSearch
data: { slaDays: 7 }
- id: n2
type: land.deedRegistration
data: { registrarOffice: "Regional Office" }
edges:
- { source: n1, target: n2 }Environment Variables
Create a .env file:
# Logging
LOG_LEVEL=info
# Redis (for BullMQ)
REDIS_URL=redis://localhost:6379
# Node environment
NODE_ENV=productionTesting
pnpm testLicense
MIT
