-- 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()
);
