Frontend Setup¶
Prerequisites¶
- Node.js 18+
- npm
- gcloud CLI (authenticated)
Quick Start¶
From the repository root, run the bootstrap script:
This handles everything: downloads environment files, installs backend and frontend dependencies.
Manual Setup (Frontend Only)¶
If you prefer to set up just the frontend, or need to understand each step:
Step 1: Download Environment Files¶
This downloads environment files from Google Secret Manager. The .env.test file is required for development servers.
First time only: If you get permission errors, run cd backend && just setup-secrets first.
Step 2: Install Dependencies¶
Step 3: Start Development¶
For detailed information about what each command does, see Justfile Details.
Development Servers¶
Standard Development Flow¶
- Setup: Run
./bootstrap.pyor manual steps above (once per worktree) - Start dev server:
just dev - Make changes in
shared/or other packages - Build all projects with
just build
Development Commands¶
cd frontend
# Recommended: Build shared + start preprod UI with hot reload
just dev
# Alternative dev servers
just dev-shared # Watch shared package only
just dev-preprod # Start preprod UI only (assumes shared is built)
just dev-client-backoffice # Build shared + start client backoffice
Widget Integration¶
Recommended: Using Rose Loader¶
The Rose Loader handles React loading, error handling, and initialization:
<script src="https://cdn.userose.ai/loader/rose-loader.js"></script>
<script>
window.InboundXLoader.init({
api_key: "YOUR_API_KEY",
api_host: "https://api.userose.ai/rose",
cdn_url: "https://cdn.userose.ai/widget/YOUR_DOMAIN"
});
</script>
For localhost/development:
<script src="https://cdn.userose.ai/loader/rose-loader.js"></script>
<script>
window.InboundXLoader.init({
api_key: "YOUR_API_KEY",
api_host: "https://api.userose.ai/rose",
cdn_url: "https://cdn.userose.ai/widget/YOUR_DOMAIN",
debug: true, // Enable console logging
forceDomain: "supported-domain.com" // Override domain for localhost
});
</script>
Direct Widget Initialization (Advanced)¶
For environments where the loader isn't suitable:
<script src="https://cdn.userose.ai/widget/YOUR_DOMAIN/inboundx-widget.js"
data-inboundx-auto-init="true"
data-api-key="YOUR_API_KEY"
data-api-url="https://api.userose.ai/rose"
data-site-name="example.com"></script>
Or via JavaScript:
InboundXWidget.init({
apiUrl: 'https://api.userose.ai/rose',
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 from the environment files:
Building¶
Build All Packages¶
Individual Builds¶
just build-widget # Build widget only
just build-preprod-ui # Build preprod UI only
just build-chrome-plugin # Build Chrome extension
just build-client-backoffice # Build client backoffice
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
Troubleshooting¶
"Error: .env.test file is missing"¶
See Justfile Details - Troubleshooting for more solutions.
TypeScript Errors in Shared Package¶
Ensure shared package is built:
Chrome Extension Not Loading¶
- Check that environment files are downloaded:
ls .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