# Гонки: последний администратор и регистр логина (изменение 021) Находка ревью № 11, серьёзность — низкая. Блокировка автоназначения адреса — в № 020. ## Context - `update_user` / `delete_user` проверяют «последний активный администратор» через `count()` без блокировки: два администратора, одновременно отключающие друг друга, могут оставить систему без администратора. - Логин уникален без учёта регистра только на уровне проверки в коде; в БД `users.username` уникален с учётом регистра — параллельное создание `Ivanov`/`ivanov` проходит. ## Решение 1. **Сериализация изменений администраторов:** в `update_user` и `delete_user`, если операция может лишить учётную запись прав администратора (`loses_admin` / удаление активного admin), до проверки выполнить `pg_advisory_xact_lock()`; проверка и изменение — в одной транзакции. Остальные изменения пользователей не блокируются. 2. **Уникальность логина в БД:** новая миграция — уникальный индекс `lower(username)`; перед созданием миграция проверяет дубли по регистру и останавливается с перечнем. Предварительная проверка в `create_user` остаётся (даёт понятный 409), `flush` ловит гонку. 3. Вход: поиск пользователя остаётся точным по регистру (логин = `sub` токена); при желании — отдельное решение, не в этом изменении. ## Файлы `app/api/v1/users.py`, `alembic/versions/_users_lower_username.py`, `app/models.py` (`Index`), `tests/test_users.py`. ## Тест Два активных администратора (временные), параллельно (потоки) каждый отключает другого → ровно одна операция успешна, вторая 409; активный администратор остаётся. ## Проверка `pytest -q`; миграция на стенде проходит (дублей нет).