-- Phase 3a admin auth — see blueprint §11.4. -- -- Per-user platform-operator accounts (distinct from the v1.1+ `users` -- table, which is for script-end users). Every authenticated admin is a -- full admin in this cut; role/permission tables will be added later -- without touching this schema. -- -- `admin_sessions.token_hash` stores SHA-256 of the raw token; the raw -- value only ever exists in the login response, the HttpOnly cookie, and -- bearer-token requests. Cascade on user delete kills the user's sessions -- automatically — which is also why deactivating a user can simply wipe -- their rows instead of marking each session expired. CREATE TABLE admin_users ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), username TEXT NOT NULL UNIQUE, password_hash TEXT NOT NULL, is_active BOOLEAN NOT NULL DEFAULT TRUE, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), last_login_at TIMESTAMPTZ ); CREATE TABLE admin_sessions ( token_hash TEXT PRIMARY KEY, user_id UUID NOT NULL REFERENCES admin_users(id) ON DELETE CASCADE, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), expires_at TIMESTAMPTZ NOT NULL, last_used_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE INDEX admin_sessions_user_idx ON admin_sessions (user_id); CREATE INDEX admin_sessions_expiry_idx ON admin_sessions (expires_at);