Frontend Setup¶
Prerequisites¶
- Node.js 18+
- npm
Installation¶
Development Servers¶
Standard Development Flow¶
- Install dependencies:
just install(run once or when dependencies change) - Make changes in
shared/package - Test changes using preprod-ui with
just run-preprod - Build all projects with
just build - Test Chrome extension with
just dev-chrome
Development Commands¶
cd frontend
# Shared package (watch mode)
just dev-shared
# Widget development
just dev-widget
# Pre-production UI
just dev-preprod
# Run shared + preprod together (recommended)
just run-preprod
# Chrome extension
just dev-chrome
Widget Integration¶
Auto-initialization (Script Tag)¶
<script src="https://cdn.example.com/inboundx-widget.js"
data-inboundx-auto-init
data-api-url="https://api.inboundx.com"
data-site-name="example.com"></script>
Manual Initialization¶
InboundXWidget.init({
apiUrl: 'https://api.inboundx.com',
siteName: 'example.com',
domain: 'example.com'
});
Chrome Extension Development¶
The Chrome extension uses shared components:
import { RoseWidget } from '@inboundx/shared';
import { ChromeStorageAdapter, ChromeNetworkAdapter } from '../adapters/chrome-adapters';
<RoseWidget
storageAdapter={new ChromeStorageAdapter()}
networkAdapter={new ChromeNetworkAdapter()}
// ... other props
/>
API Key Management¶
The build process requires IX_API_KEY:
- Create
frontend/.envfile: - Build with:
just build-chrome
Building¶
Build All Packages¶
Individual Builds¶
Testing¶
Run Tests¶
Type Checking¶
Deployment¶
Pre-production UI (Firebase)¶
cd frontend
# Deploy to production
just deploy-preprod
# Deploy to test channel
just preview-preprod
Client Backoffice (Cloudflare Pages)¶
Deployed via GitHub Actions:
mainbranch → production (app.userose.ai)stagingbranch → staging (appstaging.userose.ai)developbranch → test (apptest.userose.ai)
Logging Configuration¶
Log Levels¶
| Environment | Default Level |
|---|---|
| Development | All levels (debug) |
| Production | warn and error only |
| Test | Silent |
Override Log Level¶
LOG_LEVEL=silent # Completely silent
LOG_LEVEL=error # Only errors
LOG_LEVEL=warn # Warnings and errors
LOG_LEVEL=info # Info, warnings, errors
LOG_LEVEL=debug # All levels
Usage¶
import { logger } from '@/utils/logger';
logger.debug('Debug information');
logger.info('User action', data);
logger.warn('Deprecated feature used');
logger.error('API failed', error);
Important
Always use logger from @/utils/logger.ts, never console.log.
Analytics Events¶
All PostHog events use rw_ prefix (Rose Widget):
| Event | Description |
|---|---|
rw_widget_impression |
Widget displayed to user |
rw_message_sent |
User sent a message |
rw_cta_clicked |
User clicked CTA button |
rw_client_form_submitted |
Form submission detected |
rw_demo_cta_rendered |
Demo CTA displayed |
rw_demo_cta_clicked |
Demo CTA clicked |
Event Deduplication¶
Best Practice
Handle deduplication at the component level, not in analytics functions.
// ✅ Correct: Component handles deduplication
useEffect(() => {
if (isVersionCompatible && currentSessionId && isInitialized) {
ChatAnalytics.trackWidgetImpression({ siteName });
}
}, [isVersionCompatible && currentSessionId && isInitialized]);
Supabase Type Generation¶
When the Supabase schema changes:
This generates type-safe database types at frontend/shared/src/types/database.ts.
Never Use Manual Type Assertions
Environment Configuration¶
Each package has environment-specific configuration:
| Package | Configuration |
|---|---|
| preprod-ui | Supabase auth, multiple API endpoints |
| chrome-plugin | API key injection during build |
| widget | Data attributes or manual init |
| shared | Adapter-based configuration |
Troubleshooting¶
TypeScript Errors in Shared Package¶
Ensure shared package is built:
Chrome Extension Not Loading¶
- Check that
IX_API_KEYis set infrontend/.env - Rebuild:
just build-chrome - Reload extension in Chrome
Widget Not Appearing¶
- Check browser console for errors
- Verify
data-site-namematches Supabase configuration - Check traffic control settings in PostHog