feat(me): self-service email change, verified (P3e)

requestEmailChange -> supabase.auth.updateUser({email},{emailRedirectTo
/auth/confirm}); with Secure email change on (recommended) Supabase
double-confirms old+new. New /auth/confirm route verifyOtp(email_change)
then syncs the denormalized space_members.email to the authoritative
auth email ONLY post-verification (idempotent). proxy.ts whitelists
/auth/confirm (exact). Profile-tab UI shows current email + change
control. REQUIRES Supabase config (template -> /auth/confirm?token_hash=
{{ .TokenHash }}&type=email_change + redirect allowlist) — documented in
P3f. 521 tests; build clean (flow not exercisable without that config).
This commit is contained in:
Moheeb Zara
2026-05-18 15:53:39 -07:00
parent 2c847befeb
commit 5edd778cf6
6 changed files with 139 additions and 3 deletions
+2 -1
View File
@@ -26,7 +26,7 @@ export default async function MePage() {
const { data: member } = await supabase
.from('space_members')
.select(
'id, space_id, role, display_name, handle, phone, bio, skills, interests, willing_to, affiliations',
'id, space_id, role, email, display_name, handle, phone, bio, skills, interests, willing_to, affiliations',
)
.eq('user_id', user.id)
.in('status', ['current', 'unverified', 'late'])
@@ -34,6 +34,7 @@ export default async function MePage() {
if (!member) redirect('/signup')
const profile = {
email: (member.email as string | null) ?? '',
display_name: (member.display_name as string | null) ?? '',
handle: (member.handle as string | null) ?? '',
phone: (member.phone as string | null) ?? '',