Skip to content

Ticket 4.0 extension: Extended Supabase, Auth flow and persistent Profile schema#16

Open
alextgu wants to merge 4 commits intoutmgdsc:mainfrom
alextgu:sprint4.0/auth-setup-profile
Open

Ticket 4.0 extension: Extended Supabase, Auth flow and persistent Profile schema#16
alextgu wants to merge 4 commits intoutmgdsc:mainfrom
alextgu:sprint4.0/auth-setup-profile

Conversation

@alextgu
Copy link
Collaborator

@alextgu alextgu commented Feb 25, 2026

Feature(Auth & Profile):

Implement Supabase Auth flow and persistent Profile schema


PR Summary

This PR adds working login (sign-in, sign-up, forgot password), a profile section where users can view and edit their name, and connects profile data to Supabase via a public.profiles table with RLS and versioned migrations. Future profile features and user-scoped data can be added by extending profiles or new tables linked by user_id.


Overview

  • What feature/problem does this PR address?

    • Login was not fully working; profile data was not persisted in a database.
    • Users need a place to sign in, sign up, reset their password, and manage their profile (e.g. name) with data stored in Supabase and tied to their auth identity.
  • What approach was taken?

    • Auth: Supabase Auth for sign-in, sign-up, forgot password (reset link), and session. All sign-up/sign-in fields are required; sign-up includes First name, Last name, Email, Password, Confirm password.
    • Profile: Profile page shows full name (from DB or auth metadata) with an edit icon; editing updates both Supabase Auth user metadata and the public.profiles table via getProfile / updateProfile (upsert). RLS limits access to the current user’s row; an insert policy allows creating a profile row on first save if missing.
    • Database: public.profiles table with id, email, first_name, last_name, display_name, canvas_api_key, created_at, updated_at. Trigger creates a profile row on sign-up; migrations add columns and policies over time (run in Supabase SQL Editor; see supabase/README.md).
  • Design decisions / trade-offs:

    • Single profiles table per user (no separate “user settings” table yet) to keep schema simple; new user-level settings can be added as columns or new tables with user_id.
    • Migrations are run manually in Supabase Dashboard (no CLI) for now; each new change is a new timestamped .sql file for clarity and safe updates.
    • Canvas API key column added on profiles for future use; key should be used server-side only when calling Canvas.

Checklist

  • Added a clear description
  • Included evidence of Unit Testing
  • Updated documentation (if needed) — supabase/README.md, SUMMARY.md (this file)

Additional Notes

  • Forgot password: Redirect URL must be allowlisted in Supabase (Authentication → URL Configuration → Redirect URLs), e.g. http://localhost:3000/profile/reset-password.
  • Test login: Optional; set NEXT_PUBLIC_TEST_USER_EMAIL and NEXT_PUBLIC_TEST_USER_PASSWORD in .env.local and create that user in Supabase with “Auto Confirm User” enabled.
  • Next steps: Add profile features (e.g. Canvas API key UI), new user-scoped tables with user_id + RLS, and backend/API routes that read profile data (e.g. canvas_api_key) from the DB.

Jira Ticket

Jira Ticket(s) - (Not added yet)

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 25, 2026

Greptile Summary

Implements complete authentication system with Supabase Auth (sign-up, sign-in, password reset) and persistent user profiles. Creates public.profiles table with RLS policies, database triggers for auto-profile creation, and UI for viewing/editing user information.

Key Changes:

  • Auth helpers in lib/auth.ts handle sign-up with first/last name, sign-in, password reset, and metadata updates
  • Profile management in lib/profile.ts with RLS-protected CRUD operations for user data
  • Complete profile UI with auth forms, editable name field, and password reset flow across 3 pages
  • Database migrations create profiles table with columns for name, email, and Canvas API key (future use)
  • RLS policies ensure users can only access their own profile data
  • Trigger automatically creates profile row on user sign-up with metadata sync
  • Added header navigation and dismissible auth prompt banner

Notes:

  • Test login feature exposes credentials in client bundle (previously flagged)
  • Canvas API keys stored in plaintext (encryption recommended before production use)
  • Client-side timestamp used for profile updates instead of database-managed value

Confidence Score: 4/5

  • This PR is safe to merge with proper RLS policies and secure auth flow, but requires configuration steps
  • Well-implemented auth system with proper RLS security and comprehensive error handling. Score reduced from 5 due to: (1) manual migration steps required in Supabase Dashboard, (2) redirect URLs must be configured for password reset, (3) test credentials exposure in production builds (dev feature but bundle included), (4) Canvas API keys in plaintext pending encryption
  • Pay attention to supabase/README.md for required setup steps - migrations must be run manually in order, and password reset redirect URLs must be allowlisted in Supabase dashboard

