|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. |
| 4 | + |
| 5 | +## Project Overview |
| 6 | + |
| 7 | +FixPanel is a modern React + Next.js + Tailwind multi-vertical demo platform that showcases Mixpanel's JavaScript SDK capabilities across different industries. The project demonstrates: |
| 8 | + |
| 9 | +- **Auto-capture**: Automatic tracking of clicks, page views, and form interactions |
| 10 | +- **Feature flagging**: Real-time content variants using Mixpanel experiments |
| 11 | +- **Session replay**: User session recording and playback |
| 12 | +- **Custom event tracking**: Manual events, profile updates, and A/B testing |
| 13 | +- **Console debugging**: Browser console prompts to guide users through Mixpanel features |
| 14 | + |
| 15 | +### Available Demo Verticals |
| 16 | + |
| 17 | +The platform includes multiple industry-specific microsites: |
| 18 | + |
| 19 | +#### Fully Implemented Verticals |
| 20 | +- **Financial Services - iBank** (`/financial/*`) - Banking, investments, and personal finance demo with complete user flows |
| 21 | +- **Healthcare & Wellness - ourHeart** (`/wellness/*`) - Medical consultation and symptom tracking demo with chat, voting, and case submission features |
| 22 | + |
| 23 | +#### Scaffolded Verticals (Basic UI, minimal functionality) |
| 24 | +- **Ecommerce - weBuy** (`/checkout/*`) - Product discovery, cart optimization, and checkout analytics |
| 25 | +- **Media & Streaming - meTube** (`/streaming/*`) - Content engagement and subscription optimization |
| 26 | +- **SaaS B2B - youAdmin** (`/admin/*`) - Feature adoption and user journey optimization |
| 27 | +- **Subscription B2C - theyRead** (`/lifestyle/*`) - Consumer engagement and retention |
| 28 | + |
| 29 | +## Development Commands |
| 30 | + |
| 31 | +### Core Commands |
| 32 | +- `npm run dev` - Start development server (http://localhost:3000) |
| 33 | +- `npm run build` - Build for production (includes copying oneoffs folder to output) |
| 34 | +- `npm start` - Start production server |
| 35 | +- `npm run lint` - Run ESLint |
| 36 | +- `npm run typecheck` - Run TypeScript type checking |
| 37 | + |
| 38 | +### Testing & Serving Commands |
| 39 | +- `npm run sanity` - Serve development build locally from ./dev/ |
| 40 | +- `npm run sanity:prod` - Serve production build locally from ./out/ |
| 41 | +- `npm run oneoffs` - Serve oneoffs directory standalone |
| 42 | +- `npm run prune` - Clean the output directory |
| 43 | +- `npm run test` - Run all Playwright browser tests |
| 44 | +- `npm run test:smoke` - Run smoke tests only |
| 45 | +- `npm run test:ui` - Run tests in interactive UI mode |
| 46 | + |
| 47 | +### Build Process |
| 48 | +The build command (`npm run build`) uses Next.js static export and includes a post-build step (`postbuild` script) that automatically copies all oneoff microsites from `./oneoffs/` to `./out/` for deployment alongside the main app. The script excludes build artifacts like `node_modules/`, `package.json`, and `package-lock.json`. `copy-oneoffs.js` also copies `./deliverables/` (including subdirectories, e.g. `deliverables/gartner/` and its images) to `out/`. Pages serves the uploaded artifact directly (no Jekyll), so subfolders/images/fonts ship as-is. |
| 49 | + |
| 50 | +## Deliverables (large self-contained HTML decks) |
| 51 | + |
| 52 | +`./deliverables/*.html` are big, standalone client decks (often **300KB–500KB**) with brand fonts embedded as base64 `data:` URIs. Treat them carefully: |
| 53 | + |
| 54 | +- **Don't read/echo the whole file** — the base64 blobs will blow up context. Inspect with targeted greps and truncate base64, e.g. `grep -oE "@font-face[^}]*\}" f.html | sed -E 's/(base64,)[A-Za-z0-9+/=]+/\1.../g'`, or just count (`grep -o "local(" f | wc -l`). Note `@font-face` may be multi-line (use `node`/`grep -z` if so). |
| 55 | +- **Fonts must be embedded + fallback-safe.** Garnett and Apercu Mono Pro are **proprietary Mixpanel brand fonts — not on any public CDN**, so inline woff2 `data:` URIs are the delivery mechanism. Each `@font-face` should be `src: url('data:font/woff2;base64,…') format('woff2')` **only**. |
| 56 | + - **No `local()`** in `src`: a viewer's broken/mismatched locally-installed font silently overrides the embed and renders garbled glyphs — with **no console error** (this caused a real "broken fonts" report). `local()` also gives nothing here since the font is already inline. |
| 57 | + - **No external refs** like `url('./assets/fonts/…woff2')` — those files aren't in the repo and 404. |
| 58 | + - Keep generic fallbacks in the family stacks/vars: `'Garnett',…,Arial,sans-serif` and `'Apercu Mono Pro',…,monospace`. |
| 59 | +- **Porting embedded fonts between decks:** the `data:` URI contains `;base64`, so a naive non-greedy regex stopping at the first `;` truncates it. Capture the full token (`url\('[^']*'\)\s*format\([^)]*\)`); the single-quoted data URI has no `'` inside, so `[^']*` is safe. |
| 60 | +- **Verify rendering** before shipping: serve `./deliverables` and load in a browser (use a non-blocked port — Chromium rejects 5060/6000); check `document.fonts` shows each face `loaded` and a heading's computed `font-family` resolves to the brand font, not Times. |
| 61 | + |
| 62 | +## Code Architecture |
| 63 | + |
| 64 | +### Key Architecture Patterns |
| 65 | + |
| 66 | +**Client-Side Only App**: This is a Next.js app configured for static export (`output: "export"`) with all components marked as `"use client"`. Server-side rendering is minimal - only the root layout runs on server. The app is configured for GitHub Pages deployment with appropriate basePath and assetPrefix settings. |
| 67 | + |
| 68 | +**Mixpanel Integration**: |
| 69 | +- Initialization happens in `app/ClientLayout.tsx` via `initMixpanel()` from `lib/analytics.ts` |
| 70 | +- Mixpanel is configured with comprehensive auto-capture settings: |
| 71 | + - Page views, clicks, form inputs, scrolling, and form submissions |
| 72 | + - Session recording enabled at 100% capture rate |
| 73 | + - Feature flags and experiments support |
| 74 | +- Console logging is patched to show Mixpanel events for demo purposes |
| 75 | +- Global `window.mixpanel` and `window.RESET()` function exposed for debugging |
| 76 | +- Dynamic user identification via URL parameters (`?user=`) |
| 77 | + |
| 78 | +**Feature Flag Architecture**: The `components/Modal.tsx` demonstrates feature flagging: |
| 79 | +- Fetches experiment variant via `mixpanel.flags.get_variant_value()` |
| 80 | +- Displays different modal content based on flag value |
| 81 | +- Supports 4 variants: "sarah story (A)", "marco portfolio (B)", "priya debt (C)", "no story (D)" |
| 82 | + |
| 83 | +### Directory Structure |
| 84 | +- `app/` - Next.js app router with microsite structure: |
| 85 | + - `page.tsx` - Main landing page with vertical selection |
| 86 | + - `financial/` - iBank financial services demo (fully implemented) |
| 87 | + - `wellness/` - ourHeart healthcare & wellness demo (fully implemented) |
| 88 | + - `chat/` - Medical consultation chat interface |
| 89 | + - `vote/` - Symptom voting feature |
| 90 | + - `submit/` - Case submission flow |
| 91 | + - `case/` - Case details view |
| 92 | + - `results/` - Test results display |
| 93 | + - `checkout/` - weBuy ecommerce demo |
| 94 | + - `streaming/` - meTube media & streaming demo |
| 95 | + - `admin/` - youAdmin SaaS B2B demo |
| 96 | + - `lifestyle/` - theyRead subscription B2C demo |
| 97 | +- `components/` - Reusable React components, including shadcn/ui components |
| 98 | +- `lib/` - Utility functions, primarily Mixpanel setup and class merging utilities |
| 99 | +- `public/` - Static assets |
| 100 | +- `oneoffs/` - Standalone one-off demo microsites (copied to build output during postbuild): |
| 101 | + - `payments/` - PayFlow payment demo (vanilla HTML/CSS/JS) |
| 102 | + - `dev/` - Developer demo microsite |
| 103 | + - `hud/` - HUD demo microsite |
| 104 | + - `metube/` - MeTube YouTube-like demo (Note: separate from meTube lifestyle vertical) |
| 105 | + - `mixstake/` - iGaming casino & sportsbook demo (`index.html` = demo site, `admin.html` = browser-SDK event generator + demo-URL builder) |
| 106 | + - (and others: `allchat/`, `dunkin/`, `feature-flags-console/`, `mixtape/`) — the listing at `oneoffs/index.html` is auto-generated at build, so this list may lag |
| 107 | +- `scripts/` - Build and automation scripts: |
| 108 | + - `copy-oneoffs.js` - Postbuild script that copies oneoffs to output |
| 109 | + - `generate-oneoffs-index.js` - Generates `oneoffs/index.html` by scanning subdirectories (run during postbuild) |
| 110 | +- `out/` - Production build output directory (includes Next.js build + oneoffs) |
| 111 | +- `dev/` - Development assets for local testing |
| 112 | + |
| 113 | +### Component Patterns |
| 114 | +- Uses shadcn/ui component library with Radix UI primitives |
| 115 | +- Tailwind CSS for styling with custom color palette |
| 116 | +- Framer Motion for animations (v11.3.30) |
| 117 | +- Lucide React for icons |
| 118 | +- Components follow the pattern of importing from `@/components/ui/` |
| 119 | +- TypeScript with strict configuration and path aliasing |
| 120 | + |
| 121 | +### Styling System |
| 122 | +- Custom Tailwind configuration with brand colors: |
| 123 | + - Primary purple: `#7856FF` |
| 124 | + - Green: `#07B096` and `#1C782D` |
| 125 | + - Red: `#CC332B` |
| 126 | + - Orange: `#DA6B16` |
| 127 | +- Uses CSS custom properties for theme system |
| 128 | +- Tailwind CSS Animate for animation utilities |
| 129 | +- Prettier configured with 120 character line width |
| 130 | + |
| 131 | +### Environment Configuration |
| 132 | +- Uses environment variable `REACT_APP_MIXPANEL_TOKEN` (defaults to demo project token) |
| 133 | +- Mixpanel proxy configured: `https://express-proxy-lmozz6xkha-uc.a.run.app` |
| 134 | +- URL parameters can include `?user=` for identification |
| 135 | +- Production deployment configured for GitHub Pages with proper paths |
| 136 | + |
| 137 | +## Demo-Specific Features |
| 138 | + |
| 139 | +### Multiple Demo Modes |
| 140 | + |
| 141 | +**Core FixPanel Microsites** (Next.js-based): |
| 142 | +- **Main Landing Page** (`/`) - Industry vertical selection with animated cards |
| 143 | +- **Financial Services - iBank** (`/financial/*`) - Complete banking and finance demo with multiple user journeys |
| 144 | +- **Healthcare & Wellness - ourHeart** (`/wellness/*`) - Medical consultation platform with symptom wheel, chat, and case management |
| 145 | +- **Ecommerce - weBuy** (`/checkout/*`) - Product discovery and checkout demo |
| 146 | +- **Media & Streaming - meTube** (`/streaming/*`) - Content platform and reading demo |
| 147 | +- **SaaS B2B - youAdmin** (`/admin/*`) - Business tools and admin platform demo |
| 148 | +- **Subscription B2C - theyRead** (`/lifestyle/*`) - Consumer video subscription app demo |
| 149 | + |
| 150 | +**Oneoff Microsites** (standalone HTML/CSS/JS demos in `./oneoffs/`): |
| 151 | +- **PayFlow** (`/payments/`) - Payment flow with friction analysis demo |
| 152 | +- **Dev Demo** (`/dev/`) - Developer-focused demo microsite |
| 153 | +- **HUD Demo** (`/hud/`) - HUD interface demo |
| 154 | +- **MeTube** (`/metube/`) - YouTube-like video platform demo (Note: separate from meTube lifestyle vertical) |
| 155 | +- **MixStake** (`/mixstake/`) - iGaming casino & sportsbook demo (iGaming events, UTM attribution, experiments). `index.html` is the demo site; `admin.html` fires batches of events from the browser SDK and builds variant/UTM demo URLs. |
| 156 | + |
| 157 | +These oneoff microsites are automatically copied to the build output during the postbuild step and deployed alongside the main app. |
| 158 | + |
| 159 | +**Oneoff convention** (follow this when adding one): |
| 160 | +- Self-contained, **client-side only** — vanilla HTML/CSS/JS, no build step, no server. Entry point is `index.html`; extra pages (e.g. `admin.html`) are allowed. |
| 161 | +- Initialize Mixpanel with the oneoff's **own project token** and the shared proxy `api_host: 'https://express-proxy-lmozz6xkha-uc.a.run.app'` (matches all other oneoffs). Do **not** set `remote_settings_mode` — the proxy has no `/settings/` route and it will 404 in the console. |
| 162 | +- No registration needed: `generate-oneoffs-index.js` auto-lists it and `copy-oneoffs.js` copies it to `out/` at build. Optionally add a link in `app/page.tsx` (the "Additional standalone demos" row). |
| 163 | + |
| 164 | +### Shared Infrastructure |
| 165 | +- **Header Component**: Context-aware navigation that adapts to each microsite |
| 166 | +- **Reset Functionality**: Global user reset available on all pages via `window.RESET()` |
| 167 | +- **Mixpanel Integration**: Consistent tracking across all verticals |
| 168 | +- **Styling System**: Shared Tailwind theme with vertical-specific color palettes |
| 169 | +- **Static Export**: Configured for GitHub Pages deployment with Next.js static export |
| 170 | + |
| 171 | +### Mixpanel Demo Configuration |
| 172 | + |
| 173 | +**Project Architecture**: |
| 174 | +- All microsites send data to the same Mixpanel project (ID: `3276012`) |
| 175 | +- Each vertical has its own dedicated data view for filtering and analysis |
| 176 | +- Vertical-specific Mixpanel data views: |
| 177 | + - **weBuy** (Ecommerce): [View 4354009](https://mixpanel.com/report/3276012/view/4354009) |
| 178 | + - **iBank** (Financial): [View 4354010](https://mixpanel.com/report/3276012/view/4354010) |
| 179 | + - **meTube** (Media): [View 4354011](https://mixpanel.com/report/3276012/view/4354011) |
| 180 | + - **youAdmin** (SaaS): [View 4354012](https://mixpanel.com/report/3276012/view/4354012) |
| 181 | + - **ourHeart** (Healthcare): [View 4354013](https://mixpanel.com/report/3276012/view/4354013) |
| 182 | + - **theyRead** (Social): [View 4354015](https://mixpanel.com/report/3276012/view/4354015) |
| 183 | + |
| 184 | +**Technical Configuration**: |
| 185 | +- Pre-configured with demo project token: `7c02ad22ae575ab4e15cdd052cd730fb` |
| 186 | +- Header and Footer Mixpanel links automatically route to the appropriate vertical-specific view |
| 187 | +- Session recording enabled with 100% capture rate |
| 188 | +- Comprehensive auto-capture configured: |
| 189 | + - Page views (with scroll tracking) |
| 190 | + - Click events on all elements |
| 191 | + - Form inputs and changes |
| 192 | + - Form submissions |
| 193 | + - Scroll depth tracking |
| 194 | +- Debug mode with console logging for all Mixpanel calls |
| 195 | +- Feature flag experiment `exp_customerStory` controls homepage modal |
| 196 | +- Custom session management with reset functionality |
| 197 | + |
| 198 | +### Live Demo URLs |
| 199 | +- Production site: https://mixpanel.github.io/fixpanel/ |
| 200 | +- GitHub repository: https://github.com/mixpanel/fixpanel |
| 201 | +- Mixpanel project: https://mixpanel.com/project/3276012/view/3782804/app/events |
| 202 | +- Internal docs: https://www.notion.so/mxpnl/Fixpanel-1ece0ba9256280b9b10ad1ad09b80bca |
| 203 | + |
| 204 | +**Vertical-Specific Mixpanel Views**: |
| 205 | +- weBuy (Ecommerce): https://mixpanel.com/report/3276012/view/4354009 |
| 206 | +- iBank (Financial): https://mixpanel.com/report/3276012/view/4354010 |
| 207 | +- meTube (Media): https://mixpanel.com/report/3276012/view/4354011 |
| 208 | +- youAdmin (SaaS): https://mixpanel.com/report/3276012/view/4354012 |
| 209 | +- ourHeart (Healthcare): https://mixpanel.com/report/3276012/view/4354013 |
| 210 | +- theyRead (Social): https://mixpanel.com/report/3276012/view/4354015 |
| 211 | + |
| 212 | +## TypeScript Configuration |
| 213 | +- Uses strict TypeScript configuration |
| 214 | +- Path aliasing: `@/*` maps to project root |
| 215 | +- Includes type definitions for Mixpanel browser SDK |
| 216 | +- Some Mixpanel integrations use `@ts-ignore` due to type limitations |
| 217 | + |
| 218 | +## Testing Infrastructure |
| 219 | +- Playwright for browser testing. Two project tiers in `playwright.config.ts`: |
| 220 | + - **`chromium`** (core app) — runs against `npm run dev` on `:3000`. Strict tests in `tests/e2e/` (e.g. `smoke.spec.ts`) asserting Mixpanel tracking behavior. |
| 221 | + - **`oneoffs`** (advisory) — runs `tests/e2e/oneoffs.spec.ts` against a static server (`npx serve ./oneoffs -l 5050`). Permissive: auto-discovers every `oneoffs/*/**.html` and only asserts the page loads with no uncaught JS errors (analytics/network noise ignored). New oneoffs are covered automatically. |
| 222 | +- Commands: `npm run test:app` (core, required gate) · `npm run test:oneoffs` (advisory) · `npm run test:smoke` · `npm run typecheck` · `npm run lint`. |
| 223 | + |
| 224 | +## CI & Branch Protection |
| 225 | +- CI: `.github/workflows/nextjs.yml` runs on every PR/push: jobs `verify` (lint), `build` (Next.js build + `typecheck` — typecheck runs here because it needs the build-generated `next-env.d.ts` for asset module types), `test-app` (`test:smoke`), and `test-oneoffs`. `deploy` runs only on push to `main`. |
| 226 | +- `main` is protected (`enforce_admins: true` — **no one pushes directly, incl. admins**). All work lands via PR. |
| 227 | +- Required status checks (block merge): **`verify`, `build`, `test-app`**. `test-oneoffs` is **advisory** (runs but does not block) — intentionally permissive so a contributor's own oneoff can't block their merge. |
| 228 | +- 0 required approvals → contributors **squash-merge their own PRs**. |
| 229 | +- When changing CI job names or adding required checks, keep the branch-protection `contexts` list in sync (set via `gh api repos/mixpanel/fixpanel/branches/main/protection`). |
| 230 | + |
| 231 | +## Dependencies Overview |
| 232 | +- **Core**: Next.js 14.2.7, React 18, TypeScript 5 |
| 233 | +- **UI**: Radix UI components, shadcn/ui, Tailwind CSS |
| 234 | +- **Analytics**: Mixpanel Browser SDK 2.71.0 |
| 235 | +- **Animation**: Framer Motion 11.3.30 |
| 236 | +- **Icons**: Lucide React |
| 237 | +- **Testing**: Playwright 1.40+ |
| 238 | +- **Utilities**: clsx, tailwind-merge, class-variance-authority |
0 commit comments