-- 0054_user_profiles_username.sql -- ---------------------------------------------------------------------------- -- Optional username as a sign-in alternative to email. Stored alongside the -- canonical first/last name on user_profiles so the rest of the auth/profile -- code keeps a single place to look. The Better-Auth `user` table stays the -- source of truth for email + password; the username is a thin alias the -- login form looks up to resolve to the matching email before delegating -- to better-auth's email/password flow. -- -- Constraints (enforced application-side AND in SQL): -- - 2..30 characters -- - lowercase letters, digits, dot, underscore, hyphen -- - case-insensitive uniqueness per install (no per-port scoping - -- reps move between ports and a global username keeps URLs stable) -- -- The column is nullable; existing users keep email-only sign-in until they -- pick one. ALTER TABLE user_profiles ADD COLUMN IF NOT EXISTS username TEXT; -- Shape check at the DB level catches anything that slipped past the API -- (raw SQL inserts in tests, scripts, etc.). ALTER TABLE user_profiles ADD CONSTRAINT chk_user_profiles_username_shape CHECK (username IS NULL OR username ~ '^[a-z0-9._-]{2,30}$'); -- Case-insensitive uniqueness. Partial so multiple NULLs are allowed. CREATE UNIQUE INDEX IF NOT EXISTS idx_user_profiles_username_unique ON user_profiles (LOWER(username)) WHERE username IS NOT NULL;