Important Files Changed

Filename Overview
frontend/src/lib/auth.ts Added comprehensive auth flow with signup, signin, password reset, and name updates - well-structured with proper error handling
frontend/src/lib/profile.ts New profile management module with RLS-protected CRUD operations - uses client-side timestamp for updates
frontend/src/app/profile/page.tsx Complete profile UI with auth forms and editable name - comprehensive validation and state management
supabase/migrations/20250223000000_create_profiles.sql Initial profiles table with RLS policies, auto-creation trigger, and user backfill
supabase/migrations/20250226000000_profiles_first_last_name.sql Added first_name and last_name columns with trigger and backfill logic

Sequence Diagram

sequenceDiagram
    participant User
    participant ProfilePage
    participant AuthLib
    participant ProfileLib
    participant Supabase
    participant Database

    Note over User,Database: Sign Up Flow
    User->>ProfilePage: Enter first name, last name, email, password
    ProfilePage->>AuthLib: signUp(email, password, {firstName, lastName})
    AuthLib->>Supabase: auth.signUp with user_metadata
    Supabase->>Database: INSERT into auth.users
    Database->>Database: Trigger: handle_new_user()
    Database->>Database: INSERT into public.profiles
    Supabase-->>AuthLib: return user + session
    AuthLib-->>ProfilePage: Success
    ProfilePage-->>User: Show success message

    Note over User,Database: Sign In Flow
    User->>ProfilePage: Enter email, password
    ProfilePage->>AuthLib: signIn(email, password)
    AuthLib->>Supabase: auth.signInWithPassword
    Supabase-->>AuthLib: return session
    AuthLib-->>ProfilePage: Success
    ProfilePage->>ProfileLib: getProfile(user.id)
    ProfileLib->>Supabase: SELECT from profiles WHERE id = user.id
    Note right of Supabase: RLS policy: auth.uid() = id
    Supabase-->>ProfileLib: return profile data
    ProfileLib-->>ProfilePage: Display profile

    Note over User,Database: Update Name Flow
    User->>ProfilePage: Edit and save name
    ProfilePage->>AuthLib: updateUserName(firstName, lastName)
    AuthLib->>Supabase: auth.updateUser with metadata
    Supabase-->>AuthLib: Success
    ProfilePage->>ProfileLib: updateProfile(user.id, {first_name, last_name})
    ProfileLib->>Supabase: UPSERT into profiles
    Note right of Supabase: RLS policy: auth.uid() = id
    Supabase-->>ProfileLib: Success
    ProfilePage->>ProfileLib: getProfile(user.id)
    ProfileLib-->>ProfilePage: return updated profile
    ProfilePage-->>User: Show updated name

    Note over User,Database: Password Reset Flow
    User->>ProfilePage: Request password reset
    ProfilePage->>AuthLib: requestPasswordReset(email)
    AuthLib->>Supabase: auth.resetPasswordForEmail
    Supabase->>User: Email with reset link
    User->>ProfilePage: Click link, enter new password
    ProfilePage->>AuthLib: updatePassword(newPassword)
    AuthLib->>Supabase: auth.updateUser with new password
    Supabase-->>AuthLib: Success
    ProfilePage-->>User: Redirect to profile
Loading

Last reviewed commit: c523740

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

15 files reviewed, 5 comments

Edit Code Review Agent Settings | Greptile

return () => {
cancelled = true;
};
}, [user?.id]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dependency array uses user?.id but should use user to re-fetch when user changes, not just when ID changes (which never happens for same user object).

Suggested change
}, [user?.id]);
}, [user]);

Comment on lines +185 to +186
const testEmail = process.env.NEXT_PUBLIC_TEST_USER_EMAIL;
const testPassword = process.env.NEXT_PUBLIC_TEST_USER_PASSWORD;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test credentials will be embedded in the client bundle (visible in browser DevTools and production builds) because NEXT_PUBLIC_* vars are exposed to the browser. Remove this feature or move auth to a server API route.

first_name text,
last_name text,
display_name text,
canvas_api_key text,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Canvas API keys stored in plaintext - consider Supabase Vault encryption before production.

@alextgu
Copy link
Collaborator Author

alextgu commented Feb 27, 2026

@greptile

@alextgu
Copy link
Collaborator Author

alextgu commented Feb 27, 2026

@greptile

{
id: userId,
...updates,
updated_at: new Date().toISOString(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Client-side timestamp can drift from server time. Consider adding a database trigger to auto-update updated_at on row modifications, or omit this field and let Postgres handle it.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant