Display names now survive email-confirmation flows via user_metadata backfill
Davemaina1 fixes a Supabase signup race that silently drops display names for users who go through email confirmation. The pattern - write to user_metadata at signup, merge on the backend at login - is applicable to any product using Supabase auth with a separate profiles table.
Two failure modes cause the bug. First, when email confirmation is required, there's no active session immediately after supabase.auth.signUp(), so any post-signup write to user_profiles that depends on an access token can fail silently. Second, users who signed up before the name-write path existed have no display_name at all.
The fix touches three files.
In signup/page.tsx, full_name and first_name (extracted as trimmedName.split(/\s+/)[0]) are now passed in the options.data object to supabase.auth.signUp(). This stores them in Supabase user_metadata, which doesn't require a session - it's a property of the auth record itself and survives the confirmation gap.
In AuthContext.tsx, ensureProfile gains a userMeta parameter. Every time a session is established (both the initial auth listener and the subscription callback), session.user.user_metadata is passed through. The function extracts first_name, falling back to the first token of full_name, and includes it as display_name in the POST /user/profile request body.
On the backend (user.ts), the POST /user/profile handler checks for a display_name in the request body. If present and the current user_profiles.display_name is empty, it writes it. If the row already has a display name, no update happens. The guard is explicit: existing?.display_name?.trim() before the update query.
That idempotency matters. The handler is now called on every login. Without the guard it would overwrite later profile edits on each sign-in.
Spotted something wrong? Or know the PR text has fresher detail than the writeup above?