-- Metadata auth management schema patch. -- Keycloak owns login credentials; TJWater stores only business identity and access. CREATE EXTENSION IF NOT EXISTS pgcrypto; DO $$ DECLARE users_id_type text; BEGIN SELECT data_type INTO users_id_type FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'users' AND column_name = 'id'; IF users_id_type IS NULL THEN CREATE TABLE users ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), keycloak_id UUID UNIQUE NOT NULL, username VARCHAR(50) UNIQUE NOT NULL, email VARCHAR(100) UNIQUE NOT NULL, role VARCHAR(20) DEFAULT 'user' NOT NULL, is_active BOOLEAN DEFAULT TRUE NOT NULL, is_superuser BOOLEAN DEFAULT FALSE NOT NULL, attributes JSONB, created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, last_login_at TIMESTAMP WITH TIME ZONE ); ELSIF users_id_type <> 'uuid' THEN RAISE EXCEPTION 'Existing public.users.id is %, not uuid. Export old local users, create Keycloak accounts, then migrate to metadata UUID users before applying this patch.', users_id_type; END IF; END $$; ALTER TABLE users ADD COLUMN IF NOT EXISTS keycloak_id UUID, ADD COLUMN IF NOT EXISTS attributes JSONB, ADD COLUMN IF NOT EXISTS last_login_at TIMESTAMP WITH TIME ZONE; ALTER TABLE users ALTER COLUMN role SET DEFAULT 'user'; ALTER TABLE users DROP CONSTRAINT IF EXISTS users_role_check; ALTER TABLE users ADD CONSTRAINT users_role_check CHECK (role IN ('admin', 'user')); CREATE UNIQUE INDEX IF NOT EXISTS idx_users_keycloak_id ON users(keycloak_id); CREATE INDEX IF NOT EXISTS idx_users_role ON users(role); CREATE INDEX IF NOT EXISTS idx_users_is_active ON users(is_active);