gantt-board/AUTH_SETTINGS_MIGRATION_NOTES_2026-02-21.md

3.4 KiB

Auth and Settings Migration Notes (Feb 21, 2026)

This document captures the auth/settings stabilization work completed during the SQLite -> Supabase migration cleanup.

Why this was needed

The app had overlapping auth models:

  • Supabase Auth tables (auth.users)
  • App tables (public.users, public.sessions, public.password_reset_tokens)

The app was still expecting public.users.password_hash, but that column was not present in the migrated schema, which caused:

  • login failures
  • reset password failures (Could not find the 'password_hash' column...)
  • settings profile/session issues

Environment key mapping that must be correct

Use different values for these:

  • NEXT_PUBLIC_SUPABASE_ANON_KEY -> anon/publishable key
  • SUPABASE_SERVICE_ROLE_KEY -> service_role/secret key

If these are the same value, auth/session/profile flows break.

Database work completed (Phase 1)

Phase 1 schema alignment was completed in Supabase:

  • created public.profiles with id referencing auth.users(id)
  • enabled RLS policies for own profile access
  • backfilled profile rows from existing data
  • optional trigger created to auto-create profile rows for new auth users

public.users was retained for compatibility during transition.

Code changes made

1) src/lib/server/auth.ts

  • registerUser now creates credentials in Supabase Auth (auth.users) via admin API.
  • authenticateUser now verifies credentials using signInWithPassword instead of public.users.password_hash.
  • updateUserAccount now updates password/email in Supabase Auth admin API.
  • Profile fields are mirrored to:
    • public.users
    • public.profiles
  • Existing custom gantt_session flow remains in place for compatibility.

2) src/app/api/auth/reset-password/route.ts

  • Removed dependency on public.users.password_hash.
  • Password reset now updates Supabase Auth user password through admin API.
  • Added fallback for legacy records: if auth user is missing, create it with the same UUID, then set password.

3) src/app/settings/page.tsx

  • Hardened response parsing for session/profile/password requests to avoid client runtime errors on malformed responses.
  • Fixed avatar preset rendering key collisions:
    • deduped generated preset URLs
    • switched to stable numeric keys (not data URL strings)

Current state (important)

Auth is currently hybrid but stable:

  • credentials/passwords: Supabase Auth (auth.users)
  • app profile fields: public.profiles (and mirrored public.users)
  • app session guard cookie: custom gantt_session is still used by this codebase

This is intentional as an intermediate compatibility stage.

Known behavior

Forgot password route currently generates reset links for dev/testing flow and does not send production email by itself unless an email provider flow is added.

Validation checklist used

  • login works after env fix
  • reset password no longer fails on missing password_hash
  • settings screen loads name/email/avatar
  • avatar save no longer returns auth/session-related errors
  • duplicate React key warning in avatar presets resolved

To fully finish migration and remove duplication:

  1. Move API auth/session checks to Supabase JWT/session directly.
  2. Remove custom session table/cookie flow (public.sessions, gantt_session) after cutover.
  3. Keep public.profiles as the only app profile table and retire compatibility mirrors.