374 lines
15 KiB
Markdown
374 lines
15 KiB
Markdown
# Архитектура TG Autoposter
|
||
|
||
## Общая структура
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────┐
|
||
│ Telegram User (в личных сообщениях) │
|
||
└──────────────────────┬──────────────────────────────┘
|
||
│
|
||
↓
|
||
┌─────────────────────────────────────────────────────┐
|
||
│ Telegram Bot (python-telegram-bot) │
|
||
│ main.py → app/__init__.py │
|
||
└──────────────────┬──────────────────┬──────────────┘
|
||
│ │
|
||
┌──────────┘ └────────────┐
|
||
↓ ↓
|
||
┌─────────────┐ ┌──────────────┐
|
||
│ Handlers │ │ Callbacks │
|
||
│ (команды) │ │ (кнопки) │
|
||
└──────┬──────┘ └──────┬───────┘
|
||
│ │
|
||
└──────────────┬───────────────────────┘
|
||
↓
|
||
┌───────────────────────────────┐
|
||
│ Database Repository │
|
||
│ (repository.py) │
|
||
│ - GroupRepository │
|
||
│ - MessageRepository │
|
||
│ - MessageGroupRepository │
|
||
└──────────────┬────────────────┘
|
||
↓
|
||
┌───────────────────────────────┐
|
||
│ SQLAlchemy ORM │
|
||
│ (database/__init__.py) │
|
||
│ - AsyncSessionLocal │
|
||
│ - engine │
|
||
└──────────────┬────────────────┘
|
||
↓
|
||
┌───────────────────────────────┐
|
||
│ Database (SQLite/PgSQL) │
|
||
│ - groups │
|
||
│ - messages │
|
||
│ - message_groups │
|
||
└───────────────────────────────┘
|
||
```
|
||
|
||
## Слои приложения
|
||
|
||
### 1. **Presentation Layer** (Telegram Bot)
|
||
- Файлы: `handlers/`, `utils/keyboards.py`
|
||
- Отвечает за взаимодействие с пользователем
|
||
- Обработка команд и callback'ов
|
||
- Формирование инлайн кнопок
|
||
|
||
### 2. **Application Logic Layer** (Handlers)
|
||
- Файлы: `handlers/commands.py`, `handlers/callbacks.py`, `handlers/sender.py`, `handlers/message_manager.py`, `handlers/group_manager.py`
|
||
- Бизнес-логика отправки сообщений
|
||
- Учет slow mode
|
||
- Управление сообщениями и группами
|
||
|
||
### 3. **Repository Layer** (Data Access)
|
||
- Файл: `database/repository.py`
|
||
- CRUD операции для каждой сущности
|
||
- Абстракция работы с БД
|
||
- Защита от прямых SQL запросов
|
||
|
||
### 4. **ORM Layer** (Object-Relational Mapping)
|
||
- Файл: `database/__init__.py`
|
||
- SQLAlchemy для работы с БД
|
||
- Асинхронные сессии
|
||
- Управление подключением
|
||
|
||
### 5. **Data Layer** (Models & Database)
|
||
- Файлы: `models/`, база данных
|
||
- Определение структуры данных
|
||
- Связи между таблицами
|
||
- Физическое хранилище
|
||
|
||
## Модели данных
|
||
|
||
### Group (Группа)
|
||
```
|
||
┌──────────────────┐
|
||
│ Group │
|
||
├──────────────────┤
|
||
│ id (PK) │
|
||
│ chat_id (UNQ) │
|
||
│ title │
|
||
│ slow_mode_delay │
|
||
│ last_message_time│
|
||
│ is_active │
|
||
│ created_at │
|
||
│ updated_at │
|
||
└──────────────────┘
|
||
│
|
||
│ 1..N
|
||
│
|
||
└───────────────────┐
|
||
│
|
||
┌────────────────┐
|
||
│ MessageGroup │
|
||
│ (pivot table) │
|
||
└────────────────┘
|
||
│
|
||
│ 1..N
|
||
│
|
||
┌────────────────┐
|
||
│ Message │
|
||
│ (Сообщение) │
|
||
└────────────────┘
|
||
```
|
||
|
||
## Поток данных при отправке сообщения
|
||
|
||
```
|
||
1. Пользователь нажимает "📤 Отправить"
|
||
│
|
||
↓
|
||
2. send_message() получает callback
|
||
│
|
||
├─→ Получить сообщение из БД
|
||
│ (MessageRepository.get_message)
|
||
│
|
||
├─→ Получить все связи для отправки
|
||
│ (MessageGroupRepository.get_message_groups_to_send)
|
||
│
|
||
↓
|
||
3. Для каждой группы:
|
||
│
|
||
├─→ Проверить slow mode
|
||
│ (can_send_message() из utils)
|
||
│
|
||
├─→ Если нужно, ждать
|
||
│ (asyncio.sleep)
|
||
│
|
||
├─→ Отправить сообщение через Bot API
|
||
│ (context.bot.send_message)
|
||
│
|
||
├─→ Обновить время последнего сообщения
|
||
│ (GroupRepository.update_last_message_time)
|
||
│
|
||
├─→ Отметить как отправленное
|
||
│ (MessageGroupRepository.mark_as_sent)
|
||
│
|
||
└─→ Обновить статус в UI
|
||
(query.edit_message_text)
|
||
|
||
4. Показать итоговое сообщение пользователю
|
||
```
|
||
|
||
## Поток данных при добавлении бота в группу
|
||
|
||
```
|
||
1. Бот добавлен в группу
|
||
│
|
||
↓
|
||
2. Telegram отправляет my_chat_member update
|
||
│
|
||
↓
|
||
3. my_chat_member() обработчик получает событие
|
||
│
|
||
├─→ Проверить статус: member или left
|
||
│
|
||
├─→ Если member:
|
||
│ │
|
||
│ ├─→ Получить информацию о группе
|
||
│ │ (context.bot.get_chat)
|
||
│ │
|
||
│ ├─→ Получить slow mode
|
||
│ │
|
||
│ ├─→ Проверить есть ли уже в БД
|
||
│ │ (GroupRepository.get_group_by_chat_id)
|
||
│ │
|
||
│ └─→ Добавить или обновить
|
||
│ (GroupRepository.add_group)
|
||
│
|
||
└─→ Если left:
|
||
│
|
||
└─→ Деактивировать в БД
|
||
(GroupRepository.deactivate_group)
|
||
```
|
||
|
||
## Асинхронность
|
||
|
||
Весь код использует async/await:
|
||
|
||
```python
|
||
async def main():
|
||
# Инициализация
|
||
await init_db()
|
||
|
||
# Создание приложения
|
||
application = Application.builder().token(TOKEN).build()
|
||
|
||
# Добавление обработчиков
|
||
application.add_handler(...)
|
||
|
||
# Polling (слушаем обновления)
|
||
await application.run_polling()
|
||
```
|
||
|
||
## Обработка ошибок
|
||
|
||
```
|
||
┌─────────────────────────────────────┐
|
||
│ Попытка отправки сообщения │
|
||
└────────────┬────────────────────────┘
|
||
│
|
||
┌──────┴──────┐
|
||
│ │
|
||
↓ ↓
|
||
SUCCESS EXCEPTION
|
||
│ │
|
||
├─→ mark_as_sent() ├─→ Сохранить ошибку
|
||
│ (is_sent=True) mark_as_sent(error=str(e))
|
||
│ (is_sent=False)
|
||
└─────────┬──────────┬──────────┘
|
||
│ │
|
||
└─────────┘
|
||
│
|
||
↓
|
||
Показать статус
|
||
пользователю
|
||
```
|
||
|
||
## Состояния ConversationHandler
|
||
|
||
При создании сообщения:
|
||
|
||
```
|
||
START
|
||
│
|
||
└─→ CREATE_MSG_TITLE
|
||
(ввод названия)
|
||
│
|
||
└─→ CREATE_MSG_TEXT
|
||
(ввод текста, создание в БД)
|
||
│
|
||
└─→ SELECT_GROUPS
|
||
(выбор групп с кнопками)
|
||
│
|
||
└─→ DONE или CANCEL
|
||
(завершение)
|
||
```
|
||
|
||
## Безопасность данных
|
||
|
||
### Уровни защиты:
|
||
|
||
1. **Переменные окружения** (.env)
|
||
- Токен бота не в коде
|
||
- DATABASE_URL скрыт
|
||
|
||
2. **Асинхронные сессии**
|
||
- Каждая операция в собственной транзакции
|
||
- Автоматический rollback при ошибке
|
||
|
||
3. **SQL Injection**
|
||
- SQLAlchemy использует parameterized queries
|
||
- Защита встроена в ORM
|
||
|
||
4. **Логирование**
|
||
- Чувствительные данные не логируются
|
||
- Ошибки записываются в файл с ротацией
|
||
|
||
## Масштабируемость
|
||
|
||
### Текущие возможности:
|
||
|
||
- ✅ Линейная масштабируемость с количеством групп
|
||
- ✅ Асинхронная обработка не блокирует бота
|
||
- ✅ БД может быть PostgreSQL для производства
|
||
- ✅ Логирование с ротацией
|
||
|
||
### Возможные улучшения:
|
||
|
||
- [ ] Queue (Celery) для больших рассылок
|
||
- [ ] Cache (Redis) для часто используемых данных
|
||
- [ ] Webhook вместо polling для масштабирования
|
||
- [ ] Connection pooling для БД
|
||
|
||
## Производительность
|
||
|
||
### Оптимизации:
|
||
|
||
1. **Асинхронность**
|
||
- Не блокирует при I/O операциях
|
||
- Может обрабатывать много групп параллельно
|
||
|
||
2. **Batch операции**
|
||
- Отправка в несколько групп одновременно
|
||
- Кэширование результатов
|
||
|
||
3. **Индексы в БД**
|
||
- `chat_id` в таблице Groups (UNIQUE)
|
||
- Foreign keys оптимизированы
|
||
|
||
## Тестирование
|
||
|
||
### Структура для тестирования:
|
||
|
||
```
|
||
tests/
|
||
├── test_models.py # Модели
|
||
├── test_repository.py # Репозитории
|
||
├── test_handlers.py # Обработчики
|
||
└── test_integration.py # Интеграция
|
||
```
|
||
|
||
## Развертывание
|
||
|
||
### Production deployment:
|
||
|
||
```
|
||
1. Клонировать репо
|
||
2. pip install -r requirements.txt
|
||
3. Настроить .env с реальным токеном
|
||
4. Использовать PostgreSQL вместо SQLite
|
||
5. Запустить с systemd/supervisor
|
||
6. Настроить ротацию логов
|
||
7. Мониторинг и алерты
|
||
```
|
||
|
||
## Взаимодействие компонентов
|
||
|
||
```
|
||
┌────────────────────────────────────────────────────────────┐
|
||
│ Telegram Bot (main.py) │
|
||
├────────────────────────────────────────────────────────────┤
|
||
│ Application (python-telegram-bot) │
|
||
│ ├─ CommandHandler (/start, /help) │
|
||
│ ├─ CallbackQueryHandler (callback buttons) │
|
||
│ ├─ ChatMemberHandler (my_chat_member events) │
|
||
│ └─ ConversationHandler (multi-step flows) │
|
||
└────────────────────────────────────────────────────────────┘
|
||
↓ ↓ ↓ ↓
|
||
┌─────────┐ ┌────────────┐ ┌──────────┐ ┌─────────────┐
|
||
│ commands │ │ callbacks │ │ sender │ │group_manager│
|
||
│ .py │ │ .py │ │ .py │ │ .py │
|
||
└────┬─────┘ └──────┬─────┘ └────┬─────┘ └──────┬──────┘
|
||
│ │ │ │
|
||
└────────────────┼─────────────┼───────────────┘
|
||
│
|
||
┌────▼────┐
|
||
│ message_ │
|
||
│manager.py│
|
||
└────┬─────┘
|
||
│
|
||
┌──────────┴──────────┐
|
||
│ │
|
||
┌────▼────────┐ ┌────▼────────┐
|
||
│ Repository │ │ Utils │
|
||
│ Layer │ │ - keyboards│
|
||
│ │ │ - slow_mode│
|
||
└────┬────────┘ └─────────────┘
|
||
│
|
||
┌────▼─────────┐
|
||
│ SQLAlchemy │
|
||
│ ORM │
|
||
└────┬─────────┘
|
||
│
|
||
┌────▼──────────┐
|
||
│ SQLite/PgSQL │
|
||
│ Database │
|
||
└───────────────┘
|
||
```
|
||
|
||
Это архитектура позволяет:
|
||
- ✅ Легко тестировать каждый слой
|
||
- ✅ Менять БД без изменения логики
|
||
- ✅ Расширять функциональность
|
||
- ✅ Масштабировать приложение
|