ALTER TABLE `user`
    ADD COLUMN `password_set_at` DATETIME NULL DEFAULT NULL
        AFTER `password`;

-- Backfill: existing classic-registered users have a real password — we don't
-- know exactly when it was set, so we use joined_at as a best-effort value.
-- OAuth-registered users carry an "unusable" random bcrypt hash and must keep
-- password_set_at = NULL so the set-password endpoint treats them as
-- "no password yet". We exclude them by their placeholder username pattern
-- (`g_<hex>`) set by OAuthLoginService::generatePlaceholderUsername().
UPDATE `user`
SET `password_set_at` = `joined_at`
WHERE `password_set_at` IS NULL
  AND `username` NOT REGEXP '^g_[0-9a-f]+$';
