init commit
This commit is contained in:
373
docs/ARCHITECTURE.md
Normal file
373
docs/ARCHITECTURE.md
Normal file
@@ -0,0 +1,373 @@
|
||||
# Архитектура 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 │
|
||||
└───────────────┘
|
||||
```
|
||||
|
||||
Это архитектура позволяет:
|
||||
- ✅ Легко тестировать каждый слой
|
||||
- ✅ Менять БД без изменения логики
|
||||
- ✅ Расширять функциональность
|
||||
- ✅ Масштабировать приложение
|
||||
Reference in New Issue
Block a user