# 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 ## Next cleanup (recommended) 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.