-- Users of this organization's instance. One database == one organization, so no
-- org_id. Passwords are stored only as argon2id PHC strings.
--
-- `updated_at` is maintained manually in UPDATE statements (as in the object table);
-- there is no auto-update trigger and no update path exists yet.
CREATE TABLE app_user (
    id            UUID PRIMARY KEY,
    email         TEXT NOT NULL CHECK (email <> ''),
    password_hash TEXT NOT NULL CHECK (password_hash <> ''),
    role          TEXT NOT NULL CHECK (role IN ('admin', 'editor')),
    created_at    TIMESTAMPTZ NOT NULL DEFAULT now(),
    updated_at    TIMESTAMPTZ NOT NULL DEFAULT now()
);

-- Case-insensitive uniqueness on email, enforced at the database. The application
-- stores normalized (lowercased) emails and looks up via `lower(email) = $1`, so this
-- functional unique index both backs those lookups and guarantees no case-variant
-- duplicate can exist even if a non-normalized value were ever written.
CREATE UNIQUE INDEX app_user_email_lower_key ON app_user (lower(email));
