-- +goose Up -- +goose StatementBegin -- Authentication columns for the users table (migrated from auth-service). -- The users table itself is created in 00001_init; this migration adds the -- columns the auth and admin code paths require. ALTER TABLE users ADD COLUMN IF NOT EXISTS name VARCHAR(255), ADD COLUMN IF NOT EXISTS password_hash VARCHAR(255), ADD COLUMN IF NOT EXISTS email_verified BOOLEAN NOT NULL DEFAULT FALSE, ADD COLUMN IF NOT EXISTS provider VARCHAR(50) NOT NULL DEFAULT 'email', ADD COLUMN IF NOT EXISTS provider_id VARCHAR(255), ADD COLUMN IF NOT EXISTS role VARCHAR(50) NOT NULL DEFAULT 'user', ADD COLUMN IF NOT EXISTS last_login_at TIMESTAMP WITH TIME ZONE; ALTER TABLE users ALTER COLUMN id SET DEFAULT gen_random_uuid(); CREATE UNIQUE INDEX IF NOT EXISTS idx_users_email_unique ON users(email); CREATE INDEX IF NOT EXISTS idx_users_provider ON users(provider, provider_id); CREATE INDEX IF NOT EXISTS idx_users_role ON users(role); -- Magic links for passwordless auth CREATE TABLE IF NOT EXISTS magic_links ( token VARCHAR(255) PRIMARY KEY, user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, email VARCHAR(255) NOT NULL, used BOOLEAN DEFAULT FALSE, expires_at TIMESTAMP WITH TIME ZONE NOT NULL, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); CREATE INDEX IF NOT EXISTS idx_magic_links_user_id ON magic_links(user_id); CREATE INDEX IF NOT EXISTS idx_magic_links_expires ON magic_links(expires_at) WHERE used = FALSE; -- Password reset tokens CREATE TABLE IF NOT EXISTS password_resets ( token VARCHAR(255) PRIMARY KEY, user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, expires_at TIMESTAMP WITH TIME ZONE NOT NULL, used BOOLEAN DEFAULT FALSE, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); CREATE INDEX IF NOT EXISTS idx_password_resets_user_id ON password_resets(user_id); -- OAuth state tokens CREATE TABLE IF NOT EXISTS oauth_states ( state VARCHAR(255) PRIMARY KEY, redirect_url VARCHAR(500), created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), expires_at TIMESTAMP WITH TIME ZONE NOT NULL ); -- Admin audit log CREATE TABLE IF NOT EXISTS admin_audit_log ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), admin_user_id UUID REFERENCES users(id) ON DELETE SET NULL, action VARCHAR(100) NOT NULL, resource_type VARCHAR(100), resource_id VARCHAR(255), details JSONB, ip_address VARCHAR(45), user_agent TEXT, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); CREATE INDEX IF NOT EXISTS idx_admin_audit_log_admin ON admin_audit_log(admin_user_id); CREATE INDEX IF NOT EXISTS idx_admin_audit_log_action ON admin_audit_log(action); CREATE INDEX IF NOT EXISTS idx_admin_audit_log_created ON admin_audit_log(created_at); -- Refresh tokens for JWT CREATE TABLE IF NOT EXISTS refresh_tokens ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, token_hash VARCHAR(255) NOT NULL UNIQUE, expires_at TIMESTAMP WITH TIME ZONE NOT NULL, revoked BOOLEAN DEFAULT FALSE, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); CREATE INDEX IF NOT EXISTS idx_refresh_tokens_user ON refresh_tokens(user_id); CREATE INDEX IF NOT EXISTS idx_refresh_tokens_hash ON refresh_tokens(token_hash); -- +goose StatementEnd -- +goose Down -- +goose StatementBegin DROP TABLE IF EXISTS refresh_tokens; DROP TABLE IF EXISTS admin_audit_log; DROP TABLE IF EXISTS oauth_states; DROP TABLE IF EXISTS password_resets; DROP TABLE IF EXISTS magic_links; DROP INDEX IF EXISTS idx_users_role; DROP INDEX IF EXISTS idx_users_provider; DROP INDEX IF EXISTS idx_users_email_unique; ALTER TABLE users DROP COLUMN IF EXISTS last_login_at, DROP COLUMN IF EXISTS role, DROP COLUMN IF EXISTS provider_id, DROP COLUMN IF EXISTS provider, DROP COLUMN IF EXISTS email_verified, DROP COLUMN IF EXISTS password_hash, DROP COLUMN IF EXISTS name; -- +goose StatementEnd