Skip to content

#240 Require Full Name During Sign-Up#248

Open
b-at-neu wants to merge 5 commits into
devfrom
240-require-full-name-during-sign-up
Open

#240 Require Full Name During Sign-Up#248
b-at-neu wants to merge 5 commits into
devfrom
240-require-full-name-during-sign-up

Conversation

@b-at-neu

Copy link
Copy Markdown
Collaborator

Closes #240

Summary

  • Gate every authenticated route on user.name being set — all roles (applicant, manager, admin) must provide a name before accessing the app
  • Render a "What's your name?" card at the top of /profile for users without a name; card disappears after submit
  • Sync the name to both the Prisma User row (server action, the gate-clearing source of truth) and the Neon Auth account (client-side authClient.updateUser)

Changes

  • lib/constants.ts — add NAME_MAX_LENGTH = 100, shared between the server action and client form schema
  • prisma/actions/profile.ts — add setUserName(input: unknown) server action: auth via getCurrentUser(), zod-validated, scoped write to caller's user.id, revalidates /profile and layout
  • components/features/name-field.tsx — new 'use client' component: react-hook-form + zod, calls setUserName then authClient.updateUser({ name }), toasts on success/error, router.refresh() to clear the gate
  • app/(main)/(auth)/layout.tsx — universal name gate: if (!user.name?.trim()) redirect('/profile') before any role-specific logic
  • app/(main)/profile/page.tsx — conditionally render <NameField /> above <ProfileForm /> when !user.name?.trim()
  • app/(main)/profile/loading.tsx — add name-card skeleton at the top to avoid layout shift

Testing plan

  • As a brand-new email (never signed up), complete OTP sign-in — land on /profile with the Name card shown
  • Visiting any other authenticated route (e.g. /) before setting a name redirects to /profile
  • Submit a blank/whitespace-only name — inline field error "Enter your full name." appears; no write to DB
  • Submit a valid name — success toast "Name saved", gate clears, sidebar shows the name
  • Reload /profile after setting a name — Name card is no longer shown
  • Confirm the Neon Auth account name updated (check the session/account name)
  • As an existing user who already has a name — /profile shows no Name card; no redirect loop
  • As an admin with no name — still gated to /profile until name is set
  • As a manager with no name — still gated to /profile until name is set
  • Dev bypass user without a name — gated consistently; setting name clears the gate

Automated checks

  • TypeScript: npm run tsc:check — clean
  • ESLint: npm run eslint:check — clean
  • Prettier: npm run prettier:check — clean

Notes

  • No Prisma schema change needed — User.name String? already exists
  • The app User.name write (server action) is the gate-clearing source of truth; authClient.updateUser syncs the Neon Auth account but a failure there only generates a non-blocking warning toast — the gate still clears
  • The name check (!user.name?.trim()) is identical in both the layout gate and the profile page conditional to prevent any loop scenario

@b-at-neu b-at-neu self-assigned this Jun 26, 2026
@vercel

vercel Bot commented Jun 26, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
aplio Ready Ready Preview, Comment Jun 29, 2026 9:52am

@b-at-neu b-at-neu added the ready for review PR ready for review agent label Jun 26, 2026
@b-at-neu b-at-neu added reviewing Review agent working (in-flight) and removed ready for review PR ready for review agent labels Jun 27, 2026

@b-at-neu b-at-neu left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review — Cycle 1 · needs revision

2 open — 1 🟠 Medium, 1 ⚪ Nit (see inline)

Comment thread app/(main)/profile/loading.tsx Outdated
Comment thread prisma/actions/profile.ts Outdated
@b-at-neu b-at-neu added needs revision Review found issues that need fixing revising Revise agent working (in-flight) and removed reviewing Review agent working (in-flight) needs revision Review found issues that need fixing labels Jun 27, 2026
@b-at-neu

Copy link
Copy Markdown
Collaborator Author

Revision — Cycle 1

fixed R1-M1, R1-N1 · 67df4b7

