-- Locally-issued player accounts. GUPI mints the JWT for now; external_id is -- reserved so a glitch.university key-exchange can later link/migrate an account -- without changing how playthroughs bind (they key off the JWT sub = users.id). CREATE TABLE osint.users ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), handle TEXT NOT NULL UNIQUE CHECK (handle ~ '^[a-z0-9_.-]{3,32}$'), password_hash TEXT NOT NULL, display_name TEXT NOT NULL, avatar_url TEXT, external_id TEXT UNIQUE, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() );