Files
CGW-Quote-Builder/planning/VISUAL_NAVIGATION_EDITOR.md
T
2026-04-11 00:04:09 -05:00

2529 lines
80 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Visual Navigation Editor for navigation.json
## Concept Overview
A drag-and-drop visual interface for creating and editing the navigation flow, similar to Talend's workflow editor. This would replace manual JSON editing with an intuitive node-based editor.
## Similar Systems & Industry Parallels
This visual navigation editor concept follows proven patterns from industrial automation and visual programming tools:
### **Node-RED** (Industrial IoT & Automation)
- Flow-based programming for IoT devices and industrial automation
- Drag-and-drop nodes with input/output connections
- **Sub-flows**: Reusable flow components that can be nested and shared
- Used in manufacturing, building automation, industrial control systems
- **Key Feature**: Double-click sub-flow to drill down and edit internal logic
### **LabVIEW** (National Instruments - Industrial Control)
- Visual programming for measurement and control systems
- **SubVIs**: Reusable virtual instruments (similar to functions/methods)
- Used in aerospace, automotive testing, manufacturing quality control
- Hierarchical design: Complex systems broken into manageable sub-components
- **Key Feature**: Icon view shows high-level, double-click to edit internal diagram
### **PLC Ladder Logic** (Industrial Machine Control)
- Visual programming for Programmable Logic Controllers
- **Function Blocks**: Reusable logic blocks for common operations
- Used in factory automation, assembly lines, industrial machinery
- Modular design allows sharing common patterns across machines
### **Unreal Engine Blueprints** (Game Development)
- Visual scripting for game logic
- **Blueprint Functions/Macros**: Reusable logic components
- **Collapse to Function**: Select nodes, create reusable component
- Used by game developers worldwide for complex interactive systems
### **Power Automate / Microsoft Flow** (Business Process Automation)
- No-code workflow automation
- Visual flow designer with connectors and conditions
- Used for business process automation in enterprises
### **Why This Pattern Works**
- **Visual Clarity**: See the entire flow at a glance
- **Complexity Management**: Nest/collapse to manage large systems
- **Reusability**: Build once, use everywhere
- **Collaboration**: Team members can understand and contribute
- **Lower Barrier**: Non-programmers can build complex logic
Your navigation editor would bring these industrial-strength patterns to product configuration workflows!
---
## 🏗️ Foundational Architecture: Component-Based Rendering System
### Overview
The navigation system will use a **component-based architecture** where each question node contains an ordered array of components that render sequentially from top to bottom. This replaces the current type-based system (`inputType: "button"` vs `inputType: "form"`) with a more flexible, composable approach.
### Key Principle
**Components set variables, navigation controls flow.**
- **Toggle/Field components**: Set variables in the application state
- **Navigation components**: Control which page appears next
- **Notes/Separator components**: Provide information and visual structure
Components can be combined in any order, allowing for maximum flexibility without mixing concerns (e.g., navigation buttons remain separate from data input controls).
### Current System vs. Component-Based System
#### Current System (Limited)
```json
{
"q-door-type": {
"type": "question",
"inputType": "button", // ← Only navigation OR only form
"title": "What type of door?",
"answers": [...]
},
"q-dimensions": {
"type": "question",
"inputType": "form", // ← Can't mix with navigation
"measurementType": {...},
"fields": [...]
}
}
```
**Limitations:**
- `inputType: "button"` = Only navigation buttons
- `inputType: "form"` = Only input fields (no navigation buttons)
- Can't have multiple toggle groups
- Navigation always at bottom
- Hard to add new input types
#### Component-Based System (Flexible)
```json
{
"q-configure-door": {
"type": "question",
"title": "Configure Your Door",
"subtitle": "Set your preferences and continue",
"components": [
{
"type": "toggle",
"variable": "includeHardware",
"label": "Include Hardware?",
"options": [
{ "value": "yes", "label": "Yes", "default": true },
{ "value": "no", "label": "No" }
]
},
{
"type": "fields",
"label": "Installation Details",
"fields": [
{ "name": "installDate", "label": "Preferred Installation Date", "type": "date" },
{ "name": "notes", "label": "Special Instructions", "type": "text", "optional": true }
]
},
{
"type": "toggle",
"variable": "measurementType",
"label": "Measurement Type",
"options": [
{ "value": "opening-size", "label": "Opening Size", "icon": "📏", "default": true },
{ "value": "tip-to-tip", "label": "Tip-to-tip", "icon": "📏" }
]
},
{
"type": "fields",
"fields": [
{ "name": "width", "label": "Width (inches)", "type": "number", "required": true },
{ "name": "height", "label": "Height (inches)", "type": "number", "required": true }
]
},
{
"type": "navigation",
"answers": [
{ "caption": "Continue", "next": "results", "primary": true },
{ "caption": "Skip Optional Settings", "next": "q-accessories" }
]
},
{
"type": "notes",
"content": "<p><strong>Tip:</strong> For accurate measurements, refer to our <a href='#'>measuring guide</a>.</p>"
}
]
}
}
```
**Advantages:**
- ✅ Mix any components in any order
- ✅ Multiple toggle groups in same question
- ✅ Multiple field groups in same question
- ✅ Navigation can be anywhere (top, middle, bottom)
- ✅ Easy to add new component types
- ✅ Clean separation of concerns
- ✅ Editor-friendly (drag components to reorder)
### Component Type Reference
#### 1. **Toggle Component**
Sets a variable by presenting mutually exclusive options (radio button style).
```json
{
"type": "toggle",
"variable": "rushOrder",
"label": "Rush Order?",
"options": [
{ "value": "yes", "label": "Rush (3-5 days)", "icon": "⚡", "default": false },
{ "value": "no", "label": "Standard (2-3 weeks)", "icon": "📦", "default": true }
]
}
```
**Properties:**
- `variable` (string, required): Variable name to store selection
- `label` (string, optional): Section heading
- `options` (array, required): Available choices
- `value`: Stored value
- `label`: Display text
- `icon`: Optional emoji/icon
- `default`: Whether this is the default selection
- `disabled`: Whether this option is disabled
#### 2. **Fields Component**
Group of input fields for collecting user data.
```json
{
"type": "fields",
"label": "Product Dimensions",
"fields": [
{
"name": "width",
"label": "Width (inches)",
"type": "number",
"required": true,
"min": 12,
"max": 120,
"placeholder": "26"
},
{
"name": "height",
"label": "Height (inches)",
"type": "number",
"required": true,
"placeholder": "81"
}
]
}
```
**Properties:**
- `label` (string, optional): Group heading
- `fields` (array, required): Input fields
- `name`: Variable name
- `label`: Field label
- `type`: Input type (text, number, date, email, tel, textarea)
- `required`: Whether field is required
- `placeholder`: Placeholder text
- `min`, `max`: Constraints for number/date fields
- `pattern`: Regex validation pattern
#### 3. **Navigation Component**
Navigation buttons to control flow to next question/page.
```json
{
"type": "navigation",
"answers": [
{
"caption": "Continue",
"next": "results",
"primary": true,
"filter": { "configComplete": true }
},
{
"caption": "Add Accessories",
"next": "q-accessories"
},
{
"caption": "Start Over",
"next": "start",
"style": "secondary"
}
]
}
```
**Properties:**
- `answers` (array, required): Navigation buttons
- `caption`: Button text (can include HTML)
- `image`: Optional icon/emoji
- `next`: Target question ID
- `primary`: Style as primary action button
- `style`: Button style (primary, secondary, danger)
- `filter`: Filter object to apply on click
- `dimensions`: Dimension object to set on click
#### 4. **Notes Component**
Static informational content (tips, instructions, links).
```json
{
"type": "notes",
"content": "<p><strong>How to Measure:</strong></p><ul><li>Measure the rough opening</li><li>Round down to nearest inch</li></ul>",
"style": "info"
}
```
**Properties:**
- `content` (string, required): HTML content
- `style` (string, optional): Visual style (info, warning, tip, default)
#### 5. **Separator Component** (Optional)
Visual divider between sections.
```json
{
"type": "separator",
"style": "line"
}
```
**Properties:**
- `style`: Separator style (line, space, none)
### Rendering Order Example
```
┌─────────────────────────────────────────┐
│ Configure Your Door │ ← Title/Subtitle
├─────────────────────────────────────────┤
│ Include Hardware? │
│ ● Yes ○ No │ ← Toggle Component #1
├─────────────────────────────────────────┤
│ Installation Details │
│ [Preferred Installation Date: ____] │
│ [Special Instructions: _________] │ ← Fields Component #1
├─────────────────────────────────────────┤
│ Measurement Type │
│ ● Opening Size ○ Tip-to-tip │ ← Toggle Component #2
├─────────────────────────────────────────┤
│ Width (inches): [____] │
│ Height (inches): [____] │ ← Fields Component #2
├─────────────────────────────────────────┤
│ [Continue] [Add Accessories] │ ← Navigation Component
├─────────────────────────────────────────┤
│ 💡 Tip: For accurate measurements... │ ← Notes Component
└─────────────────────────────────────────┘
```
### Rendering Logic Implementation
```javascript
function renderQuestion(questionData) {
// Render title/subtitle
renderHeader(questionData.title, questionData.subtitle);
// Iterate through components array
questionData.components.forEach((component, index) => {
const container = document.createElement('div');
container.className = `component component-${component.type}`;
container.dataset.componentIndex = index;
switch(component.type) {
case 'toggle':
renderToggleComponent(container, component);
break;
case 'fields':
renderFieldsComponent(container, component);
break;
case 'navigation':
renderNavigationComponent(container, component);
break;
case 'notes':
renderNotesComponent(container, component);
break;
case 'separator':
renderSeparatorComponent(container, component);
break;
default:
console.warn(`Unknown component type: ${component.type}`);
}
document.getElementById('question-container').appendChild(container);
});
}
function handleFormSubmit(questionData) {
const variables = {};
// Collect all variable values from toggle and field components
questionData.components.forEach(component => {
if (component.type === 'toggle') {
const selected = document.querySelector(`input[name="${component.variable}"]:checked`);
variables[component.variable] = selected ? selected.value : null;
}
if (component.type === 'fields') {
component.fields.forEach(field => {
const input = document.querySelector(`[name="${field.name}"]`);
variables[field.name] = input ? input.value : null;
});
}
});
// Validate all required fields
if (!validateComponents(questionData.components)) {
return false;
}
// Save variables to userAnswers
Object.assign(userAnswers, variables);
// Navigation is handled by navigation component button clicks
return true;
}
```
### Migration Path from Current System
To maintain backwards compatibility during transition:
1. **Phase 1: Dual Support** - Support both old and new formats
2. **Phase 2: Auto-conversion** - Auto-convert old format to components on load
3. **Phase 3: Deprecation** - Remove old format support
```javascript
function normalizeQuestion(questionData) {
// If already using components, return as-is
if (questionData.components) {
return questionData;
}
// Auto-convert old format to components
const components = [];
if (questionData.inputType === 'button') {
// Convert to navigation component
components.push({
type: 'navigation',
answers: questionData.answers
});
}
if (questionData.inputType === 'form') {
// Convert measurementType to toggle component
if (questionData.measurementType) {
components.push({
type: 'toggle',
variable: 'measurementType',
options: questionData.measurementType.options
});
}
// Convert fields to fields component
if (questionData.fields) {
components.push({
type: 'fields',
fields: questionData.fields
});
}
// Add navigation if next exists
if (questionData.next) {
components.push({
type: 'navigation',
answers: [
{ caption: 'Continue', next: questionData.next }
]
});
}
}
// Add notes component if notes exist
if (questionData.notes) {
components.push({
type: 'notes',
content: questionData.notes
});
}
return {
...questionData,
components
};
}
```
### Benefits for Visual Editor
This component-based architecture makes the visual editor **dramatically simpler** to implement:
#### **Component Palette**
Drag components from palette onto canvas:
- 🎚️ Toggle
- 📝 Fields
- 🔗 Navigation
- 📄 Notes
- Separator
#### **Component List View**
Within each tile, show reorderable list of components:
```
📋 Configure Door
🎚️ Toggle: Include Hardware?
📝 Fields: Installation Details (2 fields)
🎚️ Toggle: Measurement Type
📝 Fields: Dimensions (2 fields)
🔗 Navigation: 2 buttons
📄 Notes: Measuring tip
[+ Add Component]
```
#### **Drag to Reorder**
Users can drag components up/down within the list to change render order.
#### **Click to Configure**
Clicking a component opens the config panel with type-specific options.
#### **Editor UI Mockup**
```
┌─────────────────────────────────────────────────────────────────┐
│ Component Palette │
│ ┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ │
│ │🎚️ │ │📝 │ │🔗 │ │📄 │ │➖ │ │
│ └────┘ └────┘ └────┘ └────┘ └────┘ │
├─────────────────────────────────────────────────────────────────┤
│ Selected Tile: q-configure-door │
│ │
│ ┌─────────────────────────────────────────────┐ │
│ │ 🎚️ Toggle: Include Hardware? [↑][↓] │ │
│ │ 📝 Fields: Installation Details [↑][↓] │ │
│ │ 🎚️ Toggle: Measurement Type [↑][↓] │ │
│ │ 📝 Fields: Dimensions [↑][↓] │ ┌────────┐ │
│ │ 🔗 Navigation: 2 buttons [↑][↓] │ │ Config │ │
│ │ 📄 Notes: Measuring tip [↑][↓] │ │ Panel │ │
│ │ │ │ │ │
│ │ [+ Add Component ▼] │ │ │ │
│ └─────────────────────────────────────────────┘ └────────┘ │
└─────────────────────────────────────────────────────────────────┘
```
### Implementation Considerations
**Validation:**
- Ensure at least one navigation component exists in reachable nodes
- Validate variable naming (no conflicts)
- Ensure required fields are marked
**State Management:**
- All variables collected before navigation
- Variables persist across question navigation
- Can reference previous answers in conditional logic
**Extensibility:**
- Easy to add new component types (checkbox group, radio group, slider, datepicker, file upload, etc.)
- Plugin architecture for custom components
- Community-contributed component library
**Editor Features:**
- Duplicate component
- Copy/paste components between tiles
- Component templates/presets
- Import component from library
---
## UI Layout
### Two-Panel Design
#### Panel 1: Canvas/Drop Area (Left/Main Panel)
- **Drag-and-drop workspace** where navigation nodes (tiles) can be moved around
- **Tiles/Nodes** represent each question/step in the navigation
- **Connection arrows** show the flow between steps
- **Colored circles** (connection points) on tiles indicate multiple possible outputs
- Number of circles determined by configuration (buttons, alternatives, etc.)
- Circles appear when tile is selected
- Different colors for different types of connections
- **Grid/snap system** for clean alignment
- **Zoom and pan** controls for large navigation flows
- **Minimap** for overview of complex flows
#### Panel 2: Configuration Panel (Right/Sidebar)
- **Tile Properties** editor (activated when a tile is selected)
- **Dynamic form fields** based on question type:
- Question ID, title, subtitle
- Question type selector (buttons, dimensions, multi-select, etc.)
- Type-specific options (button labels, icons, validation, etc.)
- **Output/Connection Groups** section:
- Group buttons together that share the same output path
- Add/remove connection groups
- Each group maps to a colored circle on the tile
- Default output selection (for ungrouped actions)
- **Default Values** section:
- List of variable assignments
- Each row: `[Variable Dropdown] : [Value Field] [Remove Button]`
- `[Add Another]` button to create new default assignments
- **Validation** section for input requirements
- **Conditional Logic** editor for complex routing
## Features
### Node/Tile Management
- **Visual representation** of each navigation step
- Title displayed on tile
- Icon/badge showing question type
- Color coding by category
- **Multiple outputs** via colored circles:
- Small circles appear on tile edges when selected
- Each circle represents a possible path forward
- Example: Door size question has 2 circles (predefined sizes, custom dimensions)
- **Drag and drop** positioning
- **Auto-layout** option to organize nodes cleanly
- **Duplicate node** feature for similar questions
- **Delete with confirmation** and automatic connection cleanup
### Connection System
#### Option A: Click-and-Drag (Visual)
- Click a circle on source tile
- Drag to create arrow/line
- Drop on target tile to connect
- Arrow shows direction of flow
- Hover shows connection metadata (condition, button labels)
#### Option B: Dropdown Selection (Form-based)
- Select a connection group in config panel
- Dropdown shows all available destination tiles
- Select target from list
- Visual arrow updates automatically
#### Option C: Hybrid Approach (Recommended)
- Both methods available
- Click-drag for quick visual connections
- Dropdown for precise selection or when tiles are far apart
- Arrows can be clicked to edit connection details
### Button/Output Grouping
Buttons within a tile can be grouped to share the same output:
**Example 1: Door Size Question**
- Group 1: "All predefined size buttons" → Circle 1 (blue) → Next standard question
- Group 2: "Custom dimensions button" → Circle 2 (orange) → Alternative dimension entry
- Default: Any ungrouped actions → Circle 3 (gray) → Fallback route
**Example 2: Simple Yes/No Question**
- Group 1: "Yes button" → Circle 1 → Path A
- Group 2: "No button" → Circle 2 → Path B
**Configuration UI:**
```
Output Groups:
┌─────────────────────────────────────┐
│ Group 1: Predefined Sizes │
│ Buttons: [32x80, 36x80, other...] │
│ → Connects to: [q-hinges ▼] │
│ Circle color: [🔵 Blue] │
└─────────────────────────────────────┘
┌─────────────────────────────────────┐
│ Group 2: Custom Entry │
│ Buttons: [Enter Custom] │
│ → Connects to: [q-alt-path ▼] │
│ Circle color: [🟠 Orange] │
└─────────────────────────────────────┘
┌─────────────────────────────────────┐
│ Default Output: [q-next-step ▼] │
└─────────────────────────────────────┘
```
### Default Values System
Users need to set default variable values that apply when reaching certain nodes.
**Configuration UI:**
```
Default Values to Set:
┌──────────────────────────────────────────────┐
│ [doorType ▼] : [storm door ] [✖] │
│ [measurementSystem ▼]: [imperial ] [✖] │
│ [region ▼] : [north-america ] [✖] │
└──────────────────────────────────────────────┘
[+ Add Another Default Value]
```
**Features:**
- Variable dropdown populated from:
- Previously used variables across all navigation nodes
- Manual entry option to add new variables
- Suggesting common variables based on question type
- Value field accepts:
- Static values
- References to other variables (e.g., `${previousAnswer}`)
- Expressions for calculations
- Remove button to delete a default value assignment
- Add button to create additional assignments
## Technical Implementation
### Technology Stack Options
#### Option 1: Web-Based Standalone Tool
**Frontend:**
- **React** or **Vue.js** for UI framework
- **React Flow** or **Vue Flow** for node-based canvas
- Built-in drag-drop, zoom, pan
- Customizable nodes and connections
- Good performance with large graphs
- **Tailwind CSS** or **Material-UI** for styling
- **Monaco Editor** for any direct JSON editing fallback
**Backend:**
- **Python Flask** (existing stack) with endpoints:
- `GET /api/editor/navigation` - Load current navigation.json
- `POST /api/editor/navigation` - Save edited navigation
- `GET /api/editor/validate` - Validate navigation structure
- `GET /api/editor/variables` - Get list of known variables
- File system operations to read/write navigation.json
- Validation logic to ensure navigation structure is valid
**Pros:**
- Can be integrated into existing Flask app
- Accessible from any browser
- No installation required
- Easy to share and collaborate
**Cons:**
- Requires server to be running
- Limited offline capability
#### Option 2: Desktop Application
**Framework:**
- **Electron** (JavaScript-based desktop app)
- Wrap the web-based editor
- Direct file system access
- Can bundle Python scripts
- **Tauri** (Rust-based, lighter alternative to Electron)
**Pros:**
- Better file system integration
- Can work offline
- More desktop-native experience
- Better performance
**Cons:**
- Requires installation
- More complex deployment
- Additional development effort
#### Option 3: VS Code Extension
**Framework:**
- VS Code Extension API
- Webview for the visual editor
- Language server for validation
**Pros:**
- Integrates with existing development environment
- Can use VS Code's existing features (git, etc.)
- Access to VS Code extension marketplace
- Syntax highlighting fallback to JSON
**Cons:**
- Limited to VS Code users
- Extension development learning curve
- More restrictive UI capabilities
### Recommended Approach: Web-Based (Option 1)
Most practical for this project given the existing Flask infrastructure.
## Implementation Phases
### Phase 1: Core Canvas (MVP)
**Goals:**
- Display existing navigation.json as visual nodes
- Basic drag-and-drop positioning
- Simple click-to-select nodes
- Read-only view to validate the concept
**Deliverables:**
- Canvas component with nodes
- JSON parser to convert navigation.json to node graph
- Basic visual styling for nodes
**Estimated Effort:** 20-30 hours
### Phase 2: Basic Editing
**Goals:**
- Configuration panel for editing node properties
- Add/delete nodes
- Simple one-to-one connections
- Save back to navigation.json
**Deliverables:**
- Config panel UI
- Node CRUD operations
- JSON serializer to convert graph back to navigation.json
- Save functionality
**Estimated Effort:** 30-40 hours
### Phase 3: Advanced Connections
**Goals:**
- Multiple output circles per node
- Button grouping system
- Visual connection management (drag-drop arrows)
- Connection validation
**Deliverables:**
- Output group configuration UI
- Connection point rendering
- Arrow drawing and management
- Validation logic
**Estimated Effort:** 25-35 hours
### Phase 4: Default Values & Variables
**Goals:**
- Default values configuration section
- Variable management system
- Variable autocomplete/suggestions
**Deliverables:**
- Default values UI
- Variable tracking system
- Smart suggestions
**Estimated Effort:** 15-20 hours
### Phase 5: Polish & Features
**Goals:**
- Auto-layout algorithm
- Zoom/pan controls
- Minimap
- Undo/redo
- Export/import
- Validation reporting
- Help tooltips
**Deliverables:**
- All polish features
- Documentation
- User guide
**Estimated Effort:** 20-30 hours
**Total Estimated Effort:** 110-155 hours (3-4 weeks full-time development)
## Data Structure Mapping
### Current navigation.json Structure (Runtime Format)
```json
{
"start": {
"type": "question",
"inputType": "button",
"title": "What are you looking for?",
"subtitle": "Select the product category",
"answers": [
{
"caption": "Door",
"image": "🚪",
"next": "q-door-type",
"filter": { "baseType": "Door" }
},
{
"caption": "Window",
"image": "🪟",
"next": "q-window-type",
"filter": { "baseType": "Window" }
}
]
},
"q-door-type": {
"type": "question",
"inputType": "button",
"title": "What type of door?",
"answers": [...]
}
}
```
### Project File Structure (Editor Format - `.navproj.json`)
The editor saves this format, which includes all visual layout and editor-specific data:
```json
{
"version": "1.0",
"metadata": {
"created": "2026-04-02",
"lastModified": "2026-04-02",
"description": "Product Finder Navigation Flow"
},
"nodes": [
{
"id": "node-1",
"tileId": "start",
"type": "NavigationTile",
"position": { "x": 100, "y": 200 },
"config": {
"type": "question",
"inputType": "button",
"title": "What are you looking for?",
"subtitle": "Select the product category",
"notes": "<p><strong>Quick Tips...</p>",
"buttons": [
{
"caption": "Door",
"image": "🚪",
"outputGroup": "output-door",
"filter": { "baseType": "Door" }
},
{
"caption": "Window",
"image": "🪟",
"outputGroup": "output-window",
"filter": { "baseType": "Window" }
}
]
},
"outputs": [
{
"id": "output-door",
"color": "#3b82f6",
"label": "Door Path",
"targetTileId": "q-door-type"
},
{
"id": "output-window",
"color": "#10b981",
"label": "Window Path",
"targetTileId": "q-window-type"
}
],
"defaults": []
}
],
"connections": [
{
"id": "conn-1",
"from": "node-1",
"fromOutput": "output-door",
"to": "node-2"
},
{
"id": "conn-2",
"from": "node-1",
"fromOutput": "output-window",
"to": "node-3"
}
],
"editorSettings": {
"zoom": 1.0,
"panX": 0,
"panY": 0,
"selectedNodeId": null
},
"customTiles": [
{
"id": "custom-size-flow",
"name": "Size Selection Flow",
"description": "Handles both standard sizes and custom dimensions",
"icon": "📏",
"version": "1.0",
"entryPoint": "node-size-entry",
"exitPoints": [
{
"id": "exit-standard",
"label": "Standard Size Selected",
"color": "#3b82f6"
},
{
"id": "exit-custom",
"label": "Custom Dimensions",
"color": "#10b981"
}
],
"nodes": [
{
"id": "node-size-entry",
"tileId": "entry",
"type": "EntryPoint",
"position": { "x": 50, "y": 150 },
"config": {},
"outputs": [
{
"id": "to-size-display",
"targetTileId": "node-size-buttons"
}
]
},
{
"id": "node-size-buttons",
"tileId": "size-options",
"type": "NavigationTile",
"position": { "x": 250, "y": 150 },
"config": {
"title": "Select Size",
"buttons": [
{
"caption": "30\" x 81\"",
"outputGroup": "standard",
"dimensions": { "width": 30, "height": 81 }
},
{
"caption": "32\" x 81\"",
"outputGroup": "standard",
"dimensions": { "width": 32, "height": 81 }
},
{
"caption": "Custom Size",
"outputGroup": "custom"
}
]
},
"outputs": [
{
"id": "standard",
"exitPoint": "exit-standard"
},
{
"id": "custom",
"targetTileId": "node-dimension-form"
}
]
},
{
"id": "node-dimension-form",
"tileId": "custom-dimensions",
"type": "FormTile",
"position": { "x": 450, "y": 250 },
"config": {
"title": "Enter Custom Dimensions",
"fields": [
{ "name": "width", "type": "number" },
{ "name": "height", "type": "number" }
]
},
"outputs": [
{
"id": "form-complete",
"exitPoint": "exit-custom"
}
]
}
],
"connections": [
{
"from": "node-size-entry",
"to": "node-size-buttons"
},
{
"from": "node-size-buttons",
"fromOutput": "custom",
"to": "node-dimension-form"
}
]
}
]
}
```
**Custom Tiles in Project File:**
- **customTiles array**: Stores all reusable sub-flows as separate entities
- **Entry/Exit Points**: Define how the custom tile interfaces with the main flow
- **Internal nodes**: Complete flow definition within the custom tile
- **Versioning**: Track custom tile versions for compatibility
- **Metadata**: Name, description, icon for library display
When a custom tile is used in the main flow:
```json
{
"id": "node-5",
"tileId": "use-size-flow",
"type": "CustomTile",
"customTileRef": "custom-size-flow", // References the custom tile
"position": { "x": 500, "y": 300 },
"outputs": [
{
"id": "standard-path",
"exitPoint": "exit-standard", // Maps to custom tile's exit
"targetTileId": "results"
},
{
"id": "custom-path",
"exitPoint": "exit-custom",
"targetTileId": "q-accessories"
}
]
}
}
```
**Key Differences:**
- **Project file** includes: positions, colors, output groups, editor state
- **Navigation file** includes: only runtime data needed by the app
- **Export process** converts project format → navigation format using class export methods
- **Import process** can convert existing navigation.json → project format
### Tile Class Architecture
Each tile type is a class with its own export logic:
```typescript
// Base class for all tiles
abstract class BaseTile {
id: string;
tileId: string;
position: Position;
config: any;
outputs: Output[];
defaults: DefaultValue[];
// Each tile type implements its own export logic
abstract export(): object;
// Validate tile configuration before export
abstract validate(): ValidationResult;
}
// Navigation tile - standard question with buttons
class NavigationTile extends BaseTile {
export(): object {
return {
type: this.config.type,
inputType: this.config.inputType,
title: this.config.title,
subtitle: this.config.subtitle,
notes: this.config.notes,
answers: this.config.buttons.map(btn => ({
caption: btn.caption,
image: btn.image,
next: this.outputs.find(o => o.id === btn.outputGroup)?.targetTileId,
filter: btn.filter,
dimensions: btn.dimensions
}))
};
}
}
// Form tile - custom input fields
class FormTile extends BaseTile {
export(): object {
return {
type: "question",
inputType: "form",
title: this.config.title,
subtitle: this.config.subtitle,
notes: this.config.notes,
measurementType: this.config.measurementType,
fields: this.config.fields,
next: this.outputs[0]?.targetTileId || "results"
};
}
}
// Results tile - terminal node
class ResultsTile extends BaseTile {
export(): object {
return {
type: "results",
title: this.config.title,
// No outputs - this is terminal
};
}
}
// Custom tile - references a reusable sub-flow
class CustomTile extends BaseTile {
customTileRef: string; // ID of custom tile definition
customTileDef: CustomTileDefinition; // Reference to the actual custom tile
export(): object {
// Custom tiles export by "flattening" their internal flow
// OR by exporting as a single node that gets expanded at runtime
// Option A: Flatten (embed internal nodes into main navigation)
// This makes the exported JSON have no "custom tile" concept
const flattened = {};
// Generate unique tile IDs for internal nodes
this.customTileDef.nodes.forEach(node => {
const uniqueId = `${this.id}_${node.tileId}`;
flattened[uniqueId] = node.export();
});
// Wire entry point to first internal node
const entryNode = this.customTileDef.entryPoint;
// Wire exit points back to main flow
return flattened;
// Option B: Keep as reference (requires app to support custom tiles)
// return {
// type: "customTile",
// ref: this.customTileRef,
// outputs: this.outputs.map(o => ({
// exitPoint: o.exitPoint,
// next: o.targetTileId
// }))
// };
}
validate(): ValidationResult {
const errors = [];
// Validate all outputs map to exit points
this.outputs.forEach(output => {
const exitExists = this.customTileDef.exitPoints.find(
ep => ep.id === output.exitPoint
);
if (!exitExists) {
errors.push(`Output references non-existent exit point: ${output.exitPoint}`);
}
});
// Validate internal flow is complete
const internalValidation = this.customTileDef.validate();
errors.push(...internalValidation.errors);
return {
valid: errors.length === 0,
errors
};
}
}
```
### Export Workflow
```typescript
class NavigationProject {
nodes: BaseTile[];
connections: Connection[];
// Export entire project to navigation.json
exportToNavigation(): object {
const navigation: any = {};
// Each node exports itself to JSON
this.nodes.forEach(node => {
navigation[node.tileId] = node.export();
});
return navigation;
}
// Import existing navigation.json to project format
static importFromNavigation(navData: object): NavigationProject {
const project = new NavigationProject();
const layout = new AutoLayout(); // Auto-position nodes
Object.entries(navData).forEach(([tileId, data], index) => {
const position = layout.getNextPosition(index);
const tile = this.createTileFromData(tileId, data, position);
project.nodes.push(tile);
});
// Reconstruct connections from 'next' references
project.reconstructConnections();
return project;
}
// Validate entire project before export
validate(): ValidationReport {
const report = new ValidationReport();
this.nodes.forEach(node => {
const result = node.validate();
if (!result.isValid) {
report.addError(node.tileId, result.errors);
}
});
// Check for orphaned nodes
const connectedNodes = new Set(
this.connections.flatMap(c => [c.from, c.to])
);
this.nodes.forEach(node => {
if (!connectedNodes.has(node.id) && node.tileId !== 'start') {
report.addWarning(node.tileId, 'Node is not connected');
}
});
return report;
}
}
```
### File Operations
```typescript
// Save project file
async function saveProject(project: NavigationProject, filepath: string) {
const projectData = {
version: "1.0",
metadata: {
created: project.metadata.created,
lastModified: new Date().toISOString(),
description: project.metadata.description
},
nodes: project.nodes.map(n => n.toJSON()),
connections: project.connections,
editorSettings: project.editorSettings
};
await fs.writeFile(filepath, JSON.stringify(projectData, null, 2));
}
// Export to navigation.json
async function exportNavigation(project: NavigationProject, filepath: string) {
// Validate first
const validation = project.validate();
if (!validation.isValid) {
throw new Error(`Validation failed: ${validation.errors.join(', ')}`);
}
// Export
const navData = project.exportToNavigation();
await fs.writeFile(filepath, JSON.stringify(navData, null, 2));
}
// Load project file
async function loadProject(filepath: string): Promise<NavigationProject> {
const data = JSON.parse(await fs.readFile(filepath, 'utf-8'));
return NavigationProject.fromJSON(data);
}
```
```
## Key Challenges & Solutions
### Challenge 1: Complex Button Grouping
**Problem:** Multiple buttons can map to different outputs, and the structure can get complex.
**Solution A: Color-Coded Output Groups** (Recommended)
- Each output path gets a unique color (suggested max ~5 colors per tile)
- User can set/choose the color for each output group
- Buttons using that output show:
- Colored rect/border around the button in the config panel
- Optional: button background tint in that color (browser support varies)
- Connection arrows from the tile use the corresponding color
- Provides immediate visual clarity for which buttons lead where
**Solution B: Per-Button Output Selector**
- Each button in the config panel has an "Output Group" dropdown near it
- Dropdown shows:
- Existing output groups (with their target tiles)
- "Add New Output" option
- Creates output circles on-demand based on unique selections
- More flexible but requires more user interactions per button
**Config Panel Structure (Type-Specific Fields):**
```
Button Type: [navigate ▼]
IF navigate:
Output Group: [🟢 Color-1: Next Step ▼] (Add New)
Target Tile: [Select Storm Door Size ▼]
Button Label: [Field]
... other options
IF toggle:
Toggle Group: [☐ Group A ☑ Group B ☐ Group C] (Add New Toggle Group)
Variable to Set: [doorType ▼]
Value or Label: [Field]
... other options
```
**Visual Representation with Colored Outputs:**
```
┌─────────────────┐
│ Door Type │
│ ┌──────────┐ │ 🟢 (Green - Predefined route)
│ │ Standard │───┼──🟢
│ │ Custom │───┼──🔵
│ │ Skip │───┼──🔴
│ └──────────┘ │ 🔵 (Blue - Custom route)
└─────────────────┘ 🔴 (Red - Skip to end)
```
### Challenge 2: Maintaining JSON Compatibility
**Problem:** The visual editor creates its own structure, but must export to the existing navigation.json format.
**Solution: Class-Based Export Architecture**
Each tile in the visual editor is a class object with an export function that generates clean JSON. This creates two separate file types:
#### 1. Project File (`.navproj.json` or similar)
Saved/loaded by the editor, contains all editor-specific data:
```json
{
"version": "1.0",
"metadata": {
"created": "2026-04-02",
"lastModified": "2026-04-02",
"author": "User"
},
"nodes": [
{
"id": "node-1",
"tileId": "start",
"type": "NavigationTile",
"position": { "x": 100, "y": 200 },
"config": {
"type": "question",
"inputType": "button",
"title": "What are you looking for?",
"subtitle": "Select the product category",
"notes": "<p><strong>Quick Tips:...</p>",
"buttons": [
{
"caption": "Door",
"image": "🚪",
"outputGroup": "output-1",
"filter": { "baseType": "Door" }
},
{
"caption": "Window",
"image": "🪟",
"outputGroup": "output-2",
"filter": { "baseType": "Window" }
}
]
},
"outputs": [
{
"id": "output-1",
"color": "#3b82f6",
"label": "Door Path",
"targetTileId": "q-door-type"
},
{
"id": "output-2",
"color": "#10b981",
"label": "Window Path",
"targetTileId": "q-window-type"
}
],
"defaults": []
}
],
"connections": [
{
"id": "conn-1",
"from": "node-1",
"fromOutput": "output-1",
"to": "node-2"
}
],
"editorSettings": {
"zoom": 1.0,
"panX": 0,
"panY": 0
}
}
```
#### 2. Export File (`navigation.json`)
Generated from project file during export, clean JSON for runtime:
```json
{
"start": {
"type": "question",
"inputType": "button",
"title": "What are you looking for?",
"subtitle": "Select the product category",
"notes": "<p><strong>Quick Tips:...</p>",
"answers": [
{
"caption": "Door",
"image": "🚪",
"next": "q-door-type",
"filter": {
"baseType": "Door"
}
},
{
"caption": "Window",
"image": "🪟",
"next": "q-window-type",
"filter": {
"baseType": "Window"
}
}
]
}
}
```
#### Export Function Example (TypeScript/JavaScript)
```typescript
class NavigationTile {
id: string;
config: TileConfig;
outputs: Output[];
// Export this tile to navigation.json format
export(): object {
const navigationNode: any = {
type: this.config.type,
inputType: this.config.inputType,
title: this.config.title,
subtitle: this.config.subtitle
};
// Add optional fields
if (this.config.notes) {
navigationNode.notes = this.config.notes;
}
// Convert buttons with output groups to answers with next references
if (this.config.buttons) {
navigationNode.answers = this.config.buttons.map(button => {
const output = this.outputs.find(o => o.id === button.outputGroup);
return {
caption: button.caption,
image: button.image,
next: output?.targetTileId || null,
filter: button.filter
};
});
}
// Add conditional logic if present
if (this.config.conditional) {
navigationNode.conditional = this.config.conditional;
}
return navigationNode;
}
// Import from navigation.json to project format
static import(tileId: string, data: any, position: Position): NavigationTile {
// Convert navigation.json format back to editor format
// ...
}
}
// Export entire project to navigation.json
function exportToNavigation(project: ProjectFile): object {
const navigation: any = {};
project.nodes.forEach(node => {
const tile = new NavigationTile(node);
navigation[node.tileId] = tile.export();
});
return navigation;
}
```
#### Benefits of This Approach:
**Separation of Concerns** - Editor data (positions, colors) separate from runtime data
**Clean Exports** - Generated navigation.json contains only what the app needs
**Version Control Friendly** - Project file can track editor-specific changes
**Validation** - Export process can validate each tile before generating JSON
**Backwards Compatible** - Can import existing navigation.json files
**Extensible** - Easy to add new tile types with their own export logic
#### Workflow:
1. **Edit Mode**: User works with project file (`.navproj.json`)
2. **Export**: Click "Export" → validates and generates `navigation.json`
3. **Import**: Can load existing `navigation.json` → converts to project format
4. **Save/Load**: Project file preserves all editor state between sessions
### Challenge 3: Large Navigation Flows & Reusability
**Problem:** Complex products might have 50+ questions, making the canvas crowded. Common patterns (size selection, color/material combos) are duplicated across flows.
**Solution: Hierarchical Sub-Flows (Custom Tiles)**
Implement a **nested flow architecture** similar to Node-RED sub-flows, LabVIEW SubVIs, or PLC function blocks used in industrial automation systems.
#### Concept: Custom Tiles
1. **Create a Sub-Flow**: Select 3-5 related tiles and group them into a reusable sub-flow
2. **Save as Custom Tile**: Name it (e.g., "Size Selection Flow", "Material-Color Picker")
3. **Use in Main Flow**: The custom tile appears as a single node with defined inputs/outputs
4. **Drill Down to Edit**: Double-click the custom tile to open its internal flow in a separate view
5. **Propagate Changes**: Edits to the custom tile automatically update all instances
#### Example Use Cases
**Size Selection Flow:**
```
[Entry Point]
[Show Standard Sizes] ──→ [Size Button 1] → [Exit: Standard]
──→ [Size Button 2] → [Exit: Standard]
──→ [Size Button 3] → [Exit: Standard]
──→ [Custom Size] → [Dimension Form] → [Exit: Custom]
```
This 5-tile flow becomes **one custom tile** in the main flow:
```
[Color Selection] → [Size Selection Flow] → [Results]
```
**Material-Color Combo Flow:**
```
[Entry Point]
[Material Selection] → [Aluminum] → [Aluminum Colors] → [Exit]
→ [Vinyl] → [Vinyl Colors] → [Exit]
→ [Wood] → [Wood Stains] → [Exit]
```
**Glass Options Flow:**
```
[Entry Point]
[Glass Type] → [Clear] → [Thickness Options] → [Exit]
→ [Tinted] → [Tint Colors] → [Exit]
→ [Obscure] → [Pattern Selection] → [Exit]
```
#### UI/UX for Sub-Flows
**Main Flow View:**
- Custom tiles show with special icon (e.g., 📦 or collapsed group icon)
- Display name: "Size Selection Flow"
- Show entry point (green circle) and exit points (colored circles per output group)
- Quick preview badge: "5 nodes"
**Switching Views:**
- **Option A:** Dropdown menu at top: `Main Flow ▼` → Select custom tile name to switch
- **Option B:** Double-click custom tile to drill down into its internal flow
- **Option C:** Breadcrumb navigation: `Main Flow > Size Selection Flow`
**Inside Custom Tile View:**
- Special entry node: "Entry Point" (where main flow enters)
- Special exit nodes: "Exit: Standard", "Exit: Custom" (where flow returns to main)
- Edit the internal flow just like the main flow
- Changes save automatically
#### Custom Tile Library
```
┌─────────────────────────┐
│ Custom Tiles Library │
├─────────────────────────┤
│ 📦 Size Selection Flow │ [Edit] [Delete]
│ 📦 Material-Color Combo │ [Edit] [Delete]
│ 📦 Glass Options Flow │ [Edit] [Delete]
│ │
│ [+ Create New Custom Tile]
└─────────────────────────┘
```
#### Implementation Benefits
**Reusability** - Create once, use many times across different product flows
**Maintainability** - Update the custom tile once, all instances update automatically
**Complexity Management** - Main flow stays clean; complex logic hidden in sub-flows
**Organization** - Group related questions logically
**Scalability** - Handle 100+ node flows by keeping main flow at 10-20 high-level tiles
**Collaboration** - Team members can work on different custom tiles independently
#### Additional Organization Features
- **Minimap** for navigation in large flows
- **Search/filter** to find specific nodes or custom tiles
- **Auto-layout** algorithm to organize nodes cleanly
- **Zoom controls** (fit to screen, zoom to selection)
- **Layers or tags** for categorizing nodes (e.g., "Storm Doors", "Patio Doors")
### Challenge 4: Path Validation
**Problem:** Ensuring all paths lead somewhere valid and no orphaned nodes.
**Solution:**
- Real-time validation as user edits
- Visual indicators: red border on nodes with issues
- Validation report showing:
- Orphaned nodes (no incoming connections)
- Dead ends (no outgoing connections)
- Missing required fields
- Circular references
- Test mode: simulate walking through the navigation
## User Experience Flow
### Creating a New Node
1. Click "Add Node" button or drag from palette
2. Node appears on canvas with default settings
3. User clicks node to select
4. Config panel opens on right
5. User fills in: Question ID, title, type
6. Based on type, additional fields appear (buttons, input fields, etc.)
7. User configures output groups
8. User saves (auto or manual)
9. Node updates visually on canvas
### Connecting Two Nodes
1. User selects source node
2. Output circles appear on node edges
3. User clicks and drags from a circle
4. Arrow follows mouse cursor
5. User drops on target node
6. Connection is created
7. Arrow persists showing the connection
8. Clicking arrow allows editing connection details
### Setting Default Values
1. User selects a node
2. Config panel shows "Default Values" section
3. User clicks "[+ Add Default Value]"
4. New row appears with dropdowns and field
5. User selects variable from dropdown (or types new name)
6. User enters value in field
7. Value is stored with the node
8. When navigation reaches this node, values are set
### Testing the Navigation
1. User clicks "Test Mode" button
2. Canvas switches to interactive mode
3. Simulated UI appears showing the current question
4. User can answer questions, seeing the path highlighted
5. Path taken is shown with animated arrows
6. User can reset and try different paths
7. Exit test mode to return to editing
## Additional Features to Consider
### Versioning & History
- Save snapshots of navigation.json before changes
- Git integration for version control
- Undo/redo with unlimited history
- Compare versions side-by-side
### Collaboration
- Multi-user editing with real-time sync
- Comments on nodes for team discussions
- Lock nodes being edited by others
- Change notifications
### Import/Export
- Export to different formats (JSON, YAML, diagram image)
- Import from other tools or formats
- Export to documentation (PDF, HTML)
### Templates & Snippets
- Save common question patterns as templates
- Library of pre-built question flows
- Duplicate and modify existing flows
### Analytics Integration
- Show usage statistics on nodes (if tracking is implemented)
- Highlight most/least used paths
- Identify bottlenecks or drop-off points
### Accessibility
- Keyboard shortcuts for all operations
- Screen reader support
- High contrast mode
- Zoom accessibility
## Additional Considerations & Potential Issues
### Critical Features Not Yet Detailed
#### 1. Undo/Redo System ⚠️ HIGH PRIORITY
**Why Critical:** Visual editors require robust undo/redo because users make lots of experimental changes, accidental deletions, and need quick recovery from mistakes.
**Implementation Approach:**
- **Command Pattern**: Each action (move node, add connection, edit property) is a reversible command
- **Action History Stack**: Maintain array of completed actions, track current position
- **Supported Actions**:
- Node: Create, Delete, Move, Duplicate, Edit Properties
- Connection: Add, Remove, Reroute
- Group Operations: Multi-node moves, bulk edits
- **UI**: Ctrl+Z (undo), Ctrl+Y/Ctrl+Shift+Z (redo), visual history panel (optional)
- **State Management**: Snapshot approach vs incremental changes
- **Snapshot**: Save full state after each action (simple but memory-intensive)
- **Incremental**: Store delta changes (complex but efficient)
**Recommendation:** Start with snapshot approach for MVP, optimize to incremental if performance becomes an issue.
**Estimated Effort:** 10-15 hours
---
#### 2. Copy/Paste & Duplication
**Why Important:** Users frequently need to duplicate similar question nodes, copy patterns, or reuse configurations.
**Features Needed:**
- **Copy Single Node**: Ctrl+C copies selected node and its config
- **Copy Multiple Nodes**: Shift-click or drag-select to copy groups
- **Copy with Connections**: Option to include/exclude connection information
- **Paste**: Ctrl+V pastes at cursor position or offset from original
- **Duplicate**: Ctrl+D creates copy immediately (no clipboard)
- **Between Flows**: Copy from main flow, paste into custom tile (and vice versa)
- **ID Conflict Resolution**: Auto-generate new unique IDs for pasted nodes
- **Connection Handling**:
- Internal connections (between pasted nodes) are preserved
- External connections (to non-copied nodes) are broken/cleared
**Clipboard Format:**
```json
{
"type": "copilot-nav-editor",
"version": "1.0",
"nodes": [...],
"connections": [...],
"boundingBox": { "width": 500, "height": 300 }
}
```
**Estimated Effort:** 8-12 hours
---
#### 3. Keyboard Shortcuts
**Why Important:** Power users expect keyboard efficiency. Mouse-only interfaces feel slow after extended use.
**Essential Shortcuts:**
```
Navigation & Selection:
Tab / Shift+Tab - Select next/previous node
Arrow Keys - Move selected node (hold Shift for 10px increments)
Ctrl+A - Select all nodes
Ctrl+Click - Multi-select nodes
Shift+Click - Select range between last selected
Editing:
Ctrl+Z - Undo
Ctrl+Y / Ctrl+Shift+Z - Redo
Ctrl+C - Copy
Ctrl+V - Paste
Ctrl+X - Cut
Ctrl+D - Duplicate
Delete / Backspace - Delete selected
Enter - Edit selected node (open config panel)
Esc - Deselect / Close panel / Cancel drag
View:
Spacebar (hold) - Pan/Hand tool (drag canvas)
Ctrl+0 - Zoom to fit all
Ctrl++ / Ctrl+- - Zoom in/out
Ctrl+Scroll - Zoom at cursor
Ctrl+F - Search/Find node
File Operations:
Ctrl+S - Save project
Ctrl+Shift+S - Save As
Ctrl+E - Export to navigation.json
Ctrl+N - New project
Ctrl+O - Open project
```
**Implementation:** Hook keyboard events at canvas level, prevent conflicts with browser shortcuts.
**Estimated Effort:** 5-8 hours
---
#### 4. Connection Routing Algorithm
**Why Important:** As flows grow complex, straight-line arrows overlap nodes and cross each other, creating visual mess.
**Options:**
**Option A: Straight Lines (Simple)**
- Direct point-to-point lines
- ✅ Easy to implement
- ✅ Fast rendering
- ❌ Overlaps and crosses in complex flows
**Option B: Bezier Curves (Smooth)**
- Curved connections using cubic Bezier paths
- ✅ Visually appealing
- ✅ Some automatic avoidance via control points
- ⚠️ Can still overlap nodes
- **React Flow default option**
**Option C: Orthogonal Routing (Clean)**
- Only horizontal and vertical lines (like electrical diagrams)
- ✅ Very clean, professional look
- ✅ Better node avoidance possible
- ❌ More complex algorithm
- ❌ May require more space
**Option D: Intelligent Routing (Advanced)**
- Pathfinding algorithm (A*) to route around nodes
- ✅ Best visual clarity
- ✅ No overlaps
- ❌ Most complex
- ❌ Performance considerations with many connections
**Recommendation for MVP:** Start with Bezier curves (React Flow default), add orthogonal routing in Phase 5 if needed.
**Estimated Effort:**
- Bezier (built-in): 0 hours
- Orthogonal: 15-20 hours
- Intelligent: 30-40 hours
---
#### 5. Auto-Save vs Manual Save
**Why Important:** Browser crashes, accidental closures, and forgotten saves can lose hours of work.
**Recommended Strategy: Hybrid Approach**
**Auto-Save to Local Storage:**
- Save to `localStorage` every 30 seconds (debounced after changes)
- Keep last 3 auto-save versions with timestamps
- Recover on next load if detected
- ⚠️ localStorage limit: ~5-10MB (should be sufficient for most flows)
**Manual Save to File:**
- Ctrl+S saves project file to disk (`.navproj.json`)
- Visual indicator: "Saved" checkmark vs "Unsaved changes" dot
- Prompt before closing window if unsaved changes exist
**Cloud Sync (Future):**
- Optional integration with cloud storage (Google Drive, Dropbox, OneDrive)
- Version history and conflict resolution
**UI Feedback:**
```
┌─────────────────────────────────────┐
│ 🟢 Auto-saved 30 seconds ago │
│ ⚫ Unsaved manual changes │
│ [Save Project] [Export Navigation] │
└─────────────────────────────────────┘
```
**Browser Close Warning:**
```javascript
window.addEventListener('beforeunload', (e) => {
if (hasUnsavedChanges()) {
e.preventDefault();
e.returnValue = 'You have unsaved changes. Are you sure?';
}
});
```
**Estimated Effort:** 6-10 hours
---
#### 6. Performance at Scale ⚠️ IMPORTANT
**Why Important:** A navigation with 100+ nodes and 200+ connections could slow down rendering and interactions.
**Potential Issues:**
- Slow drag-and-drop response
- Lag when adding/removing connections
- Sluggish panning and zooming
- Memory consumption
**React Flow Performance Characteristics:**
- Generally handles 100-300 nodes well
- Slows down around 500+ nodes
- Connections are more performant than nodes
**Optimization Strategies:**
**Level 1: Built-in React Flow Optimizations** (Free)
- Virtual rendering (only render visible nodes)
- Memoization of node components
- Connection edge optimization
**Level 2: Custom Optimizations** (If Needed)
- **Lazy Load Custom Tiles**: Don't load internal nodes until opened
- **Connection Simplification**: Reduce curve resolution for distant connections
- **Level of Detail**: Show simplified node representation when zoomed out
- **Pagination/Filtering**: Show subset of nodes at a time (by category, search)
- **Canvas Sectioning**: Divide large flows into "pages" or "zones"
**Performance Testing Plan:**
1. Create test navigation with 50, 100, 200, 500 nodes
2. Measure frame rate during drag operations (target: 60 FPS)
3. Measure zoom/pan responsiveness
4. Measure initial load time
5. Test on lower-end hardware
**Recommendation:** Test with realistic data size early (Phase 2), optimize only if needed.
**Estimated Effort:**
- Testing: 3-5 hours
- Optimizations: 10-20 hours (if needed)
---
#### 7. Circular Dependency Detection
**Why Important:** Node A → Node B → Node C → Node A creates infinite loops, breaking navigation.
**Detection Algorithm:**
```typescript
function detectCycles(nodes: Node[], connections: Connection[]): string[] {
const cycles: string[] = [];
// Build adjacency list
const graph = buildGraph(connections);
// Depth-first search with path tracking
const visited = new Set<string>();
const recursionStack = new Set<string>();
function dfs(nodeId: string, path: string[]): boolean {
visited.add(nodeId);
recursionStack.add(nodeId);
path.push(nodeId);
const neighbors = graph.get(nodeId) || [];
for (const neighbor of neighbors) {
if (!visited.has(neighbor)) {
if (dfs(neighbor, path)) return true;
} else if (recursionStack.has(neighbor)) {
// Cycle detected!
const cycleStart = path.indexOf(neighbor);
const cycle = path.slice(cycleStart).concat(neighbor);
cycles.push(cycle.join(' → '));
return true;
}
}
recursionStack.delete(nodeId);
return false;
}
// Check all nodes
nodes.forEach(node => {
if (!visited.has(node.id)) {
dfs(node.id, []);
}
});
return cycles;
}
```
**User Experience:**
- **Real-time Detection**: Run cycle check after each connection change
- **Visual Warning**: Highlight nodes involved in cycle with red border
- **Error Message**: "Cycle detected: Start → Door Type → Color → Start"
- **Suggestion**: "This creates an infinite loop. Remove one of these connections."
- **Prevent Export**: Don't allow exporting navigation with cycles
**Estimated Effort:** 4-6 hours
---
#### 8. Backwards Compatibility Strategy
**Why Important:** As the `.navproj.json` format evolves (v1.0 → v1.1 → v2.0), old project files must still load.
**Versioning Strategy:**
```json
{
"version": "1.2",
"formatVersion": "1.2", // Semantic versioning
"nodes": [...]
}
```
**Migration System:**
```typescript
const migrations = {
"1.0-to-1.1": (data) => {
// Add default values structure if missing
data.nodes.forEach(node => {
if (!node.defaults) node.defaults = [];
});
return data;
},
"1.1-to-1.2": (data) => {
// Add custom tiles structure
if (!data.customTiles) data.customTiles = [];
return data;
}
};
function migrateProjectFile(data: any): any {
const currentVersion = data.version || "1.0";
const targetVersion = "1.2";
// Apply migrations sequentially
let migrated = data;
const path = getMigrationPath(currentVersion, targetVersion);
for (const step of path) {
migrated = migrations[step](migrated);
}
migrated.version = targetVersion;
return migrated;
}
```
**Loading Process:**
1. Detect version in loaded file
2. If old version, show: "Upgrading project from v1.0 to v1.2..."
3. Apply migrations sequentially
4. Create backup of original file before overwriting
5. Ask user to save upgraded version
**Testing:**
- Keep example projects from each version
- Automated tests to ensure all old versions load correctly
**Estimated Effort:** 5-8 hours (initial setup), 2-3 hours per future migration
---
#### 9. Error Handling & Recovery
**Why Important:** Corrupted files, network issues, browser crashes require graceful handling.
**Scenarios & Solutions:**
**Corrupted Project File:**
```typescript
function loadProject(filepath: string): Result<Project, Error> {
try {
const data = JSON.parse(fileContent);
// Schema validation
const validation = validateProjectSchema(data);
if (!validation.valid) {
return Error(`Invalid project structure: ${validation.errors}`);
}
return Ok(Project.fromJSON(data));
} catch (e) {
// JSON parse error
if (autoSaveExists()) {
return showRecoveryDialog();
} else {
return Error("Could not load project. File may be corrupted.");
}
}
}
```
**Auto-Save Recovery Dialog:**
```
┌───────────────────────────────────────────┐
│ ⚠️ Project File Could Not Be Loaded │
│ │
│ The file may be corrupted. However, we │
│ found auto-saved versions: │
│ │
│ 🔵 Auto-save from 2 minutes ago │
│ 🔵 Auto-save from 5 minutes ago │
│ 🔵 Auto-save from 10 minutes ago │
│ │
│ [Recover] [Cancel] │
└───────────────────────────────────────────┘
```
**Export Validation Error:**
```
┌───────────────────────────────────────────┐
│ ❌ Cannot Export - Validation Errors │
│ │
│ The following issues must be fixed: │
│ │
│ • Node "q-dimensions" has no connections │
│ • Cycle detected: start → door → start │
│ • Node "q-color" missing required title │
│ │
│ [Show Details] [Close] │
└───────────────────────────────────────────┘
```
**Backup Strategy:**
- Before any save operation, create backup: `project.navproj.backup.json`
- Keep last 3 backups rotating
- Manual "Restore from Backup" option in File menu
**Estimated Effort:** 8-12 hours
---
#### 10. Search/Filter in Canvas
**Why Important:** Finding specific nodes in a 50+ node flow is time-consuming.
**Search Features:**
**Quick Search (Ctrl+F):**
```
┌─────────────────────────────────────┐
│ 🔍 Search: door___ │
│ │
│ Results (3): │
│ • q-door-type (Question) │
│ • q-door-size (Form) │
│ • door-accessories (Results) │
└─────────────────────────────────────┘
```
**Search Criteria:**
- Node title
- Node ID (tileId)
- Question type
- Button captions
- Notes content
**Results Interaction:**
- Click result → zoom to node and highlight
- Arrow down/up to cycle through results
- Esc to close search
**Advanced Filter:**
```
Filter Nodes:
☑ Questions ☑ Forms ☑ Results ☑ Custom Tiles
☑ Connected ☐ Orphaned
Text: [ ]
```
**Visual Highlighting:**
- Matching nodes: bright blue border
- Dimmed view: non-matching nodes become semi-transparent
- Match count badge: "3 of 47 nodes match"
**Estimated Effort:** 6-10 hours
---
### Nice-to-Have Features
#### 11. Comments & Annotations
**Use Case:** Team collaboration, leaving TODO notes, explaining complex logic.
**Implementation:**
- **Node-level Notes**: Add "Notes" field in config panel (already exists in data)
- **Canvas Comments**: Floating text boxes on canvas (like sticky notes)
- **Connection Labels**: Add text labels to connection arrows
- **Visual Indicators**: 💬 icon on nodes with comments
**Estimated Effort:** 5-8 hours
---
#### 12. Grouping/Visual Containers
**Use Case:** Visually organize related nodes without creating a custom tile.
**Implementation:**
- **Background Rectangle**: Dotted/dashed border around group of nodes
- **Group Label**: Title at top of container
- **Color Coding**: Different colors for different product categories
- **Collapse/Expand**: Optional ability to collapse group to single icon
- **Move Group**: Drag group title to move all contained nodes
**Example:**
```
╭─ Storm Door Questions ──────────────╮
│ │
│ [Color] → [Size] → [Accessories] │
│ │
╰─────────────────────────────────────╯
```
**Estimated Effort:** 10-15 hours
---
#### 13. Diff/Compare View
**Use Case:** Understanding what changed between versions, code review, debugging.
**Implementation:**
- **Side-by-side Canvas**: Show two versions simultaneously
- **Visual Diff Indicators**:
- 🟢 Green: New nodes
- 🔴 Red: Deleted nodes
- 🟡 Yellow: Modified nodes
- Updated connections shown with dashed lines
- **Change Summary**: "5 nodes added, 3 modified, 1 deleted, 7 connections changed"
**Estimated Effort:** 15-20 hours
---
#### 14. Accessibility
**Why Important:** Legal compliance (ADA/WCAG), inclusive design.
**Requirements:**
**Keyboard Navigation:**
- Tab through all interactive elements
- Arrow keys to navigate between nodes
- Enter to activate/edit
- Full functionality without mouse
**Screen Reader Support:**
- Proper ARIA labels on all elements
- Announce node selections
- Describe connections meaningfully
- Accessible forms in config panel
**Visual Accessibility:**
- High contrast mode
- Color-blind friendly palette options
- Configurable font sizes
- Focus indicators (visible keyboard focus)
**Estimated Effort:** 15-25 hours
---
#### 15. Testing/Debugging Mode (Enhanced Details)
**Why Important:** Validate navigation logic before deployment, catch errors early.
**Features:**
**Interactive Simulation:**
- Start at "start" node
- Display actual question UI as users would see it
- Click buttons/fill forms to progress
- Visual path highlighting shows route taken
**Breakpoints:**
- Set breakpoints on specific nodes
- Execution pauses when reached
- Inspect current state
**Variable Inspector:**
- Show all current variable values
- Display filters applied
- Show which products match current filter
**Path History:**
```
Path Taken:
1. start → Door
2. q-door-type → Storm Door
3. q-color → White
4. q-dimensions → Width: 32, Height: 81
5. results → 3 products match
```
**Test Cases:**
- Save common test scenarios
- Replay to verify behavior after changes
- Automated regression testing
**Estimated Effort:** 20-30 hours
---
#### 16. Export to Diagram Image
**Use Case:** Documentation, presentations, stakeholder communication.
**Export Formats:**
- **PNG**: Raster image, good for presentations
- **SVG**: Vector image, scalable, good for print
- **PDF**: Multi-page for large flows
**Export Options:**
- Full canvas or selected region
- Current viewport only
- Include/exclude connection labels
- Background color/transparency
- Resolution/DPI settings
**Implementation:**
```typescript
function exportToPNG(canvas: CanvasElement, options: ExportOptions) {
const svgData = canvas.toSVG();
const canvas2d = createCanvas(options.width, options.height);
const ctx = canvas2d.getContext('2d');
// Render SVG to canvas
renderSVGToCanvas(svgData, ctx);
// Export as PNG
return canvas2d.toDataURL('image/png');
}
```
**Estimated Effort:** 8-12 hours
---
### Security & Collaboration Concerns
#### 17. Multi-User Collaboration (Future Consideration)
**Why Important:** Teams working together on complex flows.
**Challenges:**
- **Simultaneous Edits**: Two people editing same node
- **Conflict Resolution**: Merge conflicts like Git
- **Real-time Sync**: Show others' cursors and selections
- **Locking**: Prevent conflicts by locking edited nodes
**Implementation Options:**
- **Operational Transform** (Google Docs approach)
- **CRDT** (Conflict-Free Replicated Data Types)
- **Last-Write-Wins** (simplest, but loses data)
**Recommendation:** **Not for MVP**. Add in Phase 6+ if team collaboration is critical.
**Estimated Effort:** 80-120 hours (complex)
---
#### 18. Validation & Security
**Why Important:** Prevent malicious or corrupted files from breaking the editor.
**Validation on Load:**
```typescript
function validateProjectFile(data: any): ValidationResult {
const errors: string[] = [];
// Schema validation (JSON Schema)
if (!data.version) errors.push("Missing version");
if (!data.nodes || !Array.isArray(data.nodes)) {
errors.push("Invalid nodes structure");
}
// Security checks
data.nodes?.forEach(node => {
// Sanitize HTML in notes field
if (node.config?.notes) {
node.config.notes = sanitizeHTML(node.config.notes);
}
// Check for excessively large data
const nodeSize = JSON.stringify(node).length;
if (nodeSize > 100000) {
errors.push(`Node ${node.id} exceeds size limit`);
}
});
// File size limit (prevent DoS)
const totalSize = JSON.stringify(data).length;
if (totalSize > 10000000) { // 10MB limit
errors.push("Project file too large");
}
return {
valid: errors.length === 0,
errors
};
}
```
**HTML Sanitization:**
- Use library like DOMPurify for notes field
- Prevent XSS attacks via malicious HTML
**Estimated Effort:** 5-8 hours
---
## Implementation Priority Recommendations
### Phase 1 (MVP Must-Haves):
- ✅ Core canvas with drag-drop nodes
- ✅ Basic config panel
- ✅ Connections (simple)
- ✅ Save/Load project files
- ✅ Export to navigation.json
- **Undo/Redo** (even basic implementation)
- **Keyboard shortcuts** (at least Ctrl+Z, Ctrl+S, Delete)
- **Auto-save to localStorage**
- **Error handling for corrupted files**
**Estimated:** 40-50 hours
---
### Phase 2 (Important for Usability):
- ✅ Button grouping & output colors
- ✅ Default values configuration
- ✅ Connection routing (Bezier curves)
- **Copy/Paste**
- **Full keyboard shortcuts**
- **Canvas search**
- **Circular dependency detection**
- **Basic validation & error messages**
**Estimated:** 50-65 hours
---
### Phase 3 (Advanced Features):
- ✅ Custom tiles (sub-flows)
- ✅ Hierarchical navigation
- **Performance testing & optimization** (if needed)
- **Backwards compatibility system**
- **Testing/debugging mode**
- **Auto-layout algorithm**
**Estimated:** 50-70 hours
---
### Phase 4 (Polish & Optional):
- **Comments & annotations**
- **Grouping/containers**
- **Export to image**
- **Accessibility improvements**
- **Diff/compare view**
- **Advanced routing algorithms**
**Estimated:** 40-60 hours
---
### Future/Optional:
- Multi-user collaboration (complex, separate project)
- Cloud storage integration
- Mobile responsive design
- Version control UI (Git integration)
- Analytics dashboard
---
## Bottom Line: Gaps Addressed
**Critical Gaps** (must be added to plan):
1.**Undo/Redo** - Absolutely essential, add to Phase 1
2.**Copy/Paste** - Users will expect this, add to Phase 2
3.**Auto-Save** - Prevent data loss, add to Phase 1
4.**Error Handling** - Graceful failures, add to Phase 1
**Important Gaps** (should be added):
5.**Keyboard Shortcuts** - Power user efficiency, Phase 2
6.**Performance Strategy** - Test early, optimize if needed
7.**Circular Dependencies** - Validation requirement, Phase 2
8.**Search/Filter** - Usability for large flows, Phase 2
**Nice-to-Have** (can be deferred):
9.**Comments** - Collaboration aid, Phase 4
10.**Grouping** - Visual organization, Phase 4
11.**Diff View** - Advanced feature, Phase 4
12.**Accessibility** - Important but can be iterative
13.**Export to Image** - Documentation aid, Phase 4
**Out of Scope for Now:**
14.**Multi-User Collaboration** - Too complex for initial versions
15.**Mobile App** - Desktop-first approach recommended
All critical and important gaps are now documented in this comprehensive planning document!
---
## Conclusion
### Feasibility: **Highly Feasible**
This visual editor is definitely possible and would significantly improve the maintainability of complex navigation flows.
### Complexity: **Medium-High**
- Core functionality (nodes, connections, config panel): Medium complexity
- Advanced features (grouping, validation, testing): Higher complexity
- Total project could be completed in 3-4 weeks of focused development
### Value Proposition: **Very High**
- Dramatically reduces time to create/edit navigation flows
- Visual representation makes logic much clearer
- Reduces errors from manual JSON editing
- Lowers barrier to entry for non-technical users
- Makes complex branching logic manageable
### Recommended Next Steps
1. **Prototype:** Build a simple proof-of-concept with React Flow to validate the approach
2. **Feedback:** Show prototype to potential users for feedback
3. **Iterate:** Refine the UI/UX based on feedback
4. **MVP:** Build Phase 1 & 2 (core canvas + basic editing)
5. **Evaluate:** Assess if it's worth continuing to advanced features
6. **Complete:** Finish remaining phases based on needs
### Alternative: Lower-Effort Options
If a full visual editor is too much effort:
1. **JSON Schema Editor:** Use existing JSON form builders with validation
2. **Spreadsheet Import:** Design navigation in Excel/Google Sheets, import to JSON
3. **Template Generator:** Web form to fill in, generates navigation.json
4. **Better Documentation:** Improve JSON comments and examples for manual editing
This visual editor would transform navigation.json management from a manual, error-prone process into an intuitive, visual workflow—similar to how Talend transformed data integration pipelines.