Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

11 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

🧩 Chatbot Flow Builder

A mini visual flow builder built using React + TypeScript + React Flow (@xyflow/react) that allows users to create, connect, edit, validate, and persist conversational flows.

This project focuses on clean architecture, extensibility, and correct business rule enforcement.


πŸš€ Live Demo

Add your deployed Vercel link here


πŸ›  Tech Stack

Technology Purpose
React UI framework
TypeScript Type safety
Vite Build tool & dev server
@xyflow/react (React Flow v12) Visual canvas & node rendering
Zustand Centralized state management
Zustand Persist Middleware localStorage persistence

🧠 Features

Node Creation (Drag & Drop)

  • Drag "Message Node" from sidebar
  • Drop anywhere on canvas
  • Node created at exact drop position using screenToFlowPosition

Custom Node UI

Each node contains:

  • Title
  • Message content
  • Source handle (right side β€” for outgoing connections)
  • Target handle (left side β€” for incoming connections)

Edge Connections

  • Connect nodes visually by dragging between handles
  • Only one outgoing edge per source node allowed
  • Multiple incoming edges allowed on any node

Edit Node Content

  • Click any node β†’ settings panel opens in the sidebar
  • Edit node title and message content live
  • Updates reflect instantly on the canvas

Delete Functionality

  • Delete selected node (also removes all connected edges)
  • Delete edges by selecting and pressing the Delete key

Validation Rule (Business Logic)

On clicking Save, the following rule is enforced:

If total nodes > 1 AND more than one node has no incoming edge β†’ ❌ Flow is invalid

Only one root node is allowed β€” ensuring a single entry point for the conversational flow.

Persistence

Flow state persists automatically using Zustand + localStorage. Refreshing the page does not lose the flow.


πŸ— Project Structure

src/
β”‚
β”œβ”€β”€ app/
β”‚   └── FlowBuilder.tsx          # Root layout: canvas + sidebar
β”‚
β”œβ”€β”€ components/
β”‚   β”œβ”€β”€ canvas/
β”‚   β”‚   └── FlowCanvas.tsx       # React Flow canvas, drag/drop, event handlers
β”‚   β”œβ”€β”€ nodes/
β”‚   β”‚   └── TextNode.tsx         # Custom message node UI
β”‚   β”œβ”€β”€ panels/
β”‚   β”‚   β”œβ”€β”€ Sidebar.tsx          # Conditional panel router
β”‚   β”‚   β”œβ”€β”€ NodesPanel.tsx       # Draggable node palette
β”‚   β”‚   └── SettingsPanel.tsx    # Node edit form
β”‚   └── common/
β”‚       └── SaveButton.tsx       # Save + validation trigger
β”‚
β”œβ”€β”€ store/
β”‚   └── flowStore.ts             # Zustand store (nodes, edges, UI state)
β”‚
β”œβ”€β”€ registry/
β”‚   └── nodeRegistry.ts          # Maps node type strings β†’ React components
β”‚
β”œβ”€β”€ types/
β”‚   β”œβ”€β”€ flowTypes.ts             # Edge, Node, store typings
β”‚   └── nodeTypes.ts             # Node data shape definitions
β”‚
└── utils/
    └── validation.ts            # Business rule enforcement (pure function)

🧠 Key Architectural Decisions

1. Controlled React Flow

React Flow runs in controlled mode:

  • nodes and edges are owned by Zustand
  • React Flow is responsible for UI rendering only
  • All mutations (add, update, delete) go through the centralized store

This ensures predictable, debuggable state management with a single source of truth.


2. Centralized State via Zustand

All application state lives in store/flowStore.ts:

{
  nodes: Node[],
  edges: Edge[],
  selectedNodeId: string | null,
  panelMode: 'nodes' | 'settings',
}

State is:

  • Immutable β€” updated via Zustand actions, never mutated directly
  • Persisted β€” via persist middleware to localStorage
  • Globally accessible β€” no prop drilling needed

3. Node Registry Pattern

Custom node types are registered in registry/nodeRegistry.ts:

export const nodeTypes = {
  textNode: TextNode,
};

To add a new node type:

  1. Create a new node component in components/nodes/
  2. Register it in nodeRegistry.ts
  3. Add a drag item for it in NodesPanel.tsx

The FlowCanvas does not need to be modified.


4. Business Logic Separation

Validation logic is fully isolated in utils/validation.ts as a pure function:

validateFlow(nodes, edges): { valid: boolean; message: string }

Benefits:

  • UI components stay clean and presentation-only
  • Logic is independently unit-testable
  • Responsibilities are clearly separated

πŸ” Validation Logic

The validation algorithm works as follows:

  1. Build a map of nodeId β†’ incomingEdgeCount (all start at 0)
  2. Iterate through all edges and increment the target node's count
  3. Count nodes where incomingEdgeCount === 0 (root nodes)
  4. If nodes.length > 1 AND rootCount > 1 β†’ invalid flow

This ensures a valid single-entry-point conversational flow.


🧩 Interaction Flows

Creating a Node

  1. Drag node type from sidebar palette
  2. Drop on canvas
  3. Canvas computes position via screenToFlowPosition
  4. Node added to Zustand store β†’ canvas re-renders

Connecting Nodes

  1. User drags from a source handle to a target handle
  2. onConnect fires
  3. Logic checks: does source node already have an outgoing edge?
  4. If not β†’ edge added to store

Editing a Node

  1. User clicks a node
  2. selectedNodeId set in store β†’ panel switches to settings mode
  3. User edits title/message in the settings panel
  4. Store updates node data β†’ node re-renders live

Saving the Flow

  1. User clicks Save
  2. validateFlow(nodes, edges) runs
  3. Valid β†’ success toast/indicator shown
  4. ❌ Invalid β†’ error message shown

πŸ’Ύ Persistence Strategy

Zustand's persist middleware automatically syncs state to localStorage:

persist(flowStore, { name: 'flow-builder-storage' })

On page refresh:

  • Zustand reads from flow-builder-storage in localStorage
  • State is rehydrated
  • Flow is restored automatically β€” no manual save required

▢️ Running Locally

# Install dependencies
npm install

# Start dev server
npm run dev

Build for production:

npm run build

πŸš€ Future Improvements

Feature Description
Auto layout DAG-based automatic node positioning
JSON export/import Save and load flows as files
Multiple flows Support for multiple independent flows
Backend persistence API-based storage replacing localStorage
Visual validation indicators Highlight invalid nodes/edges before save
Edge labels Named connections for conditional branches
Conditional branching Nodes with multiple conditional outputs
Undo/Redo History-based state management

πŸ“Œ Design Philosophy

This project was built with the following principles in mind:

  • Clean separation of concerns β€” UI, state, and logic are independent layers
  • Extensibility β€” new node types can be added with zero changes to core components
  • Strict TypeScript β€” all data structures are fully typed
  • Business rule enforcement β€” validation is explicit, not implicit
  • Predictable state management β€” controlled React Flow + Zustand
  • Minimal coupling β€” components communicate through the store, not each other

The goal was not just to make it work, but to structure it as a scalable, maintainable system.


About

Node Based Flow Creator

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages