Goal
Let signed-out visitors open and read any lesson page instead of being bounced to the landing page. Keep every interactive action gated behind auth, but in context: replace the action buttons with a sign-in call-to-action, and disable the sandbox shell with a sign-in CTA button in its place.
Current behavior
app/lessons/[slug]/page.tsx redirects anonymous users away: if (!session) redirect("/"). Lesson content is unreadable without an account.
- Interactive pieces on the lesson page:
<Run> button — components/lesson/RunBlock.tsx (dispatches SQL to the shell)
<Check> button — components/lesson/Check.tsx (POSTs to /api/lessons/[slug]/checks/[checkId])
- The Postgres shell/sandbox —
components/lesson/SandboxSection.tsx → SandboxPanel.tsx → components/shell/Terminal.tsx, provisioned per-user via ensureBranchForLesson.
- API routes already reject anonymous requests with
401 (checks, query, reset).
- Sign-in is GitHub OAuth via
app/sign-in-button.tsx (signIn.social({ provider: "github", callbackURL: "/dashboard" })).
Proposed change
- Drop the redirect in
app/lessons/[slug]/page.tsx — render the lesson prose + prev/next nav for everyone, branching on session only for the interactive parts.
- Action buttons (Run / Check): when there is no session, render a "Sign in to run" CTA in place of the button. Thread an
isSignedIn flag through buildLessonComponents → RunBlock / CheckCard.
- Shell / sandbox: when there is no session, do not call
ensureBranchForLesson (no Xata branch for anonymous visitors). Render a disabled terminal placeholder with a prominent "Sign in to start the sandbox" button (reuse the GitHub SignInButton).
- Return to the lesson after sign-in: set the CTA
callbackURL to the current lesson path (/lessons/<slug>) instead of always /dashboard.
Acceptance
- Signed-out users can read any
/lessons/<slug> page (no redirect).
- Run and Check buttons are replaced by an inline sign-in CTA when signed out.
- The terminal area shows a disabled state with a sign-in button; no sandbox branch is created for anonymous visitors.
- After signing in via any of these CTAs, the user lands back on the same lesson.
- API routes keep their
401 guards (defense in depth) — no change needed there.
Goal
Let signed-out visitors open and read any lesson page instead of being bounced to the landing page. Keep every interactive action gated behind auth, but in context: replace the action buttons with a sign-in call-to-action, and disable the sandbox shell with a sign-in CTA button in its place.
Current behavior
app/lessons/[slug]/page.tsxredirects anonymous users away:if (!session) redirect("/"). Lesson content is unreadable without an account.<Run>button —components/lesson/RunBlock.tsx(dispatches SQL to the shell)<Check>button —components/lesson/Check.tsx(POSTs to/api/lessons/[slug]/checks/[checkId])components/lesson/SandboxSection.tsx→SandboxPanel.tsx→components/shell/Terminal.tsx, provisioned per-user viaensureBranchForLesson.401(checks,query,reset).app/sign-in-button.tsx(signIn.social({ provider: "github", callbackURL: "/dashboard" })).Proposed change
app/lessons/[slug]/page.tsx— render the lesson prose + prev/next nav for everyone, branching onsessiononly for the interactive parts.isSignedInflag throughbuildLessonComponents→RunBlock/CheckCard.ensureBranchForLesson(no Xata branch for anonymous visitors). Render a disabled terminal placeholder with a prominent "Sign in to start the sandbox" button (reuse the GitHubSignInButton).callbackURLto the current lesson path (/lessons/<slug>) instead of always/dashboard.Acceptance
/lessons/<slug>page (no redirect).401guards (defense in depth) — no change needed there.