# Vue Flow Custom Nodes Migration Guide

## 🎯 Problem Solved
Custom nodes defined inline (using template strings or object definitions) **do not load in production** with Vue Flow. The solution is to use **separate .vue component files** that are properly imported.

## ✅ Production-Safe Approach: File-Based Custom Nodes

### 1. Create Separate .vue Files for Each Node Type

Instead of defining nodes inline in `composables/processFlowNodes.js`, create individual `.vue` files:

```
components/process-flow/custom/
├── StartNode.vue
├── FormNode.vue  
├── EndNode.vue
├── ConditionalNode.vue
├── ScriptNode.vue
├── ApiNode.vue
├── NotificationNode.vue
└── ... (other node types)
```

### 2. Standard Vue Component Structure

Each node component should follow this pattern:

```vue
<script setup>
import { Handle, Position } from '@vue-flow/core'

// Define props that Vue Flow passes to custom nodes
const props = defineProps([
  'id',           // Node ID
  'type',         // Node type
  'label',        // Node label
  'selected',     // Selection state
  'data'          // Custom data object
])
</script>

<template>
  <div class="custom-node" :class="{ selected }">
    <!-- Input handle (if needed) -->
    <Handle
      type="target"
      :position="Position.Left"
      class="node-handle"
    />
    
    <!-- Node content -->
    <div class="node-content">
      <div class="node-icon">🚀</div>
      <div class="node-label">{{ data?.label || label || 'Default Label' }}</div>
    </div>
    
    <!-- Output handle (if needed) -->
    <Handle
      type="source"
      :position="Position.Right"
      class="node-handle"
    />
  </div>
</template>

<style scoped>
/* Component-specific styles */
.custom-node {
  border-radius: 8px;
  padding: 12px;
  background: linear-gradient(135deg, #10b981, #059669);
  color: white;
  border: 2px solid #047857;
  min-width: 120px;
}

.custom-node.selected {
  border-color: #fbbf24;
  box-shadow: 0 0 0 3px rgba(251, 191, 36, 0.3);
}
</style>
```

### 3. Import Components in Your Main File

In `pages/process-builder/index.vue`:

```javascript
// Import all custom node components
import StartNode from "~/components/process-flow/custom/StartNode.vue"
import FormNode from "~/components/process-flow/custom/FormNode.vue"
import EndNode from "~/components/process-flow/custom/EndNode.vue"
import ConditionalNode from "~/components/process-flow/custom/ConditionalNode.vue"
import ScriptNode from "~/components/process-flow/custom/ScriptNode.vue"
import ApiNode from "~/components/process-flow/custom/ApiNode.vue"
import NotificationNode from "~/components/process-flow/custom/NotificationNode.vue"
// ... import other nodes
```

### 4. Create nodeTypes Object

```javascript
import { markRaw } from 'vue'

// Map node types to components (use markRaw to prevent reactivity issues)
const nodeTypes = {
  'start': markRaw(StartNode),
  'form': markRaw(FormNode),
  'end': markRaw(EndNode),
  'conditional': markRaw(ConditionalNode),
  'script': markRaw(ScriptNode),
  'api': markRaw(ApiNode),
  'notification': markRaw(NotificationNode),
  // ... other node types
}
```

### 5. Use nodeTypes in VueFlow Component

```vue
<template>
  <VueFlow
    v-model:nodes="nodes"
    v-model:edges="edges"
    :node-types="nodeTypes"
    @error="handleVueFlowError"
  >
    <Background />
    <Controls />
  </VueFlow>
</template>
```

## 🚫 What NOT to Use (Breaks in Production)

### ❌ Template Slots Approach
```vue
<!-- This breaks in production -->
<VueFlow v-model:nodes="nodes" v-model:edges="edges">
  <template #node-start="{ data, label }">
    <div class="start-node">{{ label }}</div>
  </template>
</VueFlow>
```

### ❌ Inline Object Definitions
```javascript
// This breaks in production
const nodeTypes = {
  'start': {
    props: ['id', 'data'],
    template: `<div>{{ data.label }}</div>`
  }
}
```

## 📋 Migration Checklist

