-- v1.1.8 User Management — password reset tokens.
--
-- Identical shape to `app_user_email_verifications`. Same one-shot
-- semantics via atomic UPDATE WHERE consumed_at IS NULL. Default TTL
-- is shorter (1h vs 48h) — reset tokens are higher-risk than email
-- verification (whoever holds them can change the password).
--
-- `users::request_password_reset` deliberately returns no signal to
-- script-land about whether the email matched, so probing this table
-- via mass-replay isn't a clean enumeration vector. The application
-- enforces "no existence leak"; this migration is just storage.

CREATE TABLE app_user_password_resets (
    token_hash    TEXT PRIMARY KEY,
    app_id        UUID NOT NULL REFERENCES apps(id) ON DELETE CASCADE,
    user_id       UUID NOT NULL REFERENCES app_users(id) ON DELETE CASCADE,
    created_at    TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    expires_at    TIMESTAMPTZ NOT NULL,
    consumed_at   TIMESTAMPTZ
);

CREATE INDEX idx_app_user_password_resets_user
    ON app_user_password_resets (app_id, user_id);
