Introduction
The HubSpot Form Builder is a full-stack web application that integrates with HubSpot to allow users to create and customize multi-step forms without code. The application fetches forms from HubSpot, provides a visual drag-and-drop editor, and exports customized forms as HubSpot CMS modules.System Architecture
The application follows a monorepo architecture using npm workspaces with three main packages:Architecture Diagram
Technology Stack
Frontend
| Technology | Purpose |
|---|---|
| React 18.3 | UI framework |
| TypeScript 5.5 | Type safety |
| Vite 5.4 | Build tool and dev server |
| Zustand 4.5 | State management |
| @dnd-kit | Drag and drop library |
| JSZip 3.10 | Module export (ZIP generation) |
| react-zoom-pan-pinch 3.7 | Canvas zoom controls |
Backend
| Technology | Purpose |
|---|---|
| Node.js | Runtime environment |
| Express 4.19 | Web server framework |
| TypeScript 5.5 | Type safety |
| CORS | Cross-origin resource sharing |
| dotenv | Environment configuration |
Development Tools
- ESLint - Code linting
- Prettier - Code formatting
- tsx - TypeScript execution for development
- npm workspaces - Monorepo management
Data Flow
The application follows a unidirectional data flow:- User Authentication: User connects to HubSpot via OAuth 2.0
- Form Fetching: Frontend fetches forms list from backend
- Schema Loading: Backend normalizes HubSpot form data to internal schema
- Layout Editing: User modifies layout using drag-and-drop
- State Management: Zustand store maintains layout state
- Preview: Shadow DOM renders live preview
- Export: Module generators create HubSpot CMS module files
- Download: User downloads ZIP file
Key Architectural Decisions
1. Monorepo with npm Workspaces
Why: Simplifies dependency management and type sharing between frontend and backend.2. @dnd-kit for Drag and Drop
Why: Modern, accessible, and performant drag-and-drop library with excellent TypeScript support.- Supports complex drag operations (fields, rows, steps)
- Provides collision detection and sorting strategies
- Accessible by default (keyboard navigation)
3. Zustand for State Management
Why: Lightweight, simple API, and excellent TypeScript support compared to Redux.- No boilerplate
- Hook-based API
- Easy to test
- Supports immer-like updates
4. OAuth 2.0 with Server-Side Token Storage
Why: Tokens are stored on the server (not in browser) for security.- Development: In-memory Map (tokenStore)
- Production: Should use encrypted database storage
5. Shadow DOM for Preview Isolation
Why: Prevents style conflicts between editor UI and form preview.- Complete CSS isolation
- Accurate preview of exported module
- No style leakage
6. Shared TypeScript Types
Why: Single source of truth for data structures used across frontend and backend.Workspace Structure
Security Considerations
✅ Implemented:- Tokens stored on server (not in browser)
- CORS configured with origin whitelist
- State validation in OAuth callback
- HTTPS required for HubSpot API calls
- Token refresh in background
- Database storage for tokens (encrypted)
- Rate limiting on API endpoints
- Input validation and sanitization
- CSRF protection
- Session timeout
Performance Optimizations
- Lazy loading: Components loaded on demand
- Memoization: React components memoized where appropriate
- Debouncing: Preview updates debounced
- Efficient drag-and-drop: @dnd-kit uses requestAnimationFrame
- Shadow DOM: Prevents style recalculation
- ZIP compression: Module exports use DEFLATE compression
Development Workflow
- Install dependencies:
npm install(from main/) - Build shared types:
npm run build -w shared - Start backend:
npm run dev -w server - Start frontend:
npm run dev -w frontend - Access app: http://localhost:5174
