Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions .claude/memory/decisions.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ The following were evaluated and explicitly excluded from MVP. Do not reopen wit

---

## 2026-03-19 — jsdom version pinned to v24 for Node 20.11.1 compatibility ⚠️ SUPERSEDED
## 2026-03-19 — Landing page auth redirect (server-side)
**Decision**: auth() + redirect() in the Server Component at app/page.tsx.
**Reason**: Keeps proxy.ts free of per-page logic. Server Component redirect is instant — no client-side flash.
Expand All @@ -183,3 +184,36 @@ The following were evaluated and explicitly excluded from MVP. Do not reopen wit
**Decision**: Downgraded jsdom from v29 (installed by default) to v24 in devDependencies.
**Reason**: jsdom v29 requires Node >=20.19.0; the project runs on Node 20.11.1. v24 is compatible and supports all required testing features.
**Alternatives considered**: Upgrade Node (blocked — system constraint); skip component tests in jsdom (violates TDD mandate).
**SUPERSEDED BY**: "happy-dom for all vitest environments" decision below — jsdom was later abandoned entirely in favour of happy-dom due to a transitive ESM conflict.

---

## 2026-03-19 — happy-dom for all vitest environments
**Decision**: All vitest `environmentMatchGlobs` entries use `"happy-dom"` instead of `"jsdom"`.
**Reason**: `jsdom@29` (installed as transitive dep despite the v24 pin) pulls in `html-encoding-sniffer@6` which does a synchronous `require()` of `@exodus/bytes` (pure-ESM only). This crashes the jsdom environment with an unhandled error that exits vitest with code 1 even when all tests pass — failing CI. `happy-dom` (already installed) has no such transitive dependency and is fully compatible with all existing tests.
**Effect**: Both `components/__tests__/**/*.test.tsx` and `app/**/*.test.tsx` use `happy-dom`. 100/100 tests pass, zero unhandled errors.

---

## 2026-03-19 — Proxy loop guard for stale JWT
**Decision**: In `proxy.ts`, before redirecting to `/signup/complete` when `role` is missing, check `req.nextUrl.pathname === "/signup/complete"` and return early if true.
**Reason**: When the Clerk session token claim (`{{ user.public_metadata }}`) is not configured in the Clerk dashboard, or when a JWT was issued before a role was assigned, `sessionClaims.metadata.role` is undefined. Without the guard, the proxy redirects to `/signup/complete` even when the user is already there — causing a visible redirect loop. The `/signup/complete` page handles staleness client-side via `session.reload()`.
**Constraint**: Never call external APIs from `proxy.ts` (it is Next.js middleware running on the edge). The guard is a pure pathname check with no I/O.

---

## 2026-03-19 — Landing page auth redirect (server-side)
**Decision**: Authenticated user redirect on `/` handled via `auth()` + `redirect()` inside the Server Component (`app/page.tsx`), not in `proxy.ts`.
**Reason**: Keeps proxy.ts free of per-page redirect logic. Server Component redirect is synchronous and instant — no client-side flash. Role read from `(sessionClaims?.metadata as { role?: string })?.role`.

---

## 2026-03-19 — /signup hash detection for Clerk SSO compatibility
**Decision**: `/signup/page.tsx` reads `window.location.hash` on mount to decide between showing the role picker (direct visit) or `<SignUp>` (Clerk SSO multi-step flow).
**Reason**: Clerk SSO flows (Google, phone verification) redirect back to `/signup` with a hash fragment (`#/continue`, `#/factor-one`). Detecting the hash on one route preserves SSO compatibility without adding a new route. Direct visits (no hash) show the pre-auth role picker.

---

## 2026-03-19 — Button asChild not available; use Link + buttonVariants()
**Decision**: For anchor-styled buttons (links that look like buttons), use `Link` from `next/link` with `buttonVariants()` class applied directly — not `<Button asChild>`.
**Reason**: The project's `components/ui/button.tsx` wraps `@base-ui/react/button`, which does not expose a Radix-style `asChild` prop. Applying `buttonVariants()` to a `Link` achieves the same visual result without the prop.
47 changes: 44 additions & 3 deletions .claude/memory/iterations.md
Original file line number Diff line number Diff line change
Expand Up @@ -217,9 +217,40 @@ _Append only. One entry per session or PR. Never delete._

---

## 2026-03-19 — fix/pre-m3-proxy-loop
- Added /signup/complete loop guard to proxy.ts to prevent redirect loop on stale JWT
- When authenticated user has no role claim in JWT and is already on /signup/complete, proxy now returns immediately instead of redirecting again
## 2026-03-19 — fix/pre-m3-proxy-loop (PR #8)
**Type**: Bug fix
**Branch**: fix/pre-m3-proxy-loop
**What changed**:
- `proxy.ts` — added one-line loop guard: when an authenticated user has no role claim in their JWT and is already on `/signup/complete`, proxy returns immediately instead of redirecting again
- Prevents the infinite redirect loop that occurs when the Clerk JWT is stale (role claim not yet in token)
- JWT staleness is handled client-side by `session.reload()` in `/signup/complete` — proxy just stays out of the way
- `npm run typecheck` → zero errors ✅
- `npm run lint` → zero errors ✅
**PR**: https://github.com/parva3105/projectAlpha/pull/8

---

