URL: https://mkdocs.justinsforge.com/memory/general/reference_creatortrack_onboarding/
CreatorTrack New-User Onboarding Wizard¶
Built 2026-07-10 on branch feat/onboarding-wizard (plan: creatortrack-onboarding-wizard-2026-07-10). Merged to main 2026-07-11 (merge commit 5603bcf, later included in the 3306ade deploy train); LIVE on prod. Distinct from the older per-workspace guided tour (lib/onboarding.ts, /api/onboarding); the two coexist, the tour still fires after the wizard.
Flow¶
- Signup (
lib/auth-credentials.ts) redirects new users to/?welcome=1&verify=1(unchanged). - The
/root hop (app/(suite)/page.tsx) checksapp.onboarding_responses: no row means never seen the wizard, detour to/onboardingcarrying the query params. Deep links never detour;/onboardingbounces done users home, so no traps. - Wizard (
app/(onboarding)/onboarding/page.tsx+components/onboarding/OnboardingWizard.tsx): 7 questions, one per screen, progress bar, Skip link from Q2. Session-gated (not in proxy PUBLIC_PATHS). - Complete: POST
/api/onboarding/wizardupserts the row, subscribes opted-in emails to the Resend audience (best-effort, logged loud), returns 3-5 ranked apps. Final "Your starter setup" screen: cards with icon, one-line reason, early-access badge on preview apps (University), per-card deselect, "Install and continue" CTA hitting/api/onboarding/install. - Skip: row stamped
skipped_at, default set (tasks, calendar, knowledge) auto-installed server-side, straight into the app.
Data¶
app.onboarding_responses (migration 20260710T225738_...onboarding_wizard_responses.sql): user_id PK, answers jsonb, email_opt_in, completed_at, skipped_at. Per-user RLS (app.user_id GUC pattern). All pre-existing users were grandfathered with a {"grandfathered": true} skipped row so they never see the wizard. Upserts are idempotent; completed/skipped stamps are first-write-wins.
Recommendation engine¶
lib/onboarding-wizard.ts: weighted scoring question:answer -> appId (learn -> university, organize -> tasks/projects/calendar, clips goal -> clips, sponsor -> sales, money -> finance/business, grow -> content-research/social). Availability-filtered through the App Library chokepoints (isAppAllowedForEmail, isAppAllowedInWorkspace, owner-only gates), so allowlisted apps (Clips, Content Research) never surface to users who cannot install them; backfills from the default set to a minimum of 3. Installs reuse installSystemApp / addInstalledApp (the exact App Library path). Canned checks: scripts/smoke-onboarding-wizard.ts (npx tsx).
Email opt-in (Resend)¶
Audience "CreatorTrack Updates", id in ~/.forge-secrets/resend.env as RESEND_UPDATES_AUDIENCE_ID (created 2026-07-10 via API, id 4680c9f5-2303-414d-a440-c7cc7940f6b9). subscribeToUpdatesAudience() in lib/email.ts; contact upserts are idempotent. Subscribe failures never block onboarding completion.
PostHog events¶
onboarding_started, onboarding_question_answered (question_id, answer), onboarding_skipped (at_step), onboarding_completed (email_opt_in), onboarding_app_installed (app_id). Client capture via the existing PostHogClient mount (runtime POSTHOG_KEY gating), also mounted by app/(onboarding)/layout.tsx. Gotcha: posthog-js silently drops all events from HeadlessChrome (bot UA filter); verify with a real UA override, not vanilla Playwright.
Merge status¶
- Merged to main 2026-07-11 (merge commit 5603bcf, later included in the 3306ade deploy train). Migration
20260710T225738_feat_onboarding_wizard_onboarding_wizard_responses.sqlapplied to prod lifeos on 2026-07-11; its grandfather insert protected every existing prod user. - Env:
RESEND_UPDATES_AUDIENCE_IDalready in~/.forge-secrets/resend.env; prod service loads resend.env vialib/secrets.ts(it does, same file). - No PUBLIC_PATHS/proxy change needed.
[Claude Code]