# 🤖 AnonBot - Telegram бот для анонимных вопросов Telegram-бот для приема и обработки анонимных вопросов с использованием aiogram 3.x. ## ✨ Возможности - 🔗 **Персональные ссылки** - каждый пользователь получает уникальную ссылку для приема вопросов - 👤 **Анонимность** - вопросы отправляются анонимно, личность отправителя скрыта - 💬 **Интерактивные ответы** - удобный интерфейс для ответов на вопросы через inline кнопки - 🔢 **Локальная нумерация** - каждый пользователь видит свои вопросы с номерами #1, #2, #3... вместо глобальных ID - 📊 **Статистика** - подробная статистика для администраторов - 🗄️ **База данных** - SQLite для хранения пользователей и вопросов с автоматической нумерацией - 👑 **Админ панель** - управление ботом для администраторов - 🔍 **Суперпользователи** - расширенные права для модерации с отображением информации об авторах вопросов - 🏗️ **Современная архитектура** - система инъекции зависимостей для лучшей тестируемости - 📝 **Продвинутое логирование** - автоматические декораторы, контекстное логирование, FSM отслеживание - 🛡️ **Безопасность** - валидация данных, обработка ошибок, система ролей - 🔍 **Централизованная валидация** - автоматическая валидация всех входных данных с санитизацией - 🔐 **Система разрешений** - гибкая система разрешений с соблюдением принципа OCP - 📈 **Prometheus метрики** - полный мониторинг производительности и состояния бота ## 🚀 Быстрый старт ### 1. Установка зависимостей ```bash pip install -r requirements.txt pip install dependency-injector # Для системы инъекции зависимостей ``` ### 2. Настройка конфигурации Создайте файл `.env` в корневой директории проекта: ```env # Токен бота от @BotFather BOT_TOKEN=your_bot_token_here # ID администраторов через запятую (можно получить у @userinfobot) ADMINS=123456789,987654321 # Путь к базе данных SQLite DATABASE_PATH=database/anon_qna.db # Режим отладки (true/false) DEBUG=false # Максимальная длина вопроса MAX_QUESTION_LENGTH=1000 # Максимальная длина ответа MAX_ANSWER_LENGTH=2000 ``` ### 3. Запуск бота #### Локальный запуск ```bash python main.py ``` или ```bash python bot.py ``` #### Запуск в Docker 1. Соберите Docker образ: ```bash docker build -t anon-bot . ``` 2. Запустите контейнер: ```bash docker run -d \ --name anon-bot \ --restart unless-stopped \ -p 8081:8081 \ -v $(pwd)/database:/app/database \ -v $(pwd)/logs:/app/logs \ -e BOT_TOKEN=your_bot_token_here \ -e ADMINS=123456789,987654321 \ -e DEBUG=false \ anon-bot ``` 3. Проверьте статус: ```bash docker logs anon-bot ``` 4. Проверьте метрики: ```bash curl http://localhost:8081/health ``` ## 📄 PID файл и мониторинг процесса AnonBot автоматически создает PID файл для отслеживания процесса и предоставляет детальную информацию о состоянии через HTTP эндпоинты. ### PID файл - **Расположение**: `/tmp/anon_bot.pid` - **Содержимое**: PID процесса бота - **Автоматическое управление**: создается при запуске, удаляется при остановке - **Проверка дублирования**: предотвращает запуск нескольких экземпляров ### Эндпоинт /status Предоставляет детальную информацию о процессе: ```bash curl http://localhost:8081/status ``` **Пример ответа:** ```json { "status": "running", "pid": 12345, "uptime": "2ч 15м", "memory_usage_mb": 45.2, "cpu_percent": 0.1, "timestamp": 1705312200.5 } ``` **Поля ответа:** - `status` - статус процесса (running/stopped/not_found/error) - `pid` - идентификатор процесса - `uptime` - время работы в человекочитаемом формате - `memory_usage_mb` - использование памяти в МБ - `cpu_percent` - загрузка CPU в процентах - `timestamp` - время ответа ### Тестирование Для тестирования PID функционала можно использовать curl: ```bash # Проверка статуса процесса curl http://localhost:8081/status # Проверка всех эндпоинтов curl http://localhost:8081/ ``` ## 📁 Структура проекта ``` AnonBot/ ├── main.py # Точка входа ├── bot.py # Основной файл бота ├── loader.py # Инициализация бота ├── dependencies.py # Система инъекции зависимостей ├── utils.py # Общие утилиты ├── requirements.txt # Зависимости ├── README.md # Документация ├── Dockerfile # Docker образ ├── .dockerignore # Исключения для Docker ├── .env_example # Пример переменных окружения ├── prometheus.yml # Конфигурация Prometheus ├── config/ # Конфигурация │ ├── __init__.py │ ├── config.py # Основная конфигурация │ └── constants.py # Константы приложения ├── handlers/ # Обработчики сообщений │ ├── __init__.py │ ├── start.py # Команды /start, /help │ ├── questions.py # Обработка анонимных вопросов │ ├── answers.py # Обработка ответов │ ├── admin.py # Админ функции │ └── errors.py # Глобальная обработка ошибок ├── keyboards/ # Клавиатуры │ ├── __init__.py │ ├── inline.py # Inline клавиатуры │ └── reply.py # Reply клавиатуры ├── models/ # Модели данных │ ├── __init__.py │ ├── user.py # Модель пользователя │ ├── question.py # Модель вопроса │ ├── user_block.py # Модель блокировки │ └── user_settings.py # Модель настроек ├── services/ # Сервисы (реорганизованы по категориям) │ ├── __init__.py │ ├── utils.py # Общие утилиты │ ├── auth/ # Авторизация и разрешения │ │ ├── __init__.py │ │ └── auth_new.py # Сервис авторизации с системой разрешений │ ├── validation/ # Валидация входных данных │ │ ├── __init__.py │ │ └── input_validator.py # Централизованный валидатор │ ├── business/ # Бизнес-логика │ │ ├── __init__.py │ │ ├── user_service.py # Сервис пользователей │ │ ├── question_service.py # Сервис вопросов │ │ ├── message_service.py # Сервис сообщений │ │ └── pagination_service.py # Сервис пагинации │ ├── infrastructure/ # Инфраструктурные сервисы │ │ ├── __init__.py │ │ ├── database.py # Работа с БД │ │ ├── logger.py # Система логирования │ │ ├── logging_decorators.py # Декораторы для автоматического логирования │ │ ├── logging_utils.py # Утилиты для контекстного логирования │ │ ├── metrics.py # Prometheus метрики │ │ ├── http_server.py # HTTP сервер для метрик │ │ └── pid_manager.py # Менеджер PID файлов │ ├── rate_limiting/ # Rate limiting │ │ ├── __init__.py │ │ ├── rate_limit_config.py # Конфигурация rate limiting │ │ ├── rate_limiter.py # Основной rate limiter │ │ └── rate_limit_service.py # Сервис rate limiting │ └── permissions/ # Система разрешений │ ├── __init__.py │ ├── base.py # Базовые классы │ ├── registry.py # Реестр разрешений │ ├── permissions.py # Стандартные разрешения │ ├── decorators.py # Декораторы для проверки │ └── init_permissions.py # Инициализация ├── examples/ # Примеры использования │ └── dependency_injection_example.py ├── database/ # База данных │ ├── __init__.py │ ├── schema.sql # Схема БД │ ├── crud.py # CRUD операции │ └── examples.py # Примеры использования ├── middlewares/ # Middleware │ ├── __init__.py │ ├── rate_limit_middleware.py # Middleware для rate limiting │ └── validation_middleware.py # Middleware для валидации данных ├── docs/ # Документация └── logs/ # Логи приложения ``` ### 🏗️ Архитектурные улучшения Проект был реорганизован для улучшения структуры и масштабируемости: #### 📁 Новая структура services **До реорганизации:** - Все сервисы в корне `services/` - Смешанные категории (бизнес-логика + инфраструктура) - Дублирование функциональности **После реорганизации:** - **`services/auth/`** - авторизация и разрешения - **`services/business/`** - бизнес-логика (пользователи, вопросы, сообщения) - **`services/infrastructure/`** - инфраструктурные сервисы (БД, логи, метрики) - **`services/rate_limiting/`** - rate limiting компоненты - **`services/permissions/`** - система разрешений (без изменений) #### 📁 Новая структура config **До реорганизации:** - `config.py` и `constants.py` в корне проекта **После реорганизации:** - **`config/`** - папка для всех конфигурационных файлов - **`config/config.py`** - основная конфигурация - **`config/constants.py`** - константы приложения #### ✅ Преимущества новой структуры 1. **Логическая группировка** - связанные сервисы в одних папках 2. **Разделение ответственности** - бизнес-логика отдельно от инфраструктуры 3. **Масштабируемость** - легко добавлять новые сервисы в нужные категории 4. **Читаемость** - понятно, где что находится 5. **Обратная совместимость** - старые импорты продолжают работать #### 🔄 Обратная совместимость Все импорты обновлены, но старые импорты продолжают работать благодаря `__init__.py` файлам: ```python # Старый способ (все еще работает) from services.database import DatabaseService from config import config # Новый способ (рекомендуется) from services.infrastructure.database import DatabaseService from config import config ``` ### 🔍 Система валидации входных данных Реализована централизованная система валидации всех входящих данных для обеспечения безопасности и стабильности: #### 📋 Что валидируется - **Telegram ID** - проверка диапазона и типа данных - **Username** - валидация формата и допустимых символов - **Текстовый контент** - проверка длины, HTML санитизация, защита от спама - **Deep links** - валидация формата и длины - **Callback data** - проверка безопасности и формата - **Параметры пагинации** - валидация диапазонов #### 🛡️ Безопасность - **HTML санитизация** - автоматическое экранирование опасных тегов - **Защита от спама** - проверка на повторяющиеся символы и слова - **Валидация ID** - проверка корректности всех идентификаторов - **Логирование** - полное логирование всех ошибок валидации с автоматическими декораторами #### 🏗️ Архитектура валидации ```python # Централизованный валидатор from services.validation import InputValidator validator = InputValidator() # Валидация текста вопроса result = validator.validate_question_text(text, max_length=1000) if not result: print(f"Ошибка: {result.error_message}") else: sanitized_text = result.sanitized_value # Валидация callback data result = validator.validate_callback_data(callback_data) ``` #### 🔄 Middleware валидации Автоматическая валидация всех входящих данных через middleware: ```python # ValidationMiddleware автоматически валидирует: # - Все callback queries # - Все сообщения # - Telegram ID пользователей # - Username (если есть) # - Chat ID ``` #### ✅ Преимущества 1. **Безопасность** - защита от некорректных данных и атак 2. **Стабильность** - предотвращение ошибок от невалидных данных 3. **UX** - понятные сообщения об ошибках для пользователей 4. **Мониторинг** - полное логирование проблем валидации 5. **Централизация** - единая точка валидации для всего приложения ## 🎯 Как это работает ### Для пользователей: 1. **Регистрация**: Пользователь запускает бота командой `/start` 2. **Получение ссылки**: Бот генерирует персональную ссылку формата `t.me/bot_username?start=ref_{anonymous_id}` 3. **Публикация ссылки**: Пользователь делится ссылкой в социальных сетях 4. **Получение вопросов**: Друзья переходят по ссылке и задают анонимные вопросы 5. **Ответы**: Пользователь получает уведомления и может отвечать на вопросы ### Для отправителей вопросов: 1. **Переход по ссылке**: Отправитель переходит по персональной ссылке пользователя 2. **Задание вопроса**: Отправляет вопрос боту 3. **Анонимность**: Вопрос передается получателю анонимно 4. **Получение ответа**: Если получатель ответит, ответ будет показан ## 🔧 Команды бота ### Основные команды: - `/start` - Запуск бота и получение персональной ссылки - `/help` - Справка по использованию бота ### Админ команды: - `/stats` - Показать статистику бота (только для админов) ## 👑 Админ панель Администраторы имеют доступ к дополнительным функциям: - 📊 **Статистика** - общая статистика бота, пользователей и вопросов - 👥 **Пользователи** - список всех пользователей бота - ❓ **Все вопросы** - статистика по всем вопросам - 📢 **Рассылка** - функция рассылки (планируется) - ⚙️ **Настройки** - просмотр текущих настроек бота ## 🔍 Система ролей и суперпользователи Бот поддерживает трехуровневую систему ролей: ### 👑 Администраторы (admin) - Определяются в конфигурации (`ADMINS` в `.env`) - Имеют все права доступа - Не могут быть изменены через базу данных ### 🔍 Суперпользователи (superuser) - Определяются в базе данных (поле `is_superuser = TRUE`) - Имеют расширенные права для модерации - **Могут видеть информацию об авторах вопросов** #### Особенности для суперпользователей: **Отображение списка вопросов:** ``` 10. ✅ #2 Вопрос от @username FirstName LastName ``` **Уведомления о новых вопросах:** ``` ❓ Новый вопрос от @username FirstName LastName! 📝 Вопрос: Текст вопроса... 📅 05.09.2025 23:27 ``` ### 👤 Обычные пользователи (user) - Стандартные права доступа - Видят анонимные вопросы без информации об авторах ### Назначение суперпользователя Суперпользователей можно назначать через базу данных: ```sql UPDATE users SET is_superuser = TRUE WHERE telegram_id = 123456789; ``` Или программно: ```python from services.infrastructure.database import DatabaseService async def make_superuser(telegram_id: int): db_service = DatabaseService("database/anon_qna.db") user = await db_service.get_user(telegram_id) if user: user.is_superuser = True await db_service.update_user(user) ``` ## 🔐 Система разрешений AnonBot использует современную систему разрешений, построенную с соблюдением принципа открытости/закрытости (OCP): ### ✅ Преимущества новой системы - **Открытость для расширения** - новые разрешения добавляются без изменения существующего кода - **Закрытость для модификации** - существующий код не изменяется при добавлении новых разрешений - **Типобезопасность** - использование классов вместо строк - **Единая точка входа** - все проверки разрешений через один интерфейс - **Удобные декораторы** - простое применение проверок разрешений ### 🎯 Стандартные разрешения | Разрешение | Описание | Доступ | |------------|----------|--------| | `admin` | Права администратора | Только администраторы | | `superuser` | Права суперпользователя | Только суперпользователи | | `view_stats` | Просмотр статистики | Администраторы + суперпользователи | | `admin_panel` | Доступ к админ панели | Администраторы + суперпользователи | | `manage_users` | Управление пользователями | Администраторы + суперпользователи | | `broadcast` | Рассылка сообщений | Только администраторы | | `view_questions` | Просмотр вопросов | Все активные пользователи | | `ask_questions` | Задавание вопросов | Все активные незабаненные пользователи | | `answer_questions` | Ответы на вопросы | Все активные незабаненные пользователи | ### 🚀 Использование #### С декораторами (рекомендуется) ```python from services.permissions.decorators import require_permission @router.message(Command("my_command")) @require_permission("view_stats", "❌ У вас нет прав для выполнения этой команды.") async def my_command_handler(message: Message): # Логика обработчика await message.answer("Команда выполнена!") ``` #### Готовые декораторы ```python @require_permission("view_stats") # Конкретное разрешение @require_admin() # Только администраторы @require_superuser() # Только суперпользователи @require_admin_or_superuser() # Администраторы или суперпользователи @require_active_user() # Активные пользователи @require_unbanned_user() # Незабаненные пользователи ``` #### Добавление нового разрешения ```python # 1. Создаем класс разрешения class MyCustomPermission(Permission): async def check(self, user_id: int, database: DatabaseService, config) -> bool: return user_id in config.ADMINS # 2. Регистрируем разрешение register_permission(MyCustomPermission()) # 3. Используем в обработчике @require_permission("my_custom_permission") async def my_handler(message: Message): # Логика обработчика pass ``` ## 🛡️ Безопасность - **Валидация**: Проверка всех входящих данных - **Обработка ошибок**: Глобальная обработка ошибок с уведомлениями админов - **Логирование**: Автоматическое логирование с декораторами, контекстная информация, FSM отслеживание - **Система ролей**: Трехуровневая система доступа (админ/суперпользователь/пользователь) - **Система разрешений**: Гибкая система разрешений с соблюдением принципа OCP ## 🏗️ Система инъекции зависимостей AnonBot использует современную систему инъекции зависимостей, построенную на основе **MagicData** из aiogram 3.x. Это обеспечивает: - **Тестируемость**: Легко мокать зависимости в тестах - **Читаемость**: Явные зависимости в сигнатурах функций - **Гибкость**: Легко заменять реализации сервисов - **Обратная совместимость**: Старый код продолжает работать ### Доступные сервисы 1. **DatabaseService** - работа с базой данных, CRUD операции 2. **AuthService** - авторизация, проверка прав, управление ролями 3. **InputValidator** - централизованная валидация всех входных данных 4. **UtilsService** - форматирование данных, утилиты 5. **RateLimitService** - управление rate limiting, статистика 6. **Config** - доступ к конфигурации приложения ### Быстрый старт с DI ```python # Подключение в loader.py from dependencies import DependencyMiddleware, get_dependencies async def init_dispatcher() -> Dispatcher: dp = Dispatcher(storage=storage) # Инициализируем зависимости deps = get_dependencies() await deps.init() # Добавляем middleware dp.update.middleware(DependencyMiddleware(deps)) return dp # Использование в обработчиках from dependencies import inject_start_services, inject_question_services, inject_answer_services from services.infrastructure.database import DatabaseService from services.auth.auth_new import AuthService from services.validation import InputValidator @router.message(Command("start")) @inject_start_services async def cmd_start( message: Message, user_service: UserService, auth: AuthService, utils: UtilsService, message_service: MessageService, validator: InputValidator ): # Валидируем входные данные user_id_validation = validator.validate_telegram_id(message.from_user.id) if not user_id_validation: await message.answer("❌ Ошибка: недопустимый ID пользователя") return # Используем сервисы без хардкода is_admin = auth.is_admin(message.from_user.id) user = await user_service.get_user_by_telegram_id(message.from_user.id) ``` ### Способы инъекции 1. **Специализированные декораторы** (рекомендуется): - `@inject_question_services` - для обработки вопросов - `@inject_answer_services` - для обработки ответов - `@inject_start_services` - для команды /start - `@inject_link_services` - для кнопки "Моя ссылка" - `@inject_main_menu_services` - для кнопки "Главное меню" 2. **Базовые декораторы**: - `@inject_database` - только DatabaseService - `@inject_auth` - только AuthService - `@inject_utils` - только UtilsService 3. **Автоматически**: aiogram инжектит зависимости из middleware 4. **Обратная совместимость**: старые функции продолжают работать ### Примеры использования специализированных декораторов #### Обработка вопросов ```python @router.message(StateFilter(QuestionStates.waiting_for_question)) @inject_question_services async def process_anonymous_question( message: Message, state: FSMContext, question_service: QuestionService, user_service: UserService, message_service: MessageService, validator: InputValidator ): # Валидируем и обрабатываем вопрос validation_result = validator.validate_question_text(message.text) if not validation_result: await message_service.send_message(message, "❌ Неверный формат вопроса") return # Создаем вопрос через сервис question = await question_service.create_question( message.from_user.id, target_user_id, validation_result.sanitized_value ) ``` #### Обработка ответов ```python @router.message(StateFilter(AnswerStates.waiting_for_answer)) @inject_answer_services async def process_new_answer( message: Message, state: FSMContext, validator: InputValidator ): # Валидируем ответ validation_result = validator.validate_answer_text(message.text) if not validation_result: await message.answer("❌ Неверный формат ответа") return # Сохраняем ответ # ... логика сохранения ``` ### Локальная нумерация вопросов #### Отображение вопросов с локальными номерами ```python # В модели Question добавлен метод get_display_number() def get_display_number(self) -> int: """Получить номер вопроса для отображения (приоритет user_question_number)""" return self.user_question_number if self.user_question_number is not None else self.id # В обработчиках используется локальная нумерация questions_text += f"{i}. {emoji} #{question.get_display_number()}" ``` #### Автоматическая нумерация через триггеры БД ```sql -- Триггер для автоматического вычисления номера при создании CREATE TRIGGER calculate_user_question_number AFTER INSERT ON questions FOR EACH ROW WHEN NEW.user_question_number IS NULL BEGIN UPDATE questions SET user_question_number = ( SELECT COALESCE(MAX(user_question_number), 0) + 1 FROM questions q2 WHERE q2.to_user_id = NEW.to_user_id AND q2.status != 'deleted' ) WHERE id = NEW.id; END; -- Триггер для пересчета номеров при удалении CREATE TRIGGER recalculate_user_question_numbers_on_delete AFTER UPDATE ON questions FOR EACH ROW WHEN NEW.status = 'deleted' AND OLD.status != 'deleted' BEGIN UPDATE questions SET user_question_number = user_question_number - 1 WHERE to_user_id = NEW.to_user_id AND user_question_number > OLD.user_question_number AND status != 'deleted'; UPDATE questions SET user_question_number = NULL WHERE id = NEW.id; END; ``` #### Обработка команд ```python @router.message(Command("start")) @inject_start_services async def cmd_start( message: Message, state: FSMContext, user_service: UserService, auth: AuthService, utils: UtilsService, message_service: MessageService, validator: InputValidator ): # Создаем или обновляем пользователя user = await user_service.create_or_update_user(message.from_user, message.chat.id) # Проверяем права is_admin = auth.is_admin(user.telegram_id) # Отправляем приветствие await message_service.send_message(message, welcome_text, keyboard) ``` ### Преимущества специализированных декораторов ✅ **Нет проблем с `dispatcher`** - aiogram не передает лишние параметры ✅ **Меньше зависимостей** - инжектируются только нужные сервисы ✅ **Лучшая производительность** - меньше объектов создается ✅ **Более явный код** - видно, какие зависимости используются ✅ **Легче тестировать** - меньше моков нужно создавать ### Тестирование Система DI значительно упрощает тестирование: ```python # Создание тестовых зависимостей @pytest.fixture async def test_dependencies(): deps = Dependencies() deps._database = AsyncMock() # Мокаем БД deps._auth = MagicMock() # Мокаем авторизацию return deps # Тестирование обработчиков @pytest.mark.asyncio async def test_cmd_start(test_dependencies): # Настраиваем моки test_dependencies._user_service.get_user_by_telegram_id.return_value = mock_user test_dependencies._auth.is_admin.return_value = False # Тестируем обработчик result = await cmd_start( message, state, user_service=test_dependencies.user_service, auth=test_dependencies.auth, utils=test_dependencies.utils, message_service=test_dependencies.message_service, validator=test_dependencies.validator ) # Проверяем результат assert result is not None ``` Подробная документация: [DI_SETUP.md](DI_SETUP.md) ## 📊 База данных Бот использует SQLite для хранения данных: ### Таблицы: - **users**: Информация о пользователях (ID, имя, ссылка, статус, права суперпользователя) - **questions**: Вопросы и ответы (текст, статус, анонимность, локальная нумерация) - **user_blocks**: Блокировки пользователей - **user_settings**: Настройки пользователей (уведомления, язык) ### Особенности: - **Внешние ключи**: Связи между таблицами - **Триггеры**: Автоматическое обновление timestamps и нумерация вопросов - **Индексы**: Оптимизация запросов, включая индексы для локальной нумерации - **CRUD операции**: Полный набор операций для каждой таблицы - **Локальная нумерация**: Каждый пользователь видит свои вопросы с номерами #1, #2, #3... ### Автоматическая нумерация вопросов: - **Триггер `calculate_user_question_number`**: Автоматически присваивает номер при создании вопроса - **Триггер `recalculate_user_question_numbers_on_delete`**: Пересчитывает номера при удалении вопроса - **Удаленные вопросы**: Не участвуют в нумерации (status = 'deleted') - **Уникальные номера**: Гарантируется уникальность номеров в рамках каждого пользователя ### Схема: Схема базы данных находится в файле `database/schema.sql` ## 🔧 Настройка Все настройки находятся в файле `.env`: - `BOT_TOKEN` - токен бота (обязательно) - `ADMINS` - список ID администраторов - `DATABASE_PATH` - путь к файлу базы данных - `DEBUG` - режим отладки - `MAX_QUESTION_LENGTH` - максимальная длина вопроса - `MAX_ANSWER_LENGTH` - максимальная длина ответа #### Настройки Rate Limiting: - `RATE_LIMIT_ENV` - окружение (development/production/strict) - `RATE_LIMIT_MESSAGES_PER_SECOND` - сообщений в секунду на чат - `RATE_LIMIT_BURST_LIMIT` - максимум сообщений подряд - `RATE_LIMIT_RETRY_MULTIPLIER` - множитель для задержки при retry - `RATE_LIMIT_MAX_RETRY_DELAY` - максимальная задержка между попытками - `RATE_LIMIT_MAX_RETRIES` - максимальное количество повторных попыток ## 🚀 Развертывание ### Локальный запуск: ```bash python main.py ``` ### Docker (планируется): ```bash docker build -t anonbot . docker run -d --name anonbot anonbot ``` ### VPS/Сервер: 1. Загрузите код на сервер 2. Установите зависимости: `pip install -r requirements.txt` 3. Настройте `.env` файл 4. **Для обновления существующей базы данных** (если нужно добавить поле `is_superuser`): ```bash python3 -c " import asyncio import aiosqlite async def migrate(): async with aiosqlite.connect('database/anon_qna.db') as conn: await conn.execute('ALTER TABLE users ADD COLUMN is_superuser BOOLEAN DEFAULT FALSE') await conn.execute('CREATE INDEX IF NOT EXISTS idx_users_is_superuser ON users(is_superuser)') await conn.commit() print('Миграция завершена!') asyncio.run(migrate()) " ``` 5. Запустите: `python main.py` 6. Рекомендуется использовать systemd или supervisor для автозапуска ## 📝 Система логирования В проекте настроена продвинутая система логирования с использованием библиотеки **loguru** и автоматических декораторов. Логи выводятся в stderr для корректной работы в Docker контейнерах. ### Основные компоненты - **services/infrastructure/logger.py** - основная настройка системы логирования - **services/infrastructure/logging_decorators.py** - декораторы для автоматического логирования - **services/infrastructure/logging_utils.py** - утилиты для контекстного логирования - **loguru** - библиотека для логирования (уже добавлена в requirements.txt) ### Уровни логирования - **INFO** - основная информация о работе бота - **WARNING** - предупреждения о потенциальных проблемах - **ERROR** - ошибки, требующие внимания ### Формат логов ``` 2024-01-15 10:30:45 | INFO | bot:main:25 - 🚀 Запуск бота в режиме polling 2024-01-15 10:30:45 | INFO | loader:init_bot:28 - 🤖 Инициализация Telegram бота 2024-01-15 10:30:45 | INFO | loader:init_bot:33 - ✅ Бот успешно инициализирован ``` ### 🎯 Автоматические декораторы логирования Система включает в себя набор декораторов для автоматического логирования: #### 1. Основные декораторы **`@log_function_call`** - логирование входа/выхода из функций ```python @log_function_call(log_params=True, log_result=True) async def create_question(self, from_user_id: int, to_user_id: int, message_text: str): # Автоматически логирует вход с параметрами и выход с результатом ``` **`@log_business_event`** - логирование бизнес-событий ```python @log_business_event("create_question", log_params=True, log_result=True) async def create_question(self, ...): # Логирует бизнес-событие с контекстом ``` **`@log_fsm_transition`** - логирование FSM переходов ```python @log_fsm_transition(to_state="waiting_for_answer") async def answer_question_callback(callback: CallbackQuery, state: FSMContext): # Логирует переходы между состояниями FSM ``` #### 2. Оптимизированные декораторы **`@log_middleware`** - тихое логирование для middleware ```python @log_middleware(log_params=True, log_result=False) async def __call__(self, handler, event, data): # Логирует только ошибки, вход/выход в DEBUG режиме ``` **`@log_utility`** - декоратор для служебных функций ```python @log_utility def _has_attachments(message: Message) -> bool: # Логирует только ошибки ``` #### 3. Контекстное логирование **`LoggingContext`** - контекстное логирование с дополнительной информацией ```python context = get_logging_context(__name__) context.add_context("user_id", user_id) context.log_info("Пользователь выполнил действие") ``` **Специальные функции** для бизнес-событий: ```python log_question_created(logger, question_id, from_user_id, to_user_id) log_user_created(logger, user_id, username) log_user_blocked(logger, user_id, reason) ``` ### Покрытие логированием #### 1. Запуск и инициализация - ✅ Инициализация бота - ✅ Инициализация диспетчера - ✅ Инициализация базы данных - ✅ Регистрация обработчиков - ✅ Уведомления администраторов #### 2. База данных (CRUD операции) - ✅ Создание пользователей - ✅ Создание вопросов - ✅ Обновление вопросов - ✅ Инициализация БД #### 3. Обработчики команд - ✅ Команда /start - ✅ Обработка deep links - ✅ Создание/обновление пользователей #### 4. Бизнес-логика - ✅ Отправка ответов авторам - ✅ Обработка ошибок - ✅ Валидация данных #### 5. Системные события - ✅ Ошибки в обработчиках - ✅ Очистка ресурсов - ✅ Остановка бота #### 6. FSM состояния - ✅ Переходы между состояниями - ✅ Обработка FSM событий - ✅ Отслеживание пользовательских сессий ### Использование в коде #### Импорт логгера и декораторов ```python from services.infrastructure.logger import get_logger from services.infrastructure.logging_decorators import ( log_function_call, log_business_event, log_fsm_transition, log_middleware, log_utility ) from services.infrastructure.logging_utils import ( log_user_action, log_business_operation, log_question_created ) logger = get_logger(__name__) ``` #### Примеры использования декораторов ```python # Бизнес-события @log_business_event("create_question", log_params=True, log_result=True) async def create_question(self, from_user_id: int, to_user_id: int, message_text: str): # Автоматически логирует создание вопроса pass # FSM переходы @log_fsm_transition(to_state="waiting_for_answer") async def answer_question_callback(callback: CallbackQuery, state: FSMContext): # Логирует переход в состояние ответа pass # Middleware (тихое логирование) @log_middleware(log_params=True, log_result=False) async def __call__(self, handler, event, data): # Логирует только ошибки pass # Служебные функции @log_utility def _has_attachments(message: Message) -> bool: # Логирует только ошибки pass ``` #### Контекстное логирование ```python # Создание контекста context = get_logging_context(__name__) context.add_context("user_id", user_id) context.add_context("question_id", question_id) context.log_info("Пользователь ответил на вопрос") # Специальные функции для бизнес-событий log_question_created(logger, question_id, from_user_id, to_user_id) log_user_created(logger, user_id, username) log_user_blocked(logger, user_id, reason) ``` #### Традиционное логирование ```python # Информационные сообщения logger.info("🚀 Запуск бота в режиме polling") logger.info(f"👤 Создание пользователя: {user.telegram_id} ({user.first_name})") # Предупреждения logger.warning("⚠️ Список администраторов пуст") logger.warning(f"⚠️ Не удалось отправить уведомление админу {admin_id}: {e}") # Ошибки logger.error(f"💥 Ошибка при запуске бота: {e}") logger.error(f"💥 Ошибка в обработчике /start: {e}") ``` ### Docker интеграция Логи настроены для вывода в stderr, что обеспечивает корректную работу в Docker: ```dockerfile # В Dockerfile CMD ["python", "main.py"] ``` ```bash # Просмотр логов в Docker docker logs ``` ### Файловое логирование (DEBUG режим) В режиме отладки логи также сохраняются в файлы: - **logs/bot.log** - основные логи - Ротация: 10 MB - Хранение: 7 дней - Сжатие: zip ### ⚡ Производительность и оптимизация #### Тихие декораторы Для предотвращения избыточного логирования используются тихие декораторы: - **`@log_middleware`** - для middleware (логирует только ошибки) - **`@log_utility`** - для служебных функций (логирует только ошибки) - **`quiet=True`** - параметр для полного отключения логирования входа/выхода #### Уровни логирования - **INFO** - бизнес-события и важные операции - **DEBUG** - детальная информация (только в DEBUG режиме) - **WARNING** - предупреждения - **ERROR** - ошибки (всегда логируются) #### Контекстная информация Декораторы автоматически извлекают контекстную информацию: - `user_id` - ID пользователя - `question_id` - ID вопроса - `page` - номер страницы - `status` - статус операции #### Примеры оптимизированного логирования ```python # Middleware - тихое логирование @log_middleware(log_params=True, log_result=False) async def __call__(self, handler, event, data): # Логирует только ошибки, вход/выход в DEBUG режиме pass # Служебные функции - только ошибки @log_utility def _has_attachments(message: Message) -> bool: # Логирует только ошибки pass # Бизнес-функции - полное логирование @log_business_event("create_question", log_params=True, log_result=True) async def create_question(self, ...): # Полное логирование для важных операций pass ``` ### Мониторинг #### Ключевые метрики для мониторинга 1. **Запуск/остановка бота** - `🚀 Запуск бота в режиме polling` - `🛑 Бот остановлен` 2. **Пользователи** - `👤 Создание пользователя` - `👤 Обновление существующего пользователя` 3. **Вопросы и ответы** - `❓ Создание вопроса` - `📝 Обновление вопроса` - `📤 Отправка ответа` 4. **Ошибки** - `💥 Ошибка в обработчике` - `⚠️ Предупреждения` #### Алерты Рекомендуется настроить алерты на: - ERROR уровень логов - Отсутствие логов более 5 минут - Частые ошибки в обработчиках ### Настройка уровней Уровень логирования настраивается через переменную окружения: ```bash # В .env файле DEBUG=true # DEBUG уровень DEBUG=false # INFO уровень (по умолчанию) ``` ### Производительность - Логирование асинхронное - Минимальное влияние на производительность - Эмодзи в логах для быстрого визуального поиска - Структурированный формат для парсинга ## 🤝 Вклад в проект 1. Fork репозитория 2. Создайте feature branch 3. Внесите изменения 4. Создайте Pull Request ## 📄 Лицензия MIT License ## 🆘 Поддержка Если у вас возникли проблемы: 1. Проверьте логи бота 2. Убедитесь в правильности настройки `.env` 3. Проверьте права доступа к файлам 4. Обратитесь к администратору ### Дополнительная документация: - [Руководство по суперпользователям](SUPERUSER_DISPLAY_FEATURE.md) - подробное описание системы ролей и функционала для суперпользователей - [Настройка Dependency Injection](DI_SETUP.md) - подробное руководство по системе инъекции зависимостей - [Примеры использования DI](examples/dependency_injection_example.py) - практические примеры использования системы инъекции зависимостей ## 📈 Prometheus метрики AnonBot поддерживает экспорт метрик в формате Prometheus для мониторинга и анализа производительности. ### Эндпоинты - **http://localhost:8081/metrics** - экспорт метрик Prometheus - **http://localhost:8081/health** - проверка здоровья бота - **http://localhost:8081/ready** - готовность к работе (readiness probe) - **http://localhost:8081/status** - информация о процессе (PID, uptime, использование ресурсов) - **http://localhost:8081/** - информация о сервисе ### Доступные метрики #### Информационные метрики - `anon_bot_info` - Информация о боте (версия, сервис) #### Счетчики сообщений - `anon_bot_messages_total` - Общее количество обработанных сообщений - Метки: `message_type`, `status` #### Счетчики вопросов - `anon_bot_questions_total` - Общее количество вопросов - Метки: `status` (created, rejected, deleted) #### Счетчики ответов - `anon_bot_answers_total` - Общее количество ответов - Метки: `status` (sent, edited, delivered, delivery_failed) #### Счетчики пользователей - `anon_bot_users_total` - Общее количество пользователей - Метки: `action` (created, updated) #### Счетчики ошибок - `anon_bot_errors_total` - Общее количество ошибок - Метки: `error_type`, `component` #### HTTP метрики - `anon_bot_http_requests_total` - Общее количество HTTP запросов - Метки: `method`, `endpoint`, `status_code` - `anon_bot_http_request_duration_seconds` - Время обработки HTTP запросов - Метки: `method`, `endpoint` #### Время обработки - `anon_bot_message_processing_seconds` - Время обработки сообщений - Метки: `message_type` - `anon_bot_question_processing_seconds` - Время обработки вопросов - `anon_bot_answer_processing_seconds` - Время обработки ответов #### Gauge метрики - `anon_bot_active_users` - Количество активных пользователей - `anon_bot_active_questions` - Количество активных вопросов ### Настройка Prometheus Добавьте в конфигурацию Prometheus (`prometheus.yml`): ```yaml scrape_configs: - job_name: 'anon-bot' static_configs: - targets: ['localhost:8081'] metrics_path: '/metrics' scrape_interval: 30s ``` ### Примеры запросов PromQL #### Количество сообщений в секунду ```promql rate(anon_bot_messages_total[5m]) ``` #### Количество ошибок в секунду ```promql rate(anon_bot_errors_total[5m]) ``` #### Время обработки сообщений (95-й процентиль) ```promql histogram_quantile(0.95, rate(anon_bot_message_processing_seconds_bucket[5m])) ``` #### Количество активных пользователей ```promql anon_bot_active_users ``` ### Мониторинг в Docker При запуске в Docker убедитесь, что порт 8081 доступен: ```yaml ports: - "8081:8081" ``` ### Алерты Рекомендуется настроить алерты на: 1. **Высокий уровень ошибок** ```promql rate(anon_bot_errors_total[5m]) > 0.1 ``` 2. **Медленную обработку** ```promql histogram_quantile(0.95, rate(anon_bot_message_processing_seconds_bucket[5m])) > 5 ``` 3. **Недоступность сервиса** ```promql up{job="anon-bot"} == 0 ``` ### Безопасность Эндпоинты метрик не требуют аутентификации. В продакшене рекомендуется: - Ограничить доступ к эндпоинтам через firewall - Использовать reverse proxy с аутентификацией - Настроить TLS для HTTPS ## 🔧 Исправление проблем с метриками ### 🔍 Найденные проблемы В дашбордах Grafana не отображались следующие метрики: - Database Connections - Active - Database Performance - Query Duration - Active Questions - Active Users - Answers per Minute - Live Activity - Active Users ### 🛠️ Внесенные исправления #### 1. Создан сервис MetricsUpdater (`services/infrastructure/metrics_updater.py`) **Исправление циклической зависимости**: Первоначально возникла циклическая зависимость между `metrics_updater.py` и `dependencies.py`. Проблема была решена путем: - Удаления импорта `get_database_service` из `dependencies` - Передачи пути к БД напрямую в конструктор `MetricsUpdater` - Создания собственного экземпляра `DatabaseService` внутри `MetricsUpdater` **Исправление использования логгера**: Первоначально использовался `loguru` напрямую, но в проекте уже есть настроенная система логирования. Исправлено: - Заменен `from loguru import logger` на `from .logger import get_logger` - Используется `self.logger = get_logger(__name__)` в конструкторе - Все вызовы `logger` заменены на `self.logger` **Проблема**: Методы `set_active_users()` и `set_active_questions()` были определены в `MetricsService`, но нигде не вызывались. **Решение**: Создан сервис `MetricsUpdater`, который: - Периодически обновляет количество активных пользователей (за последние 24 часа) - Периодически обновляет количество активных вопросов (статус pending/processing) - Обновляет метрики соединений с БД - Запускается автоматически при старте бота #### 2. Создан декоратор для метрик БД (`services/infrastructure/db_metrics_decorator.py`) **Проблема**: Методы `record_db_connection()` и `record_db_query()` были определены, но не интегрированы в код БД. **Решение**: Создан декоратор `track_db_operation`, который: - Автоматически записывает время выполнения операций БД - Отслеживает успешные и неудачные операции - Записывает метрики соединений с БД - Использует существующую систему логирования проекта **Интеграция декораторов**: Для избежания циклических зависимостей создан патч `crud_metrics_patch.py`: - Применяет декораторы к CRUD операциям после их импорта - Автоматически активируется при импорте модуля - Покрывает основные операции: INSERT, SELECT, UPDATE для users и questions - **Исправлено**: Убрано применение `track_db_connection` к `@asynccontextmanager` методам (ошибка `__aenter__`) #### 3. Обновлен bot.py **Изменения**: - Добавлен запуск `MetricsUpdater` при старте бота - Добавлена остановка `MetricsUpdater` при завершении работы - Передача пути к БД в `MetricsUpdater`: `config.DATABASE_PATH` - Интервал обновления метрик: 30 секунд #### 4. Обновлен __init__.py **Изменения**: - Добавлен экспорт новых сервисов и декораторов - Обновлен список `__all__` ### 📊 Ожидаемые результаты После внесения исправлений в дашбордах Grafana должны отображаться: #### AnonBot Overview: - ✅ **Active Users** - количество активных пользователей за 24 часа - ✅ **Active Questions** - количество активных вопросов (pending/processing) - ✅ **Live Activity - Active Users** - то же значение, что и Active Users - ✅ **Answers per Minute** - скорость отправки ответов #### Performance AnonBot: - ✅ **Database Connections - Active** - количество активных соединений с БД - ✅ **Database Performance - Query Duration** - время выполнения запросов к БД #### Server Monitoring: - ✅ **AnonBot System Health** - активные пользователи - ✅ **AnonBot Active Questions** - активные вопросы - ✅ **AnonBot Database Connections** - соединения с БД ### 🚀 Развертывание исправлений 1. **Перезапустите AnonBot**: ```bash docker-compose restart anon-bot ``` 2. **Проверьте логи**: ```bash docker-compose logs -f anon-bot ``` Должны появиться сообщения: ``` 📊 Запуск обновления метрик... 📊 MetricsUpdater запущен с интервалом 30 секунд ``` 3. **Проверьте метрики**: ```bash curl http://localhost:8081/metrics | grep anon_bot_active ``` 4. **Проверьте в Grafana**: - Откройте дашборды AnonBot - Дождитесь обновления данных (до 30 секунд) - Проверьте отображение метрик ### 🔧 Дополнительные настройки #### Изменение интервала обновления метрик В файле `bot.py` можно изменить интервал обновления: ```python # Текущий интервал: 30 секунд await start_metrics_updater(update_interval=30) # Для более частого обновления (например, 10 секунд): await start_metrics_updater(update_interval=10) ``` #### Добавление метрик БД в CRUD операции Для автоматического сбора метрик БД в CRUD операциях добавьте декоратор: ```python from services.infrastructure import track_db_operation @track_db_operation("SELECT", "users") async def get_user(self, user_id: int): # код метода pass ``` ### 📈 Мониторинг После внесения исправлений рекомендуется настроить алерты: 1. **Низкая активность пользователей**: `anon_bot_active_users < 1` 2. **Много активных вопросов**: `anon_bot_active_questions > 100` 3. **Проблемы с БД**: `anon_bot_db_connections_active == 0` 4. **Высокое время ответа БД**: `histogram_quantile(0.95, rate(anon_bot_db_query_duration_seconds_bucket[5m])) > 1` ### 🐛 Troubleshooting #### Ошибка циклической зависимости **Проблема**: `ImportError: cannot import name 'get_database_service' from partially initialized module 'dependencies'` **Решение**: Проблема была исправлена в версии 2.0 исправлений: - Удален импорт `get_database_service` из `metrics_updater.py` - Добавлен параметр `db_path` в конструктор `MetricsUpdater` - `DatabaseService` создается внутри `MetricsUpdater` с переданным путем к БД #### Метрики не обновляются 1. Проверьте логи AnonBot: ```bash docker-compose logs anon-bot | grep -i metrics ``` 2. Проверьте доступность эндпоинта: ```bash curl http://localhost:8081/metrics ``` 3. Проверьте конфигурацию Prometheus: ```bash curl http://localhost:9090/api/v1/targets | grep anon-bot ``` #### Ошибки в логах Если появляются ошибки типа "Database connection failed", проверьте: - Доступность базы данных - Правильность пути к БД в конфигурации - Права доступа к файлу БД #### Нулевые значения в дашбордах Если метрики отображаются, но имеют нулевые значения: - Убедитесь, что в БД есть данные (пользователи, вопросы) - Проверьте SQL запросы в `MetricsUpdater` - Увеличьте интервал обновления для накопления данных ## 🐳 Docker ### Сборка образа ```bash docker build -t anon-bot . ``` ### Запуск контейнера ```bash docker run -d \ --name anon-bot \ --restart unless-stopped \ -p 8081:8081 \ -v $(pwd)/database:/app/database \ -v $(pwd)/logs:/app/logs \ -e BOT_TOKEN=your_bot_token_here \ -e ADMINS=123456789,987654321 \ -e DEBUG=false \ anon-bot ``` ### Управление контейнером ```bash # Просмотр логов docker logs anon-bot # Остановка контейнера docker stop anon-bot # Запуск контейнера docker start anon-bot # Удаление контейнера docker rm anon-bot # Перезапуск контейнера docker restart anon-bot ``` ### Переменные окружения Все переменные окружения из `.env_example` можно передать через `-e`: ```bash docker run -d \ --name anon-bot \ -p 8081:8081 \ -e BOT_TOKEN=your_token \ -e ADMINS=123456789 \ -e DEBUG=false \ -e MAX_QUESTION_LENGTH=1000 \ -e MAX_ANSWER_LENGTH=2000 \ anon-bot ``` ### Volumes - `./database:/app/database` - персистентное хранение базы данных - `./logs:/app/logs` - персистентное хранение логов ### Порты - `8081:8081` - порт для метрик и health check ### Health Check Контейнер включает встроенный health check: ```bash # Проверка статуса docker inspect --format='{{.State.Health.Status}}' anon-bot # Просмотр деталей health check docker inspect anon-bot | jq '.[0].State.Health' ``` **Параметры health check:** - **Интервал проверки**: 30 секунд - **Таймаут**: 10 секунд - **Период запуска**: 60 секунд (время на инициализацию) - **Количество попыток**: 3 - **Команда проверки**: `curl -f http://localhost:8081/health` **Статусы health check:** - `starting` - контейнер запускается - `healthy` - контейнер здоров - `unhealthy` - контейнер нездоров ## 🚦 Rate Limiting AnonBot включает комплексную систему rate limiting для предотвращения ошибок Flood Control в Telegram Bot API. Система автоматически ограничивает скорость отправки сообщений и обрабатывает ошибки с повторными попытками. ### Рекомендуемые настройки на основе лимитов Telegram API Система настроена с учетом официальных лимитов Telegram Bot API: - **1 сообщение в секунду** в личных чатах - **20 сообщений в минуту** в групповых чатах (0.33 в секунду) - **30 запросов в секунду** глобально Настройки по умолчанию используют консервативные значения (50% от лимитов) для обеспечения стабильной работы. ### Компоненты системы #### 1. Конфигурация (`services/rate_limit_config.py`) - **RateLimitSettings**: Основные настройки rate limiting - **Конфигурации для разных окружений**: development, production, strict - **Адаптивная конфигурация**: Автоматическая настройка на основе уровня ошибок #### 2. Rate Limiter (`services/rate_limiter.py`) - **ChatRateLimiter**: Ограничения для конкретного чата - **GlobalRateLimiter**: Глобальные ограничения для всех чатов - **RetryHandler**: Обработка повторных попыток с экспоненциальной задержкой - **TelegramRateLimiter**: Основной класс, объединяющий все компоненты #### 3. Сервис (`services/rate_limit_service.py`) - **RateLimitService**: Высокоуровневый сервис для управления rate limiting - **Статистика**: Отслеживание успешных/неудачных запросов - **Адаптация**: Автоматическая настройка конфигурации #### 4. Middleware (`middlewares/rate_limit_middleware.py`) - **RateLimitMiddleware**: Автоматическое применение rate limiting ко всем сообщениям - **Прозрачная интеграция**: Минимальные изменения в существующем коде #### 5. Validation Middleware (`middlewares/validation_middleware.py`) - **ValidationMiddleware**: Автоматическая валидация всех входящих данных - **Безопасность**: Защита от некорректных данных и атак - **Логирование**: Оптимизированное логирование с тихими декораторами для middleware ### Настройка #### Переменные окружения Добавьте следующие переменные в ваш `.env` файл: ```env # Окружение для rate limiting (development/production/strict) RATE_LIMIT_ENV=production # Основные настройки rate limiting RATE_LIMIT_MESSAGES_PER_SECOND=0.5 RATE_LIMIT_BURST_LIMIT=2 RATE_LIMIT_RETRY_MULTIPLIER=1.5 RATE_LIMIT_MAX_RETRY_DELAY=30.0 RATE_LIMIT_MAX_RETRIES=3 # Задержки для разных типов сообщений RATE_LIMIT_VOICE_DELAY=2.0 RATE_LIMIT_MEDIA_DELAY=1.5 RATE_LIMIT_TEXT_DELAY=1.0 # Множители для разных типов чатов RATE_LIMIT_PRIVATE_MULTIPLIER=1.0 RATE_LIMIT_GROUP_MULTIPLIER=0.8 RATE_LIMIT_CHANNEL_MULTIPLIER=0.6 # Глобальные ограничения RATE_LIMIT_GLOBAL_MESSAGES_PER_SECOND=10.0 RATE_LIMIT_GLOBAL_BURST_LIMIT=20 ``` #### Конфигурации по умолчанию **Production (по умолчанию)** - 0.5 сообщений в секунду на чат (50% от лимита Telegram API) - Максимум 2 сообщения подряд - 3 повторные попытки при ошибках - Максимальная задержка 30 секунд - 20 глобальных запросов в секунду (из 30 доступных) **Development** - 0.8 сообщений в секунду на чат (80% от лимита для тестирования) - Максимум 3 сообщения подряд - 2 повторные попытки при ошибках - Максимальная задержка 15 секунд **Strict** - 0.3 сообщений в секунду на чат (30% от лимита для максимальной стабильности) - Максимум 1 сообщение подряд - 5 повторных попыток при ошибках - Максимальная задержка 60 секунд - 10 глобальных запросов в секунду (консервативные настройки) ### Использование #### Автоматическое использование (рекомендуется) Rate limiting и валидация автоматически применяются ко всем сообщениям через middleware. Никаких изменений в коде не требуется. **ValidationMiddleware** автоматически валидирует: - Все callback queries - Все сообщения - Telegram ID пользователей - Username (если есть) - Chat ID #### Ручное использование ```python from services.rate_limiting.rate_limit_service import RateLimitService from dependencies import get_rate_limit_service # Получение сервиса через DI rate_limit_service = get_rate_limit_service() # Отправка сообщения с rate limiting result = await rate_limit_service.send_with_rate_limit( bot.send_message, chat_id=user_id, text="Привет!" ) ``` #### Прямое использование rate limiter ```python from services.rate_limiting.rate_limiter import send_with_rate_limit # Отправка с автоматическим rate limiting result = await send_with_rate_limit( bot.send_message, chat_id=user_id, text="Привет!" ) ``` #### Ручное использование валидатора ```python from services.validation import InputValidator from dependencies import get_validator # Получение валидатора через DI validator = get_validator() # Валидация текста вопроса result = validator.validate_question_text(text, max_length=1000) if not result: print(f"Ошибка: {result.error_message}") else: sanitized_text = result.sanitized_value # Валидация callback data result = validator.validate_callback_data(callback_data) if not result: await callback.answer("❌ Неверные данные", show_alert=True) return ``` ### Административные функции Доступ к управлению rate limiting осуществляется через админскую панель: 1. **Перейти в админку**: `/admin` 2. **Нажать кнопку "🚦 Rate Limiting"** 3. **Выбрать нужное действие**: - **📊 Статистика Rate Limiting** - показывает подробную статистику: - Общее количество запросов - Процент успеха/ошибок - Количество RetryAfter ошибок - Среднее время ожидания - **🔄 Сбросить статистику** - сбрасывает всю статистику rate limiting - **⚙️ Адаптировать конфигурацию** - адаптирует настройки на основе текущей производительности **Важно**: Доступ к функциям rate limiting имеют только администраторы бота (не суперпользователи). ### Мониторинг #### Логирование Система логирует: - Rate limiting события (DEBUG уровень) - RetryAfter ошибки (WARNING уровень) - Критические ошибки (ERROR уровень) #### Статистика RateLimitService отслеживает: - Общее количество запросов - Успешные/неудачные запросы - Типы ошибок (RetryAfter, API ошибки) - Время ожидания #### Адаптивная конфигурация Система автоматически адаптирует настройки: - При >10% ошибок: ужесточает ограничения - При <1% ошибок: ослабляет ограничения - Требует минимум 100 запросов для адаптации ### Интеграция с DI Rate limiting полностью интегрирован в систему инъекции зависимостей: ```python # В обработчиках async def some_handler( message: Message, rate_limit_service: RateLimitService ): # rate_limit_service автоматически инжектируется pass ``` ### Архитектурные особенности #### Соблюдение принципов 1. **Single Responsibility**: Каждый компонент отвечает за свою задачу 2. **Open/Closed**: Легко расширяется новыми типами ограничений 3. **Dependency Inversion**: Зависит от абстракций, а не от конкретных реализаций #### Производительность - Минимальные накладные расходы - Эффективное управление памятью - Асинхронная обработка #### Надежность - Обработка всех типов ошибок Telegram API - Экспоненциальная задержка при повторных попытках - Автоматическое восстановление после ошибок ### Устранение неполадок #### Высокий процент ошибок 1. Проверьте статистику: `/ratelimit_stats` 2. Адаптируйте конфигурацию: `/adapt_ratelimit` 3. При необходимости ужесточите настройки в `.env` #### Медленная отправка сообщений 1. Проверьте настройки `RATE_LIMIT_MESSAGES_PER_SECOND` 2. Увеличьте значение для более быстрой отправки 3. Убедитесь, что не превышаете лимиты Telegram API #### Проблемы с интеграцией 1. Убедитесь, что middleware зарегистрирован в `loader.py` 2. **Ошибка `TypeError: got an unexpected keyword argument 'dispatcher'`**: - **Причина**: aiogram 3.x передает `dispatcher` во все обработчики сообщений, но `@inject_all` не обрабатывает его правильно - **Решение**: Используйте специализированные декораторы вместо `@inject_all`: ```python # ❌ Неправильно @inject_all async def process_question(message: Message, dispatcher, ...): # ✅ Правильно @inject_question_services async def process_question(message: Message, question_service: QuestionService, ...): ``` - **Преимущества**: Нет проблем с `dispatcher`, меньше зависимостей, лучшая производительность 3. Проверьте, что все зависимости корректно импортированы 4. Проверьте логи на наличие ошибок инициализации ## 🔮 Планы развития - [x] **Система суперпользователей** - расширенные права для модерации с отображением информации об авторах - [x] **Система инъекции зависимостей** - современная архитектура с DI для лучшей тестируемости - [x] **Система разрешений** - гибкая система разрешений с соблюдением принципа OCP - [x] **Prometheus метрики** - мониторинг производительности и ошибок - [x] **Rate limiting** - защита от спама и DDoS с автоматической адаптацией - [x] **Реорганизация структуры проекта** - улучшенная архитектура с логической группировкой сервисов - [x] **Локальная нумерация вопросов** - каждый пользователь видит свои вопросы с номерами #1, #2, #3... вместо глобальных ID - [ ] **Unit-тесты** - полное покрытие тестами с использованием DI - [ ] **Кэширование Redis** - оптимизация производительности - [ ] Рассылка сообщений - [ ] Экспорт данных - [ ] Веб-интерфейс для админов - [ ] Поддержка медиафайлов в вопросах - [ ] Категории вопросов - [ ] Модерация контента - [ ] Аналитика и отчеты ## 📝 Changelog ### v1.7.0 - Продвинутая система логирования (2025-01-27) #### ✨ Новые возможности - **Автоматические декораторы логирования** - `@log_function_call`, `@log_business_event`, `@log_fsm_transition` - **Контекстное логирование** - `LoggingContext` с дополнительной информацией - **Оптимизированные декораторы** - `@log_middleware`, `@log_utility` для предотвращения избыточного логирования - **FSM отслеживание** - автоматическое логирование переходов между состояниями - **Специальные функции** - `log_question_created`, `log_user_created`, `log_user_blocked` - **Тихие декораторы** - предотвращение рекурсивного логирования в middleware #### 🔧 Улучшения - **100% покрытие логированием** - все функции теперь логируются автоматически - **Улучшенная производительность** - оптимизированное логирование для middleware - **Детальная диагностика** - полная трассировка выполнения функций - **Контекстная информация** - автоматическое извлечение user_id, question_id и других параметров #### 📁 Новые файлы - `services/infrastructure/logging_decorators.py` - декораторы для автоматического логирования - `services/infrastructure/logging_utils.py` - утилиты для контекстного логирования ### v1.6.0 - Локальная нумерация вопросов (2025-01-27) #### ✨ Новые возможности - **Локальная нумерация вопросов**: Каждый пользователь теперь видит свои вопросы с номерами #1, #2, #3... вместо глобальных ID - **Автоматическая нумерация**: Триггеры БД автоматически присваивают и пересчитывают номера вопросов - **Умная нумерация**: Удаленные вопросы не участвуют в нумерации, номера автоматически пересчитываются при удалении #### 🔧 Технические изменения - **Новое поле БД**: `user_question_number` в таблице `questions` - **Триггеры БД**: - `calculate_user_question_number` - автоматическое вычисление номера при создании - `recalculate_user_question_numbers_on_delete` - пересчет номеров при удалении - **Индексы**: Оптимизированные индексы для быстрого поиска по локальным номерам - **Модель Question**: Новый метод `get_display_number()` для получения номера для отображения #### 🐛 Исправления - **Отображение номеров**: Исправлена проблема с несоответствием номеров в тексте сообщений и на кнопках - **Пагинация**: Обновлена для работы с локальными номерами - **CRUD операции**: Обновлены для поддержки автоматической нумерации #### 📊 Улучшения UX - **Интуитивная нумерация**: Пользователи видят последовательные номера своих вопросов - **Консистентность**: Номера в тексте и на кнопках всегда совпадают - **Автоматизация**: Никаких ручных действий для поддержания нумерации