Kansho/backend/migrations/027_account_identifiers.sql
Lars 89d149684e
Some checks failed
Deploy Development / deploy (push) Successful in 58s
Test Suite / pytest-backend (push) Failing after 3m11s
Test Suite / smoke-dev (push) Successful in 0s
Test Suite / frontend-build (push) Successful in 16s
Add username login and expiring reset links so accounts stay recoverable.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-12 20:00:17 +02:00

50 lines
2.0 KiB
SQL

-- Account identifiers, verified addresses, and one-time mail tokens.
-- Existing primary addresses are grandfathered as verified once.
ALTER TABLE profiles ADD COLUMN IF NOT EXISTS username TEXT;
ALTER TABLE profiles ADD COLUMN IF NOT EXISTS secondary_email TEXT;
ALTER TABLE profiles ADD COLUMN IF NOT EXISTS email_verified_at TEXT;
ALTER TABLE profiles ADD COLUMN IF NOT EXISTS secondary_email_verified_at TEXT;
ALTER TABLE profiles ADD COLUMN IF NOT EXISTS pending_email TEXT;
ALTER TABLE profiles ADD COLUMN IF NOT EXISTS pending_secondary_email TEXT;
UPDATE profiles
SET email_verified_at = COALESCE(NULLIF(created, ''), CURRENT_TIMESTAMP::text)
WHERE email_verified_at IS NULL OR email_verified_at = '';
CREATE TABLE IF NOT EXISTS password_reset_tokens (
id TEXT PRIMARY KEY,
profile_id TEXT NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
token_hash TEXT NOT NULL UNIQUE,
expires_at TEXT NOT NULL,
used_at TEXT,
created TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP::text
);
CREATE TABLE IF NOT EXISTS email_verification_tokens (
id TEXT PRIMARY KEY,
profile_id TEXT NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
purpose TEXT NOT NULL CHECK (purpose IN ('primary', 'secondary')),
email TEXT NOT NULL,
token_hash TEXT NOT NULL UNIQUE,
expires_at TEXT NOT NULL,
used_at TEXT,
created TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP::text
);
CREATE UNIQUE INDEX IF NOT EXISTS profiles_username_lower_idx
ON profiles (lower(username))
WHERE username IS NOT NULL AND username <> '';
CREATE UNIQUE INDEX IF NOT EXISTS profiles_secondary_email_lower_idx
ON profiles (lower(secondary_email))
WHERE secondary_email IS NOT NULL AND secondary_email <> '';
CREATE UNIQUE INDEX IF NOT EXISTS profiles_pending_email_lower_idx
ON profiles (lower(pending_email))
WHERE pending_email IS NOT NULL AND pending_email <> '';
CREATE UNIQUE INDEX IF NOT EXISTS profiles_pending_secondary_email_lower_idx
ON profiles (lower(pending_secondary_email))
WHERE pending_secondary_email IS NOT NULL AND pending_secondary_email <> '';