@b-at-neu b-at-neu added ready for review PR ready for review agent and removed revising Revise agent working (in-flight) labels Jun 27, 2026
@b-at-neu b-at-neu added reviewing Review agent working (in-flight) and removed ready for review PR ready for review agent labels Jun 27, 2026

@b-at-neu b-at-neu left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review — Cycle 2 · approved

1 open — 1 ⚪ Nit (see inline)

Comment thread prisma/actions/profile.ts
@b-at-neu b-at-neu added approved Review passed, ready to merge and removed reviewing Review agent working (in-flight) labels Jun 27, 2026
@b-at-neu

Copy link
Copy Markdown
Collaborator Author

Revision needed — move name collection to the login page

The name gate should happen on the login page itself, not as a redirect to /profile. Here is the new design:

New approach

app/login/page.tsx becomes the gating point for name collection. It already runs server-side and has access to the session. Add three-state logic:

  1. No session → render AuthView as today.
  2. Session + user.name is blank → render a name collection form (instead of AuthView, or below it). The user can't proceed until they enter their name.
  3. Session + user.name existsredirect('/').

This way, right after OTP confirmation, the user's next page load hits /login (or any redirect back to it) and sees the name form before entering the app.

Middleware change

middleware.ts currently redirects authenticated users away from /login to /. That bypass must be removed so authenticated-but-nameless users can visit /login. The page's own server-side redirect (session + name → redirect('/')) takes over that responsibility for signed-in users with a name.

Remove from the existing PR

  • Remove the if (!user.name?.trim()) redirect('/profile') gate from app/(main)/(auth)/layout.tsx.
  • Remove <NameField /> from app/(main)/profile/page.tsx.
  • Remove the name-card skeleton block from app/(main)/profile/loading.tsx.

Keep from the existing PR

  • setUserName server action in prisma/actions/profile.ts (same logic, just called from the login page now instead of /profile).
  • NAME_MAX_LENGTH constant in lib/constants.ts.
  • NameField client component — move it to components/features/name-field.tsx if not already there, and update it to router.replace('/') on success instead of router.refresh().

UX

  • The name form on the login page should match the login card's existing look (use the same Card/CardContent layout). Heading: "What's your name?". Single required text input. Submit button: "Continue".
  • Existing users (session + name) are redirected immediately — they never see the form.

@b-at-neu b-at-neu added needs revision Review found issues that need fixing revising Revise agent working (in-flight) and removed approved Review passed, ready to merge needs revision Review found issues that need fixing labels Jun 27, 2026
@b-at-neu b-at-neu force-pushed the 240-require-full-name-during-sign-up branch from 67df4b7 to d69fb47 Compare June 27, 2026 09:43
@b-at-neu

Copy link
Copy Markdown
Collaborator Author

Revision — Cycle 2

skipped R2-N1 (no change needed — profile.ts already uses zod/v4, which is the majority convention in prisma/actions/; applications.ts is the outlier) · d69fb47

follow-up: migrate applications.ts to import { z } from 'zod/v4' for consistency with the rest of the actions directory

@b-at-neu b-at-neu added ready for review PR ready for review agent and removed revising Revise agent working (in-flight) labels Jun 27, 2026

@b-at-neu b-at-neu left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review — Cycle 4 · needs revision

2 open — 1 🔴 Critical, 1 🟠 Medium (see inline)

Comment thread app/login/page.tsx Outdated
Comment thread components/features/name-field.tsx Outdated
@b-at-neu b-at-neu added needs revision Review found issues that need fixing revising Revise agent working (in-flight) and removed reviewing Review agent working (in-flight) needs revision Review found issues that need fixing labels Jun 27, 2026
@b-at-neu b-at-neu force-pushed the 240-require-full-name-during-sign-up branch from bb69594 to 8e7ef0a Compare June 27, 2026 10:03
@b-at-neu

Copy link
Copy Markdown
Collaborator Author

Revision — Cycle 4

