Standalone account management page at /my-account with profile settings, subscription management, and security options.

Sections

Section Features
Profile Avatar display (OAuth or Gravatar), validated server-side name/phone updates, email (read-only)
Subscription Current plan, status badge, renewal date, Stripe Customer Portal link
Newsletter Subscribe/unsubscribe toggle synced to the active email provider through authenticated CSRF-protected API calls
Privacy & Data Rights Data export entry point, cookie consent management, regional rights summary for GDPR / Swiss FADP / US state privacy / Canada PIPEDA + CASL, and links to the Privacy Policy and contact page
Security Login method display, password change (email users), 2FA option
Danger Zone Account deletion with 30-day grace period, cancel deletion option

Privacy & Data Rights

The My Account page exposes customer-facing privacy controls alongside profile and billing settings. Authenticated users can start a CSV data export, reopen Cookie settings, review the regional rights covered by the product, navigate to the Privacy Policy, and contact the operator for manual access, correction, objection, consent-withdrawal, or CASL/PIPEDA-style requests.

The public footer also links to /[locale]/privacy-choices, which mirrors the same rights in a public legal surface and explains do-not-sell/share and targeted-advertising opt-out behavior.

Account Deletion (GDPR)

GDPR Article 17 - Right to Erasure compliance:

  1. User requests deletion from Danger Zone
  2. Confirmation dialog with consequences explained (and B2B member-cascade warning when applicable)
  3. 30-day grace period before permanent deletion
  4. Cancel deletion option with warning banner shown
  5. process-account-deletions job handles permanent removal
  6. Processor cleanup covers Stripe, newsletter/email provider, Supabase Storage documents/avatars, database rows, and Supabase Auth
  7. Failures are redacted into processor_errors, increment retry_count, and mark the request failed instead of falsely completing it

B2B Member Cascade

When the owner of a workspace deletes their personal account in B2B mode, the workspace cannot continue to exist (members exist solely to access that workspace). The deletion job therefore cascades the workspace deletion through to every member's auth.users row, which in turn cascades through existing FKs to profiles → other memberships → their personal accounts.

The behavior is controlled by the cascade_members column on account_deletion_requests:

Triggercascade_membersEffect on member accounts
/my-account → owner deletes their personal account, B2B modetrue on workspace requests onlyCascade-deleted with the workspace
/my-account → owner deletes their personal account, B2C / hybridfalsePreserved
/api/org/schedule-deletion → owner deletes only the workspacefalsePreserved (members exist outside this org)

The job handler captures member user_ids before the membership delete (after the rows are gone there's no way to know who they were), deletes known Storage objects before their rows disappear, then issues supabaseAdmin.auth.admin.deleteUser() for each, skipping the requesting owner (their personal-account request handles their own auth row). Per-processor errors are redacted and stored on the request; a failed processor blocks completed and leaves the row retryable.

The confirmation dialog in /my-account surfaces an explicit warning "All member accounts in these organizations will also be permanently deleted" when the user is about to trigger this cascade.

Billing Display in My Account

The /my-account Subscription card shows the current plan badge and Stripe Customer Portal link for any active or trialing subscription on any account the user belongs to (personal or workspace). The cookie-preferred account wins when multiple accounts have a subscription, so B2B users land on the workspace plan they manage. The lookup goes through getFirstActiveSubscriptionForAccounts(accountIds) in core/billing/queries.ts — a single batched query, no N+1.

Data Export (GDPR Article 20)

GDPR Article 20 - Right to Data Portability compliance. Users can download a CSV export from the My Account page. The export includes profile information, account memberships, chat sessions/messages, AI usage logs, consent records, payments, personal subscriptions, purchased licenses, invitations, access logs, admin logs tied to the user, deletion requests, notification preferences, pending emails, document metadata, and API-key metadata without secret hashes. The export is scoped to the caller's own data and streams server-side with formula-injection protection.