Skip to content

Frontend Setup

Prerequisites

  • Node.js 18+
  • npm
  • gcloud CLI (authenticated)

Quick Start

From the repository root, run the bootstrap script:

./bootstrap.py

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

cd frontend
just download-env all

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

just install

Step 3: Start Development

just dev

For detailed information about what each command does, see Justfile Details.

Development Servers

Standard Development Flow

  1. Setup: Run ./bootstrap.py or manual steps above (once per worktree)
  2. Start dev server: just dev
  3. Make changes in shared/ or other packages
  4. 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

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:

# Download env files first
just download-env all

# Then build
just build-chrome

Building

Build All Packages

cd frontend
just build

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

cd frontend
just test

Type Checking

cd frontend
just type-check

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:

  • main branch → production (app.userose.ai)
  • staging branch → staging (appstaging.userose.ai)
  • develop branch → 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:

cd frontend
just gen-types

This generates type-safe database types at frontend/shared/src/types/database.ts.

Never Use Manual Type Assertions

// ❌ Bad
return data as unknown as MyType;

// ✅ Good: Use generated types
type MyTableRow = Database['public']['Tables']['my_table']['Row'];

Troubleshooting

"Error: .env.test file is missing"

cd frontend
just download-env test

See Justfile Details - Troubleshooting for more solutions.

TypeScript Errors in Shared Package

Ensure shared package is built:

cd frontend
just build-widget  # or just dev to build and watch

Chrome Extension Not Loading

  1. Check that environment files are downloaded: ls .env.*
  2. Rebuild: just build-chrome
  3. Reload extension in Chrome

Widget Not Appearing

  1. Check browser console for errors
  2. Verify data-site-name matches Supabase configuration
  3. Check traffic control settings in PostHog