gantt-board/AUTH_SETTINGS_MIGRATION_NOTES_2026-02-21.md

92 lines
3.4 KiB
Markdown

# 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.