Optional onboarding flow for new users to complete their profile before accessing the dashboard.
Toggle with NEXT_PUBLIC_ONBOARDING_ENABLED.
Onboarding Flow
Onboarding primarily collects profile fields after checkout. In B2B, the workspace is normally created earlier by the automatic bootstrap so billing can target a workspace account. The middleware does not block /checkout only because a profile is incomplete; the profile gate decision is made in checkout/success/page.tsx.
- User signs up — magic link / OTP code / OAuth. The database trigger creates the personal account.
- B2B workspace bootstrap — if
businessModelis'b2b', server-side auth/checkout paths callensureWorkspaceForUser()so the subscription has a workspace target./onboarding/workspaceremains a fallback if bootstrap fails. - Plan + payment — the user continues to
/checkoutfrom the pending-checkout cookie. The configured provider's hosted checkout completes, or/api/billing/subscribe-freecreates the free subscription on the correct account. - Success page decision —
checkout/success/page.tsxreadsprofile.onboarding_completed. Iffalse, the success CTA leads to/onboarding; otherwise straight to a dashboard (workspace-manager rule:/org-dashboardfor owners/admins, else/private-dashboard). - Form submission —
OnboardingFormposts first/last name + optional birthday + phone toPOST /api/user/onboarding. The handler requires the canonical application actor before its parsing or persistence; the wrapper retains its earlier bounded body-size check, CSRF and strict rate limit. Existing Zod validation and sanitization are preserved. Provider email and metadata supply display fields only. The core helper writes the canonical profile and requires an exact matching completion receipt before audit and destination lookup, both scoped to that same actor. Responses are private/no-store; missing identity returns 503, malformed JSON returns 400, and failed or malformed write receipts return a generic 500. Signup analytics remains fire-and-forget; the referral-attribute fallback is awaited but errors remain non-blocking so a payment that committed first can be reconciled before navigation. - Post-submit redirect — routes the user to the appropriate dashboard via the same workspace-manager rule. If a B2B user still has no workspace, they are sent back to
/onboarding/workspace.
(private)/layout.tsx server-side guard also redirects any B2B user
without a workspace membership to /onboarding/workspace. This catches users who skipped onboarding,
accepted the cookie cache, or were imported via SQL.
Collected Fields
| Field | Required | Description |
|---|---|---|
| First Name | Yes | User's first name — Zod-validated min(2).max(50) chars. |
| Last Name | Yes | User's last name — Zod-validated min(2).max(50) chars. |
| Phone | No | Contact phone number (optional). |
| Birthday | No | Date of birth (optional) — minimum age 13 (Zod refinement against the current date). |
If the user reached /onboarding with a bsk_pending_checkout cookie set (the "clicked a plan before signing in" case), the post-submit redirect goes to /checkout instead of the dashboard. Otherwise the workspace-manager rule applies: owners/admins of any workspace land on /org-dashboard, everyone else on /private-dashboard.
Skipping Onboarding
When NEXT_PUBLIC_ONBOARDING_ENABLED=false:
- Middleware skips profile completeness check
- Users go directly to dashboard after auth
- Profile can be completed later in My Account page