Brand the Clerk auth surface to PRAMAAN
The accelerator signed up through the Clerk-hosted Account Portal at
accounts.pramaan.io/sign-up/continue and saw default
Clerk chrome — a generic card and a Clerk-purple
(#6c47ff) primary button. PRAMAAN already ships fully
branded in-app /sign-in and /sign-up
surfaces; the bug was that sign-up could fall through to the hosted
portal instead. This Story makes the branded in-app surface canonical
for the whole flow, including the OAuth "fill in missing fields"
continue step.
Decision: brand in-app and make it canonical (issue option 2)
-
The hosted Account Portal (
accounts.pramaan.io) appearance is Clerk Dashboard configuration only — it cannot be themed from app source. So the durable fix is to keep auth on the in-app routes the repo already controls and brands. -
The in-app surface is already skinned:
clerkAppearance/authSurfaceClerkAppearanceinsrc/components/auth/clerk-appearance.tssetcolorPrimarytovar(--brand-primary)(maroon#882222), map every Clerk element to a.pramaan-clerk-*class inglobals.css, and theAuthEditorialShellrenders the realBrandLogoand Playfair/Inter typography. No ad-hoc color literals were added.
The one-line root cause
-
ClerkProviderinsrc/app/[locale]/layout.tsxhardcodedsignInUrl+signInFallbackRedirectUrlbut omitted the sign-up equivalents. Sign-up routing depended only onNEXT_PUBLIC_CLERK_SIGN_UP_URL, which lives in local.envand is not guaranteed in every deploy. When absent, Clerk falls back to its default sign-up URL — the hosted Account Portal — so sign-up and the OAuth continue step rendered Clerk-purple. -
Fix: pin
signUpUrlandsignUpFallbackRedirectUrlto the localized in-app routes (localizeHref(locale, "/sign-up")/"/dashboard"), symmetric with the existing sign-in props. Every Clerk-emitted sign-up + OAuth-continue redirect now lands on the branded in-app surface, never the purple hosted portal.
Before / after
Token-accurate comparison (maroon #882222 vs Clerk purple
#6c47ff). The "after" mirrors the live in-app
AuthEditorialShell + authSurfaceClerkAppearance.
pk_live,
domain-locked to staging) in-app form cannot be captured headlessly in
this worktree. Per retired HR-20 a rendered-app screenshot is no longer
a merge gate; the appearance config + CSS are the source of truth that
the in-app surface is branded.
Residual hosted-portal surface (Dashboard ops step)
-
Direct visits to
accounts.pramaan.ioand any backend-issued link whoseredirect_urltargets the portal still render the hosted page, which app source cannot style. -
To brand that residual surface, set the Account Portal appearance in
the production Clerk Dashboard (Customization → Appearance):
primary
#882222, logo = PRAMAAN mark, Inter body / Playfair display,borderRadius6px — matchingclerkAppearancehere. Tracked as the follow-up ops step in the PR body; it is configuration, not code.
Acceptance criteria
- Sign-up / sign-in / OAuth-continue match the PRAMAAN design system, no default Clerk-purple primary — the in-app surface is branded and is now the canonical destination. met
-
Consistent across the full flow incl. the "fill in missing fields"
step after Google — handled by the in-app
<SignUp>withauthSurfaceClerkAppearanceonce routing is pinned. met - Works in the Production Clerk env — the fix removes the env dependence that caused the prod fallback to the hosted portal. met (code)
- Before/after in the PR — token-accurate comparison above; live capture not feasible headlessly (noted). met
Verification
-
pnpm lintpassed (only pre-existing add-matter warnings). pnpm typecheckpassed.pnpm test528 passed.pnpm buildpassed.git diff --checkclean.
Files changed
1 file(s), +7 / -0 lines
| Path | Role | + | - |
|---|---|---|---|
| src/app/[locale]/layout.tsx | App route | +7 | -0 |