### Current State Analysis
- [ ] Review `composables/processFlowNodes.js` for all node type definitions
- [ ] Identify unique node types used in your process builder
- [ ] Note any complex computed properties or methods in existing nodes

### Migration Steps
1. [ ] Create individual `.vue` files for each node type in `components/process-flow/custom/`
2. [ ] Convert existing node logic from `processFlowNodes.js` to Vue component format
3. [ ] Import all node components in main process builder file
4. [ ] Create `nodeTypes` object mapping types to components with `markRaw`
5. [ ] Update VueFlow component to use `:node-types` prop instead of template slots
6. [ ] Remove old `processFlowNodes.js` file
7. [ ] Test all node types render correctly
8. [ ] Test in production environment

### Key Node Types to Migrate
Based on your `processFlowNodes.js`, you have these node types:
- `start` - Start nodes
- `form` - Form nodes  
- `end` - End nodes
- `conditional` - Conditional/gateway nodes
- `script` - Script execution nodes
- `api` - API call nodes
- `notification` - Notification nodes
- `subprocess` - Subprocess nodes
- Various shape nodes (rectangle, circle, diamond, etc.)

## 🔧 Common Patterns for Migration

### Computed Properties
Convert computed properties from options API to composition API:

```javascript
// OLD (in processFlowNodes.js)
computed: {
  nodeLabel() {
    return this.data?.label || 'Default'
  }
}

// NEW (in .vue component)
const nodeLabel = computed(() => {
  return props.data?.label || 'Default'
})
```

### Event Handlers
```javascript
// OLD
methods: {
  onClick() {
    this.$emit('node-click', this.id)
  }
}

// NEW
const emit = defineEmits(['node-click'])
const onClick = () => {
  emit('node-click', props.id)
}
```

### Complex Node Logic
For nodes with complex logic (like ConditionalNode), maintain the same patterns but convert to composition API:

```vue
<script setup>
import { computed } from 'vue'
import { Handle, Position } from '@vue-flow/core'

const props = defineProps(['id', 'type', 'data', 'selected'])

const totalConditions = computed(() => {
  return props.data?.conditions?.length || 0
})

const conditionSummary = computed(() => {
  if (totalConditions.value === 0) return 'No conditions'
  return `${totalConditions.value} condition${totalConditions.value > 1 ? 's' : ''}`
})
</script>
```

## 🚀 Benefits of File-Based Approach

1. **Production Compatibility** - Works reliably in all environments
2. **Better Performance** - Proper component compilation and tree-shaking
3. **Developer Experience** - Full IDE support, syntax highlighting, linting
4. **Maintainability** - Separate files are easier to manage and debug
5. **Reusability** - Components can be imported and used elsewhere
6. **Scoped Styles** - No CSS conflicts between node types

## 🐛 Debugging Tips

### Error Handling
Add error handling to catch Vue Flow issues:

```javascript
const handleVueFlowError = (error) => {
  console.error('Vue Flow Error:', error)
  if (isErrorOfType(error, ErrorCode.MISSING_VIEWPORT_DIMENSIONS)) {
    console.error('Container needs explicit width/height')
  }
}
```

### Node ID Conflicts
Ensure all node IDs are unique across your application to prevent rendering conflicts.

## 📁 File Structure After Migration

```
components/process-flow/custom/
├── StartNode.vue
├── FormNode.vue
├── EndNode.vue
├── ConditionalNode.vue
├── ScriptNode.vue
├── ApiNode.vue
├── NotificationNode.vue
├── SubprocessNode.vue
├── RectangleShapeNode.vue
├── CircleShapeNode.vue
├── DiamondShapeNode.vue
├── TriangleShapeNode.vue
├── PentagonShapeNode.vue
├── HexagonShapeNode.vue
└── OctagonShapeNode.vue

pages/process-builder/
└── index.vue (updated to import and use file-based nodes)

# Remove after migration:
composables/processFlowNodes.js ❌
```

---

## 🎯 Ready to Migrate?

When you're ready to start the migration, provide:
1. Your current `pages/process-builder/index.vue` file
2. Your current `composables/processFlowNodes.js` file
3. Any specific node types you want to prioritize

The assistant will help you convert each node type to the production-safe file-based approach! 🚀 