fixed R4-C1, R4-C2 · 8e7ef0a · rebase: app/login/page.tsx (took PR's conditional structure, incorporated dev's updated SIGN_IN_DESCRIPTION text)

@b-at-neu b-at-neu added ready for review PR ready for review agent and removed revising Revise agent working (in-flight) labels Jun 27, 2026
@b-at-neu b-at-neu added reviewing Review agent working (in-flight) and removed ready for review PR ready for review agent labels Jun 27, 2026

@b-at-neu b-at-neu left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review — Cycle 4 · needs revision

2 open — 1 🔴 Critical, 1 🟠 Medium (see inline)

Comment thread app/login/page.tsx
}
/>
{user ? (
<NameField defaultName={user.name ?? ''} redirectTo={safeTo} />

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

R4-C1 🔴 Critical — The name gate is broken end-to-end. NameField only appears here when an already-authenticated nameless user explicitly visits /login again. But a brand-new user completing OTP via AuthView is redirected by the Neon SDK directly to redirectTo={safeTo} — they never land back on /login to see this form. The auth layout (app/(main)/(auth)/layout.tsx) no longer checks user.name (removed in a prior cycle), so that authenticated-nameless user arrives at their destination route with no gate. The acceptance criterion "Visiting any other authenticated route before setting a name redirects to /profile" is not met.

Fix: the login-page name form is the right home for name collection, but it cannot be the only enforcement point. The auth layout gate must be restored: add if (!user.name?.trim()) redirect('/login'); as the first check after getCurrentUser() in app/(main)/(auth)/layout.tsx, before the admin/manager early-returns. This catches every route under (auth) including post-OTP landings and direct navigation. The layout redirect sends nameless users to /login where this form then handles them — completing the loop correctly.

'Name saved, but account sync failed. Reload if issues persist.',
);
else toast.success('Name saved');

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

R4-C2 🟠 Medium — router.replace('/') is hardcoded. When a user arrives at /login?redirectTo=/positions/xyz/apply, the login page computes safeTo = '/positions/xyz/apply' and passes it to AuthView. An authenticated-nameless user seeing NameField should be sent to that same safeTo after submitting — but this hardcodes / (which resolves to /positions via the root redirect). Fix: add a redirectTo: string prop to NameField and pass safeTo from the login page: <NameField defaultName={user.name ?? ''} redirectTo={safeTo} />. Use that prop in router.replace(redirectTo) so post-name navigation honors the original destination.

@b-at-neu b-at-neu left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review — Cycle 5 · approved

0 open — R4-C1 (Critical) and R4-C2 (Medium) both resolved; no regressions introduced

@b-at-neu b-at-neu added approved Review passed, ready to merge needs revision Review found issues that need fixing revising Revise agent working (in-flight) and removed reviewing Review agent working (in-flight) approved Review passed, ready to merge needs revision Review found issues that need fixing labels Jun 27, 2026
b-at-neu and others added 5 commits June 29, 2026 11:47
on /profile with a NameField client component, and sync to the Neon Auth
account after the server action writes the app User row.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
/login when a session has no name, redirect named users to the app,
remove the name gate from the auth layout and NameField from /profile.
Router.replace('/') on success so the user lands in the app directly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Restore name gate in auth layout so every authenticated-nameless user is
redirected to /login regardless of entry point. Add redirectTo prop to
NameField so post-name navigation honors the original destination.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@b-at-neu b-at-neu force-pushed the 240-require-full-name-during-sign-up branch from 8e7ef0a to a1bd619 Compare June 29, 2026 09:51
@b-at-neu b-at-neu added approved Review passed, ready to merge and removed revising Revise agent working (in-flight) labels Jun 29, 2026
@b-at-neu

Copy link
Copy Markdown
Collaborator Author

Revision — Cycle 4

rebase: app/login/page.tsx (accepted both sides — HEAD added metadata export + import, PR added NameField import + conditional rendering; applied HEAD's max-w-sm/w-full styling on top of PR's JSX structure) · a1bd619

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Review passed, ready to merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Require Full Name During Sign-Up

1 participant