Frontend Overview¶
The frontend uses a modular architecture with shared components across multiple deployment targets.
Architecture¶
frontend/
├── shared/ # Core shared package (@inboundx/shared)
├── widget/ # Standalone JavaScript widget for websites
├── preprod-ui/ # Pre-production testing interface
├── chrome-plugin/ # Chrome extension
├── client-backoffice/ # Client configuration dashboard
├── e2e/ # End-to-end tests (Playwright)
└── justfile # Build and development commands
Packages¶
shared - @inboundx/shared¶
Core shared TypeScript package containing:
| Component | Description |
|---|---|
| Components | React components (RoseWidget, ExpandedChatView, etc.) |
| Services | API services with adapter support |
| Adapters | Storage and network adapters for different environments |
| Utils | Utility functions (color, language, theme, conversation) |
| Types | Comprehensive TypeScript type definitions |
| Hooks | Custom React hooks |
widget¶
Standalone JavaScript widget for website integration:
- Output:
inboundx-widget.js- UMD bundle optimized for embedding - Usage: Can be embedded in any website with simple script tag
- Adapters: Uses WebStorageAdapter and FetchNetworkAdapter
preprod-ui¶
Pre-production testing interface built with Vite:
- Purpose: Test widget with different client configurations
- Features: Client selector, environment switching, live preview
- Tech: Vite + React with hot reloading
chrome-plugin¶
Chrome extension using shared components:
- Adapters: ChromeStorageAdapter and ChromeNetworkAdapter
- Background Script: Handles webhook calls and CORS bypass
- Content Script: Injects chat widget into web pages
client-backoffice¶
Client configuration dashboard deployed to Cloudflare Pages:
- Purpose: Client management and configuration
- Deployment: Cloudflare Pages with branch-based environments
Adapter Pattern¶
The architecture uses adapters to handle different environments:
Storage Adapters¶
| Adapter | Use Case | Backend |
|---|---|---|
| WebStorageAdapter | Web widgets, preprod-ui | localStorage |
| ChromeStorageAdapter | Chrome extension | chrome.storage.local |
| ConfigurableStorageAdapter | Testing | Dynamic selection |
Network Adapters¶
| Adapter | Use Case | Method |
|---|---|---|
| FetchNetworkAdapter | Web widgets, preprod-ui | Direct fetch() API |
| ChromeNetworkAdapter | Chrome extension | chrome.runtime.sendMessage() |
Benefits¶
- Environment Abstraction: Same code works across deployment targets
- CORS Handling: Chrome extension adapter bypasses CORS via background script
- Storage Flexibility: Consistent API regardless of storage mechanism
- Testing Support: Configurable adapters for comprehensive testing
Communication Architecture¶
Chrome Extension Message Flow¶
Key Components:
- ChromeNetworkAdapter: Sends messages with tracking IDs
- Background Script: Makes HTTP requests (bypasses CORS)
- Message Types:
toggleWidget,checkSiteSupport,callWebhook
Web Widget Communication¶
Direct HTTP communication without message passing overhead.
Key Features¶
Widget Initialization¶
The widget follows a provider chain pattern:
- SiteConfigProvider - Initializes Supabase, loads site configuration, creates InboundXService
- AnalyticsProvider - Initializes PostHog with config data
- DisplayController - Waits for analytics ready, checks traffic allocation, evaluates display rules
- RoseWidget - Renders appropriate view based on state (collapsed/expanded/minimized)
Each layer must complete before the next begins. If any layer fails, the widget fails closed (doesn't render).
LocalStorage Structure¶
All data consolidated under single "rose" key (managed by RoseStorageManager):
localStorage.rose = {
version: 1,
widget: {
settings: {
logLevel: string | null,
namedLogLevels: Record<string, string>
},
analytics: {
counters: { widgetImpressions, messagesSent, ctaClicks, formsSubmitted, loginClicks },
lastSessionId: string | null,
lastActiveSessionId: string | null,
lastActiveSessionDate: number | null,
clientId: string | null, // Stable client ID for traffic control bucketing
apiVersion: string | null,
frontendVersion: string | null,
offlineQueue: { evaluations: [], conversations: [] }
},
trafficControl: { // Traffic allocation decision cache
clientId: string,
trafficAllocated: number,
enabled: boolean,
bucket: number, // 0-99 deterministic bucket
timestamp: number
} | null
},
preprod?: { config, endpoint, client, iframe } // Only in preprod-ui
}
Additional keys used:
| Key Pattern | Purpose |
|---|---|
inboundx_chat_state_${siteName} |
Per-domain conversation state (messages, expand/minimize) |
inboundx_session_${apiUrl} |
Session ID per API endpoint (sessionStorage) |
Form Detection & Tracking¶
Automatic form detection for conversion tracking:
- SuperformStrategy: Webflow Superform multi-step forms
- CTAPageFormStrategy: Standard forms on CTA pages
- Cross-Subdomain Attribution: Cookie fallback for attribution
Build Outputs¶
| Package | Output | Purpose |
|---|---|---|
| shared/dist/ | TypeScript declarations, JS, CSS | Shared library |
| widget/dist/ | UMD bundle | Website embedding |
| preprod-ui/dist/ | Static files | Firebase hosting |
| chrome-plugin/dist/ | Extension files | Chrome Web Store |
| client-backoffice/dist/ | Static files | Cloudflare Pages |
Quick Commands¶
cd frontend
# Setup (run once per worktree)
just download-env all # Download environment files
just install # Install all dependencies
# Development
just dev # Build shared + start preprod UI (recommended)
just dev-shared # Watch shared package only
just dev-preprod # Pre-production UI only
just dev-client-backoffice # Client backoffice
# Building
just build # Build all packages
just build-chrome-plugin # Build Chrome extension
# Testing
just test # Run tests
just type-check # Type check all projects
Further Reading¶
- Frontend Setup - Setup instructions and development workflow
- Justfile Details - Deep dive into justfile commands
- Widget Development - Two-step workflow for CSS/UI changes