-- SSO Database Initialization CREATE SCHEMA IF NOT EXISTS sso; -- Users table CREATE TABLE IF NOT EXISTS sso.users ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), email VARCHAR(255) NOT NULL UNIQUE, password_hash VARCHAR(255), username VARCHAR(100), avatar TEXT, bio TEXT, access_level VARCHAR(50) NOT NULL DEFAULT 'user' CHECK (access_level IN ('guest', 'user', 'employee', 'admin', 'investor')), profiles JSONB DEFAULT '[]'::jsonb, primary_profile VARCHAR(50), is_active BOOLEAN DEFAULT TRUE, status VARCHAR(50) NOT NULL DEFAULT 'active', email_verified BOOLEAN DEFAULT FALSE, email_verified_at TIMESTAMP WITH TIME ZONE, last_login_at TIMESTAMP WITH TIME ZONE, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); -- Sessions table CREATE TABLE IF NOT EXISTS sso.sessions ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), user_id UUID NOT NULL REFERENCES sso.users(id) ON DELETE CASCADE, token_hash VARCHAR(255) NOT NULL UNIQUE, device_info JSONB DEFAULT '{}', ip_address INET, user_agent TEXT, expires_at TIMESTAMP WITH TIME ZONE NOT NULL, revoked BOOLEAN DEFAULT FALSE, revoked_at TIMESTAMP WITH TIME ZONE, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); -- MFA table CREATE TABLE IF NOT EXISTS sso.mfa ( id SERIAL PRIMARY KEY, user_id UUID NOT NULL REFERENCES sso.users(id) ON DELETE CASCADE, type VARCHAR(50) NOT NULL, secret_encrypted TEXT, backup_codes_encrypted TEXT, verified BOOLEAN DEFAULT FALSE, verified_at TIMESTAMP WITH TIME ZONE, last_used_at TIMESTAMP WITH TIME ZONE, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), UNIQUE(user_id, type) ); -- OAuth providers CREATE TABLE IF NOT EXISTS sso.oauth_providers ( id SERIAL PRIMARY KEY, user_id UUID NOT NULL REFERENCES sso.users(id) ON DELETE CASCADE, provider VARCHAR(50) NOT NULL, provider_user_id VARCHAR(255) NOT NULL, access_token_encrypted TEXT, refresh_token_encrypted TEXT, expires_at TIMESTAMP WITH TIME ZONE, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), UNIQUE(provider, provider_user_id) ); -- Password reset tokens CREATE TABLE IF NOT EXISTS sso.password_resets ( id SERIAL PRIMARY KEY, user_id UUID NOT NULL REFERENCES sso.users(id) ON DELETE CASCADE, token_hash VARCHAR(255) NOT NULL UNIQUE, expires_at TIMESTAMP WITH TIME ZONE NOT NULL, used BOOLEAN DEFAULT FALSE, used_at TIMESTAMP WITH TIME ZONE, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); -- Indexes CREATE INDEX IF NOT EXISTS idx_users_email ON sso.users(email); CREATE INDEX IF NOT EXISTS idx_users_access_level ON sso.users(access_level); CREATE INDEX IF NOT EXISTS idx_users_profiles ON sso.users USING GIN (profiles); CREATE INDEX IF NOT EXISTS idx_users_primary_profile ON sso.users(primary_profile); CREATE INDEX IF NOT EXISTS idx_users_is_active ON sso.users(is_active); CREATE INDEX IF NOT EXISTS idx_users_status ON sso.users(status); CREATE INDEX IF NOT EXISTS idx_sessions_user ON sso.sessions(user_id); CREATE INDEX IF NOT EXISTS idx_sessions_expires ON sso.sessions(expires_at); CREATE INDEX IF NOT EXISTS idx_mfa_user ON sso.mfa(user_id); CREATE INDEX IF NOT EXISTS idx_oauth_user ON sso.oauth_providers(user_id); -- Permissions GRANT ALL PRIVILEGES ON SCHEMA sso TO lilith; GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA sso TO lilith; GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA sso TO lilith; DO $$ BEGIN RAISE NOTICE 'SSO database initialized'; END $$;