## 2026-03-19 — fix/pre-m3-landing-auth (PR #9)
**Type**: Feature + Bug fix
**Branch**: fix/pre-m3-landing-auth
**What changed**:
- `app/page.tsx` — replaced Next.js scaffold with branded landing page (Server Component); server-side auth redirect via `auth()` + `redirect()`; hero + 3 benefit blocks + 3 role cards; dark surface, Geist Sans, shadcn/ui Card + buttonVariants
- `app/(public)/signup/page.tsx` — replaced bare `<SignUp>` with `'use client'` role picker + Clerk SSO fallback; detects Clerk SSO flows via `window.location.hash` on mount (hash present = Clerk driving; no hash = role picker)
- `components/auth/signup-role-picker.tsx` — pre-auth role selection (Agency / Creator / Brand) with shadcn/ui Cards and correct hrefs; Server Component
- `components/auth/auth-layout.tsx` — shared two-panel auth layout Server Component (branded left panel hidden on mobile via `hidden md:flex`, Clerk right panel)
- `app/(public)/login/[[...rest]]/page.tsx` — wrapped in AuthLayout; forceRedirectUrl unchanged
- `app/(public)/signup/agency/[[...rest]]/page.tsx` — wrapped in AuthLayout; forceRedirectUrl unchanged
- `app/(public)/signup/creator/[[...rest]]/page.tsx` — wrapped in AuthLayout; forceRedirectUrl unchanged
- `app/(public)/signup/brand/[[...rest]]/page.tsx` — wrapped in AuthLayout; forceRedirectUrl unchanged
- `app/page.test.tsx` — 9 vitest tests for landing page
- `components/__tests__/auth-layout.test.tsx` — 3 vitest tests for AuthLayout
- `components/__tests__/signup-role-picker.test.tsx` — 3 vitest tests for SignupRolePicker
- `vitest.config.ts` — switched `app/**/*.test.tsx` and `components/__tests__/**/*.test.tsx` to `happy-dom` (from `jsdom`) to resolve CJS/ESM crash from `html-encoding-sniffer` v6 in jsdom v29
- All 100 tests pass ✅ (zero unhandled errors)
- `npm run typecheck` → zero errors ✅
- `npm run lint` → zero errors ✅
- `npm run build` → success ✅
**PR**: https://github.com/parva3105/projectAlpha/pull/9

---

Expand All @@ -236,3 +267,13 @@ _Append only. One entry per session or PR. Never delete._
- Fix applied to all branches: postinstall: "prisma generate" for Vercel build compatibility
- Total: 76 tests across 4 PRs, all passing
- All 13 M2 tasks delivered

---

## 2026-03-19 — CI fixes: test regex + vitest env (PR #9 follow-up)
**Type**: Bug fix
**Branch**: fix/pre-m3-landing-auth (commits 467669f, e579c71)
**What changed**:
- `app/page.test.tsx` line 70: tightened regex from `/get started/i` to `/^get started$/i` — the broad regex matched all 4 "Get started" links on the landing page causing `getByRole` to throw "Found multiple elements"
- `vitest.config.ts`: switched `components/__tests__/**/*.test.tsx` from `jsdom` to `happy-dom` to eliminate 5 unhandled errors from `html-encoding-sniffer` v6's synchronous `require()` of `@exodus/bytes` (pure-ESM); both globs now use `happy-dom`
- All 100 tests pass, zero unhandled errors, CI green
9 changes: 7 additions & 2 deletions .claude/memory/memory.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,13 @@
_Last updated: 2026-03-19_

## Current state
- Status: **M2 COMPLETE** ✅ — Ready to begin M3
- Active milestone: M3 — Creator Portal + Content Approval (next)
- Status: **M2 COMPLETE** ✅ — Pre-M3 fixes in progress (2 PRs open)
- Active milestone: Pre-M3 fixes → then M3 — Creator Portal + Content Approval

## Pre-M3 fixes in progress — 2 PRs open
- **PR #8** `fix/pre-m3-proxy-loop` — proxy.ts redirect loop guard (stale JWT)
- **PR #9** `fix/pre-m3-landing-auth` — landing page + /signup role picker + branded auth layouts
- ⚠️ Both PRs must be merged AND the Clerk dashboard step completed before M3 begins
- Production URL: https://project-alpha-rho.vercel.app (deployed, all env vars baked in)
- Vercel Root Directory: blank (repo root) — confirmed correct
- GitHub repo: https://github.com/parva3105/projectAlpha
Expand Down
7 changes: 7 additions & 0 deletions .claude/memory/roadmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@ M8 (Polish) ← depends on all milestones complete

---

## Pre-M3 — Regression fixes (2026-03-19)
- [🔄 PR Open] **PR #8** `fix/pre-m3-proxy-loop` — proxy.ts redirect loop guard for stale JWT
- [🔄 PR Open] **PR #9** `fix/pre-m3-landing-auth` — landing page, /signup role picker, branded auth layouts
- ⚠️ REQUIRED MANUAL STEP: Clerk dashboard → Configure → Sessions → Customize session token → add `{ "metadata": "{{user.public_metadata}}" }` → Save

---

## Pre-M1 — Completed refactors
- Completed pre-M2 refactor: app lifted to repo root (refactor/lift-to-root PR)

Expand Down
Loading