-- +goose Up -- +goose StatementBegin -- Users table for authentication (migrated from auth-service) CREATE TABLE IF NOT EXISTS users ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), email VARCHAR(255) NOT NULL UNIQUE, name VARCHAR(255), password_hash VARCHAR(255), email_verified BOOLEAN DEFAULT FALSE, provider VARCHAR(50) NOT NULL DEFAULT 'email', provider_id VARCHAR(255), role VARCHAR(50) NOT NULL DEFAULT 'user', created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), last_login_at TIMESTAMP WITH TIME ZONE ); CREATE INDEX IF NOT EXISTS idx_users_email 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 TABLE IF EXISTS users; -- +goose StatementEnd