-- +goose Up CREATE EXTENSION IF NOT EXISTS pgcrypto; CREATE EXTENSION IF NOT EXISTS citext; CREATE TABLE users ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), email CITEXT NOT NULL UNIQUE, display_name TEXT, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now() ); CREATE TABLE user_passwords ( user_id UUID PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE, password_hash BYTEA NOT NULL, password_salt BYTEA NOT NULL, algorithm TEXT NOT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now() ); CREATE TABLE user_oauth_accounts ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, provider TEXT NOT NULL, subject TEXT NOT NULL, email TEXT, email_verified BOOLEAN NOT NULL DEFAULT false, profile JSONB, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now() ); CREATE UNIQUE INDEX user_oauth_accounts_provider_subject_idx ON user_oauth_accounts (provider, subject); CREATE INDEX user_oauth_accounts_user_id_idx ON user_oauth_accounts (user_id); CREATE TABLE login_events ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), user_id UUID REFERENCES users(id), provider TEXT, success BOOLEAN NOT NULL, ip INET, user_agent TEXT, created_at TIMESTAMPTZ NOT NULL DEFAULT now() ); CREATE INDEX login_events_user_id_idx ON login_events (user_id); CREATE INDEX login_events_created_at_idx ON login_events (created_at); -- +goose Down DROP TABLE IF EXISTS login_events; DROP TABLE IF EXISTS user_oauth_accounts; DROP TABLE IF EXISTS user_passwords; DROP TABLE IF EXISTS users; DROP EXTENSION IF EXISTS citext; DROP EXTENSION IF EXISTS pgcrypto;