# Process Builder Technical Appendix This document provides technical implementation details for developers working with the Process Builder system. > For user documentation and usage guidelines, please refer to [Process Builder Documentation](USER_GUIDE.md) ## Architecture Overview ### Technology Stack - **Frontend Framework**: Nuxt 3 / Vue 3 - **State Management**: Pinia - **Flow Visualization**: Vue Flow - **UI Framework**: Tailwind CSS - **Icons**: Material Design Icons - **Validation**: Zod - **Form Components**: FormKit ### Key Dependencies ```json { "@vue-flow/core": "^1.42.5", "@vue-flow/background": "^1.3.2", "@vue-flow/controls": "^1.1.2", "@vue-flow/minimap": "^1.5.3", "@pinia/nuxt": "^0.4.11", "@formkit/nuxt": "^1.5.5", "uuid": "^10.0.0", "zod": "^3.22.2" } ``` ## Project Structure ``` pages/ ├── process-builder/ │ ├── index.vue # Main builder interface │ └── manage.vue # Process management components/ ├── process-flow/ │ ├── ProcessFlowCanvas.vue # Flow canvas │ ├── ProcessFlowNodes.js # Custom node types │ ├── FormSelector.vue # Form selection component │ ├── GatewayConditionManager.vue # Gateway conditions UI │ ├── ApiNodeConfiguration.vue # API node configuration │ ├── FormNodeConfiguration.vue # Form node configuration │ ├── BusinessRuleConfiguration.vue # Business rule configuration │ └── VariableManager.vue # Process variables manager stores/ ├── processBuilder.js # State management └── variableStore.js # Variable state management composables/ └── useProcessValidation.js # Process validation types/ └── process-builder.d.ts # TypeScript definitions ``` ## Component Architecture ### Core Components 1. **ProcessFlowCanvas.vue** ```vue ``` 2. **ProcessFlowNodes.js** ```javascript import { h, markRaw } from 'vue'; import { Handle, Position } from '@vue-flow/core'; // Enhanced custom node renderer with 4-point connection system const CustomNode = markRaw({ template: `
{{ label }}
`, props: ['id', 'type', 'label', 'data'], components: { Handle }, mounted() { // Add event listeners for handle visibility this.$el.addEventListener('mouseenter', this.showHandles); this.$el.addEventListener('mouseleave', this.hideHandles); }, methods: { showHandles() { const handles = this.$el.querySelectorAll('.vue-flow__handle'); handles.forEach(handle => { handle.style.opacity = '1'; }); }, hideHandles() { const handles = this.$el.querySelectorAll('.vue-flow__handle'); handles.forEach(handle => { handle.style.opacity = '0'; }); } } }); // Enhanced CSS for handles const handleStyles = ` .custom-node:hover .vue-flow__handle { opacity: 1 !important; z-index: 100; } .vue-flow__handle { opacity: 0; transition: all 0.2s ease; cursor: crosshair; border: 2px solid; border-radius: 50%; } .handle-input { background-color: #3b82f6; border-color: #1d4ed8; } .handle-output { background-color: #10b981; border-color: #059669; } .vue-flow__handle:hover { transform: scale(1.2); box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.3); } .custom-node.connecting .vue-flow__handle { opacity: 1; } /* Special handling for gateway nodes (rotated) */ .node-gateway .vue-flow__handle { position: absolute; } .node-gateway .vue-flow__handle[data-handlepos="top"] { top: -6px; left: 50%; transform: translate(-50%, -50%) rotate(-45deg); } .node-gateway .vue-flow__handle[data-handlepos="right"] { right: -6px; top: 50%; transform: translate(50%, -50%) rotate(-45deg); } .node-gateway .vue-flow__handle[data-handlepos="bottom"] { bottom: -6px; left: 50%; transform: translate(-50%, 50%) rotate(-45deg); } .node-gateway .vue-flow__handle[data-handlepos="left"] { left: -6px; top: 50%; transform: translate(-50%, -50%) rotate(-45deg); } `; // Node type definitions with enhanced handle system export const nodeTypes = markRaw({ task: TaskNode, start: StartNode, end: EndNode, gateway: GatewayNode, form: FormNode, api: ApiNode, script: ScriptNode, 'business-rule': BusinessRuleNode, notification: NotificationNode }); // Connection validation export const isValidConnection = (connection) => { // Prevent self-connections if (connection.source === connection.target) { return false; } // Validate handle types const sourceHandle = connection.sourceHandle; const targetHandle = connection.targetHandle; // Ensure proper source/target handle types if (sourceHandle && !sourceHandle.includes('right') && !sourceHandle.includes('bottom')) { return false; } if (targetHandle && !targetHandle.includes('top') && !targetHandle.includes('left')) { return false; } return true; }; // Enhanced connection handler with handle-specific routing export const onConnect = (params) => { const { source, target, sourceHandle, targetHandle } = params; return { id: `${source}-${target}-${Date.now()}`, source, target, sourceHandle, targetHandle, type: 'smoothstep', animated: true, style: { strokeWidth: 2, stroke: '#64748b' }, data: { sourcePosition: sourceHandle?.split('-')[1] || 'bottom', targetPosition: targetHandle?.split('-')[1] || 'top' } }; }; #### Handle System Features 1. **4-Point Connection System**: - **Top Handle**: Primary input connection point (blue, target) - **Right Handle**: Secondary output connection point (green, source) - **Bottom Handle**: Primary output connection point (green, source) - **Left Handle**: Secondary input connection point (blue, target) 2. **Enhanced Visibility**: - Handles are invisible by default for clean UI - Become visible on node hover with smooth transitions - Unique IDs for precise connection targeting (`nodeId-position`) 3. **Visual Feedback**: - Color-coded handles (blue for inputs, green for outputs) - Hover effects with scaling and shadow - Connection state awareness 4. **Special Node Handling**: - **Start Nodes**: Only output handles (right + bottom) - **End Nodes**: Only input handles (top + left) - **Gateway Nodes**: Rotated handle positioning for diamond shape 5. **Connection Validation**: - Prevents self-connections - Validates proper source/target handle types - Ensures logical connection flow ## Enhanced Node Configuration Components The following components implement the improved UI/UX for node configuration: ### 1. VariableManager.vue The Variable Manager allows users to create, edit, and manage global process variables. ```vue ``` ### 2. BusinessRuleConfiguration.vue The Business Rule Configuration component provides a stepped workflow for configuring rule nodes. ```vue ### 3. GatewayConditionManager.vue The Gateway Condition Manager provides an enhanced UI for decision point configuration. ```vue ``` ### 4. ApiNodeConfiguration.vue The API Node Configuration component provides a stepped interface for configuring API calls. ```vue ``` ### 5. FormNodeConfiguration.vue The Form Node Configuration component provides a comprehensive 3-step interface for configuring form interactions with enhanced data mapping and conditional field behavior. #### Architecture Overview ```vue ``` #### Script Implementation ```javascript ``` #### Key Features 1. **3-Step Configuration Workflow**: - **Step 1**: Form selection with integrated FormSelector component - **Step 2**: Bidirectional data mapping between process variables and form fields - **Step 3**: Dynamic field conditions for runtime form behavior 2. **Input/Output Mappings**: - **Input Mappings**: Map process variables to form fields for pre-filling - **Output Mappings**: Capture form submission data in process variables - **Auto-Variable Creation**: Automatically create process variables from form fields - **FormKit Integration**: Seamless dropdown selection with proper v-model binding 3. **Field Conditions**: - **Conditional Logic**: Support for 9 different operators (equals, contains, greater than, etc.) - **Multiple Actions**: readonly, hide, show, required, optional, enable - **Process Variable Integration**: Conditions based on current process state - **Real-time Updates**: Dynamic form behavior during process execution 4. **Data Persistence**: - **Deep Copying**: Proper reactivity management to prevent data corruption - **Explicit Save**: Manual save mechanism with `saveAllChanges()` function exposed via `defineExpose` - **Change Tracking**: Reliable change detection and persistence 5. **API Integration**: - **Form Field Loading**: Dynamic loading of form fields via `/api/forms/{formId}/fields` - **Error Handling**: Comprehensive error handling for API failures - **Loading States**: Proper loading state management #### Component Integration The FormNodeConfiguration component integrates with: - **FormSelector.vue**: For form selection and browsing - **VariableStore**: For process variable management and creation - **FormNodeConfigurationModal.vue**: Modal wrapper with save/cancel functionality - **ProcessBuilder**: Main process builder integration #### Data Flow ``` 1. User selects form → handleFormSelection() → loadFormFields() → Update localNodeData 2. User adds mappings → addInputMapping()/addOutputMapping() → Update arrays → saveChanges() 3. User configures conditions → addFieldCondition() → Update conditions array → saveChanges() 4. User clicks Save → FormNodeConfigurationModal calls saveAllChanges() → emit('update', data) 5. Parent receives update → Process node data is persisted ``` This architecture ensures reliable data persistence, proper reactivity management, and seamless integration with the broader process builder system. ## State Management The project uses Pinia for state management. Key stores include: ### processBuilder.js Enhanced with Settings Management The Process Builder store has been enhanced to handle comprehensive process settings: ```javascript export const useProcessBuilderStore = defineStore('processBuilder', { state: () => ({ processes: [], currentProcess: null, selectedNodeId: null, selectedEdgeId: null, history: [], historyIndex: -1, unsavedChanges: false }), actions: { /** * Update the current process with new data including settings */ updateCurrentProcess(processUpdates) { if (!this.currentProcess) return; this.currentProcess = { ...this.currentProcess, ...processUpdates, updatedAt: new Date().toISOString() }; this.unsavedChanges = true; this.saveToHistory('Update process settings'); }, /** * Enhanced save process with settings persistence */ async saveProcess() { if (!this.currentProcess) return; try { // Save process data including all settings const processData = { ...this.currentProcess, variables: useVariableStore().getAllVariables.process, // Settings are now part of the process object structure settings: this.currentProcess.settings || {} }; // TODO: Implement API call to save process with settings const index = this.processes.findIndex(p => p.id === this.currentProcess.id); if (index !== -1) { this.processes[index] = processData; } else { this.processes.push(processData); } this.unsavedChanges = false; return true; } catch (error) { console.error('Error saving process:', error); return false; } } } }); ``` ### Process Settings Data Structure The enhanced process object now includes comprehensive settings: ```typescript interface ProcessSettings { // Process Info priority: 'low' | 'normal' | 'high' | 'critical'; category: string; owner: string; // Execution Settings processType: 'standard' | 'approval' | 'data_collection' | 'automation' | 'review'; maxExecutionTime: number; // minutes autoTimeout: number; // hours allowParallel: boolean; enableErrorRecovery: boolean; sendNotifications: boolean; // Data & Variables dataPersistence: 'session' | 'temporary' | 'short_term' | 'long_term' | 'permanent'; logVariableChanges: boolean; encryptSensitiveData: boolean; dataRetentionPolicy: string; // Permissions executionPermission: 'public' | 'authenticated' | 'roles' | 'managers' | 'admin'; allowedRoles: string; modificationPermission: 'owner' | 'managers' | 'admin' | 'editors'; requireApproval: boolean; enableAuditTrail: boolean; } interface EnhancedProcess { id: string; name: string; description: string; nodes: ProcessNode[]; edges: ProcessEdge[]; variables: Record; settings: ProcessSettings; createdAt: string; updatedAt: string; } ``` ## Process Settings Implementation ### ProcessSettingsModal.vue Component Architecture The Process Settings modal is implemented as a comprehensive tabbed interface: ```vue ``` ### JSON Export Functionality The JSON export feature provides comprehensive process configuration export: ```javascript // Complete export data structure const formattedJson = computed(() => { const exportData = { processInfo: { id: localProcess.value.id, name: localProcess.value.name, description: localProcess.value.description, priority: localProcess.value.priority, category: localProcess.value.category, owner: localProcess.value.owner }, settings: { processType: localProcess.value.processType, maxExecutionTime: localProcess.value.maxExecutionTime, autoTimeout: localProcess.value.autoTimeout, allowParallel: localProcess.value.allowParallel, enableErrorRecovery: localProcess.value.enableErrorRecovery, sendNotifications: localProcess.value.sendNotifications }, dataSettings: { dataPersistence: localProcess.value.dataPersistence, logVariableChanges: localProcess.value.logVariableChanges, encryptSensitiveData: localProcess.value.encryptSensitiveData, dataRetentionPolicy: localProcess.value.dataRetentionPolicy }, permissions: { executionPermission: localProcess.value.executionPermission, allowedRoles: localProcess.value.allowedRoles, modificationPermission: localProcess.value.modificationPermission, requireApproval: localProcess.value.requireApproval, enableAuditTrail: localProcess.value.enableAuditTrail }, workflow: { nodes: processStore.currentProcess?.nodes || [], edges: processStore.currentProcess?.edges || [] }, variables: variableStore.getAllVariables, metadata: { nodeCount: nodeCount.value, edgeCount: edgeCount.value, variableCount: variableCount.value, exportedAt: new Date().toISOString() } } return JSON.stringify(exportData, null, 2) }) // Export functions const copyToClipboard = async () => { try { await navigator.clipboard.writeText(formattedJson.value) console.log('JSON copied to clipboard') } catch (err) { console.error('Failed to copy JSON:', err) } } const downloadJson = () => { const blob = new Blob([formattedJson.value], { type: 'application/json' }) const url = URL.createObjectURL(blob) const a = document.createElement('a') a.href = url a.download = `${localProcess.value.name || 'process'}_settings.json` document.body.appendChild(a) a.click() document.body.removeChild(a) URL.revokeObjectURL(url) } ``` ### Integration with Process Builder The Process Settings modal is integrated into the main Process Builder interface: ```vue ``` ### API Integration Considerations For future API integration, the settings should be handled as follows: ```javascript // API endpoint structure for process settings POST /api/processes/{processId}/settings PUT /api/processes/{processId}/settings GET /api/processes/{processId}/settings // Request/Response format { "processInfo": { "name": "Customer Onboarding", "description": "Complete customer onboarding workflow", "priority": "high", "category": "Sales", "owner": "Sales Manager" }, "settings": { "processType": "approval", "maxExecutionTime": 480, "autoTimeout": 48, "allowParallel": true, "enableErrorRecovery": true, "sendNotifications": true }, "dataSettings": { "dataPersistence": "long_term", "logVariableChanges": true, "encryptSensitiveData": false, "dataRetentionPolicy": "Delete after 30 days" }, "permissions": { "executionPermission": "roles", "allowedRoles": "hr_manager,department_head", "modificationPermission": "managers", "requireApproval": true, "enableAuditTrail": true } } ``` ### Performance Considerations 1. **Lazy Loading**: Settings are only loaded when the modal is opened 2. **Local State Management**: Changes are made to local copies to avoid unnecessary reactivity 3. **Debounced Updates**: Consider debouncing settings updates for better performance 4. **Validation**: Client-side validation before API calls ### Security Considerations 1. **Permission Validation**: Server-side validation of permission changes 2. **Audit Trail**: All settings changes should be logged 3. **Role Verification**: Verify user permissions before allowing settings modifications 4. **Data Encryption**: Implement proper encryption for sensitive settings ### variableStore.js ```javascript import { defineStore } from 'pinia'; export const useVariableStore = defineStore('variables', { state: () => ({ variables: { global: [], local: {} } }), getters: { getAllVariables: (state) => state.variables, getVariableByName: (state) => (name, scope = 'global') => { if (scope === 'global') { return state.variables.global.find(v => v.name === name); } else { return state.variables.local[scope]?.find(v => v.name === name); } } }, actions: { addVariable(variable) { const { scope = 'global' } = variable; if (scope === 'global') { this.variables.global.push(variable); } else { if (!this.variables.local[scope]) { this.variables.local[scope] = []; } this.variables.local[scope].push(variable); } }, updateVariable(name, updatedVariable, scope = 'global') { if (scope === 'global') { const index = this.variables.global.findIndex(v => v.name === name); if (index !== -1) { this.variables.global[index] = { ...updatedVariable }; } } else { if (this.variables.local[scope]) { const index = this.variables.local[scope].findIndex(v => v.name === name); if (index !== -1) { this.variables.local[scope][index] = { ...updatedVariable }; } } } }, deleteVariable(name, scope = 'global') { if (scope === 'global') { this.variables.global = this.variables.global.filter(v => v.name !== name); } else if (this.variables.local[scope]) { this.variables.local[scope] = this.variables.local[scope].filter(v => v.name !== name); } } } }); ``` ## UI Component Styling The project uses Tailwind CSS for styling with consistent patterns: ### Color Theming by Component Type Each node type has a consistent color theme: - **Business Rules**: Purple - **API Tasks**: Indigo - **Form Tasks**: Emerald - **Decision Points**: Orange - **Variables**: Blue ### Common Visual Elements 1. **Modal Headers**: ```html

{Title}

{Description}

``` 2. **Step Indicators**: ```html
``` 3. **Empty States**: ```html

{Empty State Title}

{Empty State Description}

{Action Text}
``` ## Best Practices for Development When developing new components or enhancing existing ones: 1. **Consistent Design Pattern**: - Follow the established design patterns for node configurations - Use the same structure for headers, step indicators, and action buttons - Maintain the color coding system for different node types 2. **Responsive Components**: - Ensure all components work on various screen sizes - Use responsive utilities from Tailwind - Test on mobile and desktop views 3. **State Management**: - Store node configuration in the appropriate Pinia store - Use reactive Vue 3 patterns with `ref`, `computed`, etc. - Implement proper validation before saving 4. **Accessibility**: - Ensure all UI elements are keyboard accessible - Use semantic HTML elements - Maintain proper focus management in modals 5. **Data Flow Visualization**: - Use visual indicators to show data flow direction - Provide clear feedback on how variables are used - Highlight connections between nodes --- For user documentation and usage guidelines, please refer to [Process Builder Documentation](USER_GUIDE.md). Last updated: December 2024