Stabilize staff concurrency and premium emoji; enable verified Drone deployment
Some checks failed
continuous-integration/drone/push Build is failing
Some checks failed
continuous-integration/drone/push Build is failing
This commit is contained in:
67
docs/STABILIZATION_REPORT.md
Normal file
67
docs/STABILIZATION_REPORT.md
Normal file
@@ -0,0 +1,67 @@
|
||||
# Проверка и стабилизация бота призовых розыгрышей
|
||||
|
||||
Дата: 13 сентября 2026. Исходная ревизия: `733298b`, ветка `master`.
|
||||
Отчёт о проверках перед выпуском. Результат конкретного deployment проверяется по соответствующему pipeline в Drone и состоянию контейнера на сервере.
|
||||
|
||||
## Устройство проекта
|
||||
|
||||
| Область | Основные файлы | Назначение |
|
||||
| --- | --- | --- |
|
||||
| Запуск | `main.py`, `src/core/config.py`, `src/core/database.py` | aiogram polling, FSM, соединения с БД, фоновые задачи |
|
||||
| Пользовательские сценарии | `src/controllers/`, `src/components/`, `src/handlers/registration_handlers.py` | Меню, регистрация, просмотр розыгрышей и счетов |
|
||||
| Управление | `src/handlers/admin_panel.py`, `admin_account_handlers.py`, `cashier_handlers.py` | Администраторы, кассиры, участники, счета, результаты |
|
||||
| Данные и операции | `src/core/models.py`, `services.py`, `registration_services.py`, `src/handlers/account_services.py` | PostgreSQL, участие, проведение розыгрыша, подтверждение выигрыша |
|
||||
| Общение | `src/core/chat_services.py`, `broadcast_services.py`, `src/handlers/chat_handlers.py`, `p2p_chat.py` | Чат, личные сообщения, рассылки и модерация |
|
||||
| Развёртывание | `.drone.yml`, `Dockerfile`, `docker-compose.yml`, `scripts/deploy_release.sh` | CI, артефакт, резервная копия, миграции и запуск |
|
||||
|
||||
## Исправленные проблемы
|
||||
|
||||
| Приоритет | Проблема | Исправление |
|
||||
| --- | --- | --- |
|
||||
| Критический | В Git отслеживался `.env.prod`; пароль БД также находился в Compose | Локальный файл сохранён, его удаление из индекса подготовлено; Compose читает настройки окружения, образ и релиз собираются по разрешённому списку файлов. Старые секреты остаются в истории и требуют замены |
|
||||
| Высокий | Проверки администратора различались; отдельные callback/FSM шаги позволяли обойти проверку меню | Общий источник ролей и middleware проверяют выбранный обработчик; пользовательские callback выделены явно; права назначенного администратора учитываются в админке |
|
||||
| Высокий | Два администратора могли одновременно провести один розыгрыш, два кассира — подтвердить один приз | Транзакционная блокировка конкретного розыгрыша, уникальные ограничения, условное обновление неподтверждённого выигрыша |
|
||||
| Высокий | Повторное добавление участника/счёта и одновременное создание пользователя приводили к дублям или IntegrityError | Атомарная вставка/обновление пользователя, блокировки изменений участия, ограничения уникальности, восстановление сессии после ожидаемых конфликтов |
|
||||
| Высокий | Победителя по Telegram ID мог подтвердить другой пользователь | Проверяется владелец выигрыша; подтверждение до завершения розыгрыша запрещено |
|
||||
| Высокий | Повторный розыгрыш мог затронуть подтверждённые призы и конфликтовать с подтверждением кассира | Общий сервис повторного розыгрыша блокирует результаты, заменяет только подходящие неподтверждённые места и сохраняет остальные призы |
|
||||
| Высокий | Глобальная проверка повторов сообщений путала одинаковые номера из разных чатов; модерация искала сообщение без чата | Ключ `(chat_id, message_id)`; поиск оригиналов и пересланных копий учитывает чат получателя и отклоняет неоднозначный результат |
|
||||
| Высокий | Синхронный Excel и удержание соединений БД во время массовых отправок мешали другим операциям | Работа с Excel вынесена в поток; данные подготавливаются до отправки; основные рассылки освобождают соединение БД, имеют общий лимит параллельных запросов и темпа |
|
||||
| Высокий | Первоначальная цепочка Alembic имела две вершины и повторно создавала существовавшие таблицы; рабочая ревизия отсутствовала в Git | Включена фактическая ревизия `20260701_perf_indexes` с сервера и объединяющая миграция; дублирующая историческая ревизия оставлена как пустой переход. Проверяется полная цепочка и обновление с рабочей ревизии |
|
||||
| Средний | Возврат через кнопку использовал автора сообщения — самого бота | Для действий пользователя передаётся `callback.from_user`; выход очищает его FSM |
|
||||
| Средний | Excel мог содержать формулы, чрезмерно большой архив или строку, срывающую весь импорт | Экспорт строк как текста; ограничения размера/числа строк; безопасный XML; отдельная транзакция для каждой строки; импорт не назначает административные роли |
|
||||
| Средний | HTML в имени/тексте ломал пересылку, длинный текст переставал помещаться с заголовком | Экранирование и сохранение Telegram entities; для предельного размера заголовок отправляется отдельно |
|
||||
| Средний | Разные интерфейсы бана/разбана расходились; повторная запись о блокировке ломала рассылку и задачу неактивности | Оба механизма блокировки согласованы; служебные записи обновляются атомарно |
|
||||
| Средний | Ошибки SQL/исключений уходили пользователю; были обращения к удалённому `User.account_number` и несуществующим методам | Общие сообщения об ошибке без технических деталей, исправленные обращения к Account и сервисам, критическая статическая проверка в CI |
|
||||
| Средний | CI скрывал ошибки, а наличие процесса считалось успешным деплоем | Проверки останавливают pipeline при ошибке; проверяются миграции, схема, доступ к БД, запуск Telegram и heartbeat приложения |
|
||||
| Средний | Установленные зависимости содержали известные уязвимости; старый aioredis несовместим с Python 3.12 | Обновлены aiogram/aiohttp/python-dotenv, удалён неиспользуемый aioredis; выполнен pip-audit |
|
||||
|
||||
## Одновременная работа сотрудников
|
||||
|
||||
Состояние диалога разделено по боту, чату и пользователю. В Compose используется Redis с сохранением данных; локальный запуск без `REDIS_URL` использует память. Блокировка FSM упорядочивает события одного пользователя, не закрывая доступ другим пользователям. Изменения одного розыгрыша сериализуются на уровне PostgreSQL; разные розыгрыши могут обрабатываться одновременно.
|
||||
|
||||
`ADMIN_IDS` задаёт главных администраторов. Назначенные в БД администраторы используют админку. `CASHIER_IDS` либо `User.is_cashier` дают доступ к кассе: счета, добавление участников по счетам и подтверждение выигрышей. Создание/проведение розыгрышей и управление сотрудниками остаются административными операциями.
|
||||
|
||||
Главный администратор может выполнить `/add_cashier TELEGRAM_ID`, `/remove_cashier TELEGRAM_ID`, `/cashiers`. Сначала сотрудник должен открыть бота через `/start`. Кассир открывает `/cashier`; `/cancel` отменяет текущий ввод. Для кассира из `CASHIER_IDS` отзыв выполняется через настройку окружения.
|
||||
|
||||
Поддерживается один процесс Telegram polling с несколькими одновременно работающими сотрудниками. Запуск нескольких polling-контейнеров с одним токеном не является способом масштабирования этой конфигурации.
|
||||
|
||||
## Проверки
|
||||
|
||||
Добавлены проверки конкурентного создания пользователей и участия, нескольких победных счетов одного пользователя, повторного проведения/подтверждения/перерозыгрыша, прав и их отзыва, настоящих маршрутов aiogram с подменённым Telegram API, независимости диалогов, импорта/экспорта, пересылок и модерации.
|
||||
|
||||
CI запускает тесты на SQLite и отдельной PostgreSQL 16, соответствующей рабочему серверу. Проверка Alembic создаёт дополнительную временную БД, выполняет полную миграцию и обновление с рабочей ревизии, повторяет upgrade head и проверяет наличие ожидаемых таблиц/полей. SQLite используется для тестов сервисов через SQLAlchemy metadata; историческая цепочка миграций предназначена для PostgreSQL.
|
||||
|
||||
Итоговый локальный прогон с поддержкой премиум-эмодзи: **62 passed на PostgreSQL 15**; **60 passed, 2 skipped на SQLite** (пропущены PostgreSQL-тесты миграций). Оба прогона выдают по шесть предупреждений openpyxl об устаревающем `datetime.utcnow`; падений тестов нет. Поддержка эмодзи описана в [EMOJI_SYSTEM.md](EMOJI_SYSTEM.md).
|
||||
|
||||
Дополнительно прошли compileall, Ruff для критических ошибок, проверка состава релизного архива, поиск секретов в отслеживаемых файлах и синтаксическая проверка shell-скрипта. `pip-audit -r requirements.txt` сообщил `No known vulnerabilities found`. Это результат проверки известных уязвимостей зависимостей на дату аудита, а не гарантия безопасности всего приложения.
|
||||
|
||||
## Что ещё нельзя считать проверенным
|
||||
|
||||
1. **Drone и сервер.** Проверены SSH-доступ, права Docker, активность репозитория `trevor/new_lottery_bot` в `https://drone.smartsoltech.kr`. Настроены пять deployment-секретов. Успех удалённого deployment подтверждается отдельно после push; локальный зелёный прогон его не заменяет.
|
||||
2. **Рабочая инфраструктура.** Docker-образ собран на целевом хосте. Эффективные настройки и volumes сопоставлены с действующим контейнером; PostgreSQL 16.15 на `192.168.20.2` доступен. Реальная проверка восстановления выявила несовместимость клиента pg_dump 17 с версией рабочей БД 16; образ закрепляет клиент 16 из официального PostgreSQL APT-репозитория. После исправления production backup успешно восстановлен в изолированном PostgreSQL 16, применена новая миграция и проверена схема; рабочая БД этой проверкой не изменялась. Автоматический откат приложения при искусственном сбое пока не проверялся.
|
||||
3. **История секретов.** Удаление файла из будущего коммита не отзывает ранее записанные токен бота и пароль БД. Их нужно сменить и передать новые значения в Drone. История Git не переписывалась.
|
||||
4. **Подтверждение клубной карты.** Текущая бизнес-логика принимает введённый пользователем номер карты без проверки по внешней системе или отдельного подтверждения кассиром. Она не доказывает, что карта принадлежит заявителю. Для устранения этого риска требуется определить источник проверки владельца; автоматического подтверждения такой принадлежности сейчас нет.
|
||||
5. **Нагрузка и внешние сбои.** Тесты используют подменённые ответы Telegram и отдельные тестовые БД. Длительная нагрузка с реальными пользователями и потеря сети/Redis ещё не проверены. Рассылки не имеют долговременной очереди восстановления после рестарта; незавершённую рассылку может потребоваться повторить.
|
||||
6. **Производственные данные.** Проверка перед выпуском не обнаружила дубликатов участников или призовых мест. Новая миграция повторяет эту проверку и останавливается при неоднозначных данных; она не удаляет их автоматически.
|
||||
|
||||
Инструкция по секретам и первому запуску: [DRONE_DEPLOYMENT.md](DRONE_DEPLOYMENT.md). Проверка выявленных дефектов не является гарантией отсутствия всех возможных ошибок.
|
||||
Reference in New Issue
Block a user