Member Settings Page
Context
Members have no way to edit their profile, change their password, manage email, or control privacy. The guild activity feed is blocked behind privacy controls — we need members to opt in before showing their activity publicly. This page unblocks both the live activity feed and basic account management.
Scope
PR 1: Profile, privacy, password, email
- Profile fields — edit name, nickname, phone, birthday
- Privacy controls — toggle guild activity visibility (unblocks live feed)
- Password change — change password while logged in
- Email change — change email with re-verification
PR 2: Discord OAuth management (separate)
- Discord link/unlink — connect or disconnect Discord from the settings page
Navigation
Add “Settings” link to the NavUser dropdown in the sidebar footer (alongside theme toggle + logout). Keeps the 5-page RPG nav structure clean.
Data model changes
Members collection — add privacy fields
privacy group:
showInGuildActivity: boolean (default false — opt-in)
No new fields needed for profile — name, nickname, phone, birthday already exist.
Route structure
src/app/(frontend)/dashboard/settings/
page.tsx — server component, fetches member data
profile-form.tsx — client component: name, nickname, phone, birthday
privacy-form.tsx — client component: guild activity toggle
password-form.tsx — client component: current + new password
email-form.tsx — client component: new email + password confirmation
discord-section.tsx — client component: link/unlink Discord (PR 2)
API routes
POST /api/member/profile — update profile fields
- Auth: Better Auth session → find member by
betterAuthUserId - Validates + updates: name, nickname, phone, birthday
- Uses
payload.update()withoverrideAccess: true(members can’t update their own records via Payload access control, so the API route handles auth and delegates)
POST /api/member/privacy — update privacy settings
- Same auth pattern
- Updates:
privacy.showInGuildActivity
Password change — Better Auth client
No custom API route needed. Better Auth’s authClient.changePassword() handles this client-side.
Email change — Better Auth client
authClient.changeEmail() if available, otherwise custom flow: verify current password → update BA user email → send verification → update Payload member email on verification callback.
Discord link/unlink — Better Auth client (PR 2)
authClient.linkSocial({ provider: 'discord' }) to link, custom endpoint to unlink.
Page layout
Settings
├── Profile (Card)
│ ├── Name, Nickname, Phone, Birthday inputs
│ └── Save button
├── Privacy (Card)
│ └── "Show my activity in Guild Hall" toggle + description
├── Email (Card)
│ ├── Current email (display)
│ ├── New email input + password confirmation
│ └── Update button
├── Password (Card)
│ ├── Current password, New password, Confirm password
│ └── Update button
└── Connected Accounts (Card) — PR 2
├── Discord: Connected as @username [Unlink] / Not connected [Link]
└── (future: other OAuth providers)
Key decisions
- Privacy is opt-in (default false) — members must explicitly choose to show activity in the guild feed. Respects privacy by default.
- Profile updates go through API routes not server actions — matches existing form patterns (signup, login all use API routes).
- Members can’t update Payload records directly — access control is staff+. API routes authenticate via Better Auth session, then use
overrideAccess: true. - Better Auth handles password/email/OAuth — we don’t reinvent auth flows.
Related
- guild-portal-ui-mockups — 5-page portal structure (settings is a utility page, not part of the RPG nav)
- guild-portal-ui-implementation — implementation status
- Privacy decision documented in memory:
project_guild_activity_privacy.md