Создание ботов в Telegram

Курс знакомит с полным циклом разработки Telegram-ботов: от регистрации и проектирования логики до реализации, хранения данных и развертывания. Вы научитесь создавать ботов на практике, подключать внешние сервисы и обеспечивать надежную работу и безопасность.

1. Основы Telegram Bot API и подготовка окружения

Основы Telegram Bot API и подготовка окружения

Telegram-бот — это программа, которая общается с пользователями через Telegram и выполняет команды: отвечает текстом, отправляет файлы, показывает кнопки, принимает платежи и многое другое. В этой статье вы разберётесь, как устроен Telegram Bot API, чем отличаются способы получения сообщений, как создать бота через BotFather и подготовить рабочее окружение для разработки.

Что такое Telegram Bot API

Telegram Bot API — это HTTP-интерфейс, через который ваша программа (бот) взаимодействует с серверами Telegram.

Ключевая идея простая:

  • Telegram принимает сообщения от пользователей
  • Telegram формирует обновления (updates) и передаёт их вашему боту
  • ваш бот обрабатывает обновления и отправляет ответы обратно через методы Bot API
  • Официальная документация:

  • Telegram Bot API
  • Создание бота через BotFather
  • Как устроено взаимодействие: Telegram, бот и Bot API

    Ваш бот обычно запускается на вашем компьютере или сервере и обращается к Bot API по HTTPS.

    !Схема показывает путь сообщения от пользователя к боту и обратно

    В обмене данными часто встречаются два понятия:

  • Метод — действие, которое ваш бот просит выполнить (например, sendMessage).
  • Обновление (Update) — событие от Telegram к вашему боту (например, пришло сообщение).
  • Базовые сущности Bot API

    Ниже — минимальный набор сущностей, которые вы будете видеть постоянно.

    | Сущность | Что это | Пример из жизни | |---|---|---| | Bot | ваша программа + учётная запись бота в Telegram | бот поддержки, бот-напоминалка | | Update | объект события от Telegram | пришло сообщение, нажали кнопку | | Message | конкретное сообщение | текст, фото, документ | | Chat | место общения | личный чат, группа, канал | | User | пользователь Telegram | человек, который написал боту |

    Важно: бот не читает сообщения везде автоматически. Он получает только те обновления, которые Telegram отправляет боту в рамках разрешённых сценариев (например, личный чат с ботом, упоминания и события в группах при нужных настройках).

    Как бот получает сообщения: long polling и webhook

    Есть два основных способа получать обновления.

    | Способ | Как работает | Когда удобно | |---|---|---| | Long polling (getUpdates) | бот сам регулярно запрашивает у Telegram новые обновления | обучение, локальная разработка, простые проекты | | Webhook (setWebhook) | Telegram сам отправляет обновления на ваш HTTPS-адрес | продакшен, высокие нагрузки, стабильный сервер |

    Ссылки на методы в документации:

  • getUpdates
  • setWebhook
  • Практическое правило на старте:

  • начинайте с long polling (проще запустить локально)
  • переходите на webhook, когда нужен сервер и стабильная доставка
  • Создание бота через BotFather и получение токена

    Чтобы бот существовал в Telegram, его нужно зарегистрировать.

  • Откройте в Telegram пользователя BotFather.
  • Отправьте команду /newbot .
  • Задайте:
  • - отображаемое имя бота - username бота (должен оканчиваться на bot, например my_course_helper_bot)
  • BotFather выдаст токен вида 123456:ABC-DEF....
  • Токен — это ключ доступа к вашему боту.

  • не публикуйте токен в чатах
  • не коммитьте токен в Git
  • при утечке сразу перевыпустите токен через BotFather (/token)
  • Подготовка окружения разработки

    Ниже — универсальная база, которая подойдёт для большинства учебных и реальных проектов.

    Выбор языка и библиотеки

    Вы можете работать напрямую через HTTP-запросы, но удобнее использовать библиотеку-обёртку.

    | Язык | Популярная библиотека | Когда выбирать | |---|---|---| | Python | python-telegram-bot | быстрый старт, много примеров | | Node.js | Telegraf | если вы пишете на JavaScript/TypeScript |

    В курсе критично понимать сам Bot API, а библиотека — это удобный инструмент, который берёт на себя часть рутины (парсинг обновлений, роутинг хендлеров и т.д.).

    Установка Python и создание виртуального окружения

  • Установите Python 3.11+ (или актуальную стабильную версию):
  • - Загрузка Python
  • Проверьте версии:
  • Создайте папку проекта и виртуальное окружение:
  • Активируйте окружение:
  • Установите библиотеку (пример для Python):
  • Установка Node.js (если выбираете JavaScript)

  • Установите Node.js LTS:
  • - Загрузка Node.js
  • Инициализируйте проект и установите Telegraf:
  • Где хранить токен бота

    Правильный подход — хранить токен во внешней конфигурации, а не в коде.

    Минимальные варианты:

  • переменная окружения (например, TELEGRAM_BOT_TOKEN)
  • локальный файл конфигурации, который добавлен в .gitignore
  • Даже в учебном проекте привыкайте к этому с первого дня: утечки токенов — одна из самых частых проблем.

    Быстрая проверка токена: первый запрос к Bot API

    Проверим, что токен рабочий, без написания кода.

  • Выполните запрос getMe — он возвращает информацию о боте.
  • Если всё хорошо, вы увидите JSON с полем ok: true и данными бота.
  • Полезно знать:

  • адрес API всегда начинается с https://api.telegram.org/bot...
  • <ВАШ_ТОКЕН> нужно подставить полностью
  • Long polling на практике: что такое offset

    При long polling вы вызываете getUpdates, а Telegram отдаёт список событий. Чтобы не получать одни и те же события повторно, используется параметр offset.

    Идея такая:

  • у каждого Update есть целочисленный update_id
  • после обработки вы запоминаете последний update_id
  • в следующий раз запрашиваете offset = last_update_id + 1
  • Так бот последовательно «читает» очередь обновлений.

    Инструменты разработчика, которые стоит поставить

    Минимальный набор:

  • Git — контроль версий
  • терминал (Windows Terminal / iTerm / любой удобный)
  • редактор кода (например, VS Code)
  • Если вы будете тестировать webhook локально, пригодится туннель:

  • ngrok — даёт временный публичный HTTPS-адрес для вашего локального сервера
  • Типичные ошибки на старте

  • Токен вставлен с лишними пробелами или обрезан.
  • Токен попал в репозиторий и его успели использовать злоумышленники.
  • Запущены одновременно webhook и long polling для одного и того же бота (это мешает получать обновления корректно).
  • Бот добавлен в группу, но «молчит» из-за настроек приватности и отсутствия нужных прав.
  • Что дальше по курсу

    Дальше вы соберёте первого рабочего бота: научитесь принимать обновления, отвечать на сообщения, подключать команды и добавлять базовую структуру проекта. На этом фундаменте затем появятся кнопки, состояния диалога, хранение данных и развёртывание.

    2. Проектирование сценариев: команды, меню, состояния и UX

    Проектирование сценариев: команды, меню, состояния и UX

    После предыдущей статьи у вас уже есть бот, токен и понимание, как Telegram доставляет события через Bot API. Следующий шаг — спроектировать поведение бота: какие у него есть команды, как устроено меню, как бот ведёт диалог шаг за шагом, и что делает интерфейс удобным.

    Что такое сценарий бота и зачем его проектировать

    Сценарий — это описание пути пользователя: от точки входа (например, /start) до результата (например, «получил справку», «оформил заказ», «создал напоминание»).

    Проектирование сценариев нужно, чтобы:

  • не превращать бота в набор разрозненных ответов
  • заранее продумать, где и какие данные спрашивать
  • избежать тупиков (пользователь не понимает, что делать дальше)
  • одинаково обрабатывать “хорошие” и “плохие” случаи (ошибки, отмена, повтор)
  • Команды и точки входа

    Базовый набор команд

    Команда — это сообщение, начинающееся с /, которое Telegram распознаёт как команду (например, /start). Команды удобно использовать как публичные якоря сценариев.

    Чаще всего в боте есть:

  • /start — первая точка входа и возврат “домой”
  • /help — как пользоваться ботом
  • /settings — настройки (если нужны)
  • /cancel — отмена текущего шага/диалога
  • В Telegram можно официально задать список команд, чтобы они отображались в интерфейсе. Делается через метод Bot API setMyCommands: setMyCommands.

    /start как главный маршрут

    /start обычно выполняет две задачи:

  • Объясняет, что умеет бот (очень кратко)
  • Показывает главное меню (кнопки или список возможных действий)
  • Отдельно полезная возможность — deep linking: когда бот получает /start с параметром и понимает, куда вести пользователя (например, сразу открыть конкретный заказ или приглашение). Документация: Deep Linking.

    Принцип “команда — это маршрут”

    Хорошая практика: считать команды входами в сценарии, а не “функциями”. Например:

  • /start ведёт в состояние главное меню
  • /help ведёт в состояние справка
  • /cancel возвращает в главное меню, сбросив текущий диалог
  • Так вы получаете понятную навигацию, похожую на структуру сайта.

    Меню в Telegram: Reply-клавиатура и Inline-клавиатура

    В Telegram есть два популярных типа кнопок.

    | Тип | Где отображается | Что отправляется боту | Когда использовать | |---|---|---|---| | Reply Keyboard (клавиатура под строкой ввода) | Вместо стандартной клавиатуры | Обычное сообщение (текст) | Когда пользователь часто выбирает из фиксированных вариантов и вы готовы принимать текст | | Inline Keyboard (кнопки под конкретным сообщением) | Под сообщением бота | callback_query (нажатие кнопки) или открытие URL | Когда важно, чтобы нажатия были точными, без “свободного текста”, и удобно обновлять интерфейс |

    Inline-кнопки описаны в Bot API через InlineKeyboardMarkup и события callback_query: InlineKeyboardMarkup, CallbackQuery.

    Почему для “меню” часто выбирают Inline

    Inline-кнопки хороши для UX, потому что:

  • пользователь не “засоряет” чат служебными сообщениями (нажатие не обязательно создаёт отдельное текстовое сообщение)
  • вы получаете строго заданное значение (callback_data), а не произвольный текст
  • можно делать “экранное” меню, редактируя текущее сообщение вместо отправки нового (метод editMessageText: editMessageText)
  • Пример структуры inline-меню

    Ниже — пример того, как обычно кодируют callback_data для кнопок, чтобы удобно роутить нажатия:

    Важно: callback_data имеет ограничение по длине, поэтому туда обычно кладут компактный идентификатор действия, а детали (например, id) кодируют коротко или хранят на сервере.

    Состояния: как делать диалоги “по шагам”

    Состояние — это текущий шаг сценария для конкретного пользователя (или чата). Например, бот может быть в состоянии:

  • ожидаю название
  • ожидаю дату
  • ожидаю подтверждение
  • Зачем вообще нужны состояния

    Без состояний бот часто превращается в “угадайку”: пользователь пишет текст, а бот пытается понять, что имели в виду. Состояния позволяют сделать диалог точным:

  • Бот задаёт конкретный вопрос
  • Бот ожидает конкретный тип ответа
  • Бот валидирует и переводит пользователя дальше
  • Модель “конечный автомат” (FSM) на практике

    Вы можете мыслить диалог как набор переходов:

  • состояние A + событие X → состояние B
  • состояние B + событие Y → состояние C
  • !Диаграмма показывает, как пользователь переходит по шагам диалога и где находится отмена

    Где хранить состояние

    Есть три типичных варианта (по мере роста проекта):

  • в памяти процесса (быстро, но пропадёт при перезапуске)
  • в файле/простой базе данных (подходит для учебных проектов)
  • во внешней базе (подходит для продакшена)
  • Правило для UX: если потеря состояния приводит к раздражению (например, пользователь заполнял форму), лучше хранить состояние так, чтобы оно переживало перезапуск.

    “Глобальные” действия: помощь и отмена

    Чтобы диалоги не превращались в ловушку, почти всегда стоит поддерживать:

  • /cancel — сброс состояния и возврат в меню
  • кнопку “Назад” (если сценарий сложный)
  • “Помощь” как доступную опцию в любом месте
  • UX для Telegram-бота: практические принципы

    UX в боте — это не “красота”, а предсказуемость и скорость.

  • Дайте пользователю следующий шаг в каждом ответе
  • Не перегружайте текстом
  • Показывайте варианты кнопками, когда это возможно
  • Подтверждайте действия, которые меняют данные
  • Делайте ошибки “исправимыми”
  • Поддерживайте повторяемость и единый стиль
  • Не спамьте сообщениями, используйте редактирование там, где уместно
  • Микрокопирайтинг: как писать сообщения

    Хорошие сообщения бота обычно:

  • короткие
  • конкретные
  • содержат пример формата ввода
  • Пример:

  • Плохо: “Введите дату”
  • Лучше: “Введите дату в формате ДД.ММ.ГГГГ, например 07.02.2026
  • Ошибки и валидация

    Если пользователь ввёл неверное значение, полезно:

  • Сказать, что именно не так
  • Показать пример
  • Не сбрасывать весь прогресс, если можно исправить только один шаг
  • Идемпотентность и “повторы”

    Иногда Telegram или сеть приводят к повторной доставке события, или пользователь нажмёт кнопку несколько раз. UX-следствие: пользователь может получить двойной результат.

    Практика:

  • на “опасных” шагах (оплата, создание заказа, отправка заявки) делайте подтверждение
  • по возможности используйте уникальные идентификаторы операций на сервере
  • после успешного действия отключайте/обновляйте кнопки (например, редактированием сообщения)
  • Негативные сценарии, которые нужно предусмотреть

    Минимальный список случаев, которые стоит заложить в проект до написания кода:

  • Пользователь пишет не по сценарию (в состоянии “ожидаю дату” присылает фото)
  • Пользователь не отвечает долго и возвращается позже
  • Пользователь присылает /start в середине диалога
  • Пользователь в группе, а бот не может отвечать так же, как в личке
  • Пользователь нажал кнопку, но сообщение уже устарело
  • Решения обычно простые:

  • fallback-ответ: “Я сейчас жду дату. Введите дату или нажмите Отмена.”
  • таймауты (опционально) и мягкий возврат в меню
  • /start всегда безопасно возвращает в меню
  • Артефакт, который экономит время: таблица сценария

    Перед кодом сделайте маленькую таблицу на 1–2 экрана. Этого часто достаточно, чтобы не запутаться.

    | Шаг | Триггер (что сделал пользователь) | Состояние до | Ответ бота | Кнопки/варианты | Состояние после | |---|---|---|---|---|---| | 1 | /start | любое | приветствие + краткие возможности | “Создать”, “Список”, “Помощь” | меню | | 2 | нажал “Создать” | меню | “Введите название” | “Отмена” | ввод_названия | | 3 | отправил текст | ввод_названия | “Введите дату…” | “Отмена” | ввод_даты | | 4 | отправил дату | ввод_даты | “Подтвердить?” | “Да”, “Нет” | подтверждение |

    Такая таблица напрямую превращается в набор хендлеров и проверок.

    Что дальше

    В следующих материалах вы начнёте реализовывать эти идеи в коде: подключите обработчики команд и сообщений, соберёте главное меню на кнопках и сделаете первый диалог со состояниями. Фундамент из этой статьи поможет вам не “лепить ответы”, а строить бота как продукт.

    3. Реализация бота: обработчики, клавиатуры, инлайн-режим и медиа

    Реализация бота: обработчики, клавиатуры, инлайн-режим и медиа

    В предыдущих статьях вы разобрались, как Telegram доставляет обновления (long polling и webhook), как проектировать сценарии с командами, меню и состояниями, и почему UX в боте важнее “красивого текста”. Теперь соберём это в код: настроим обработчики событий, сделаем меню на кнопках, добавим инлайн-режим и научимся отправлять и принимать медиа.

    В примерах ниже используется Python и библиотека python-telegram-bot версии 20+ (она популярна и хорошо документирована). Документация библиотеки: python-telegram-bot. Официальная спецификация методов: Telegram Bot API.

    !Схема показывает, как разные типы событий попадают в разные обработчики и приводят к разным действиям бота

    Базовый каркас проекта

    Минимально полезная структура учебного проекта:

  • bot.py или main.py — точка входа
  • handlers/ — обработчики команд, сообщений, кнопок
  • services/ — логика предметной области (не завязанная на Telegram)
  • .env или переменные окружения — токен и настройки
  • Важно: токен храните вне кода (например, в переменной окружения). Это продолжение практики из первой статьи.

    Запуск бота на long polling (python-telegram-bot)

    Ниже — рабочий скелет, который запускает бота, подключает несколько обработчиков и логирование.

    Ключевые идеи:

  • Обработчик связывает тип события с функцией.
  • CommandHandler("start", ...) ловит /start.
  • MessageHandler(filters.TEXT & ~filters.COMMAND, ...) ловит текст, исключая команды.
  • allowed_updates=Update.ALL_TYPES удобно в учебных целях, чтобы не “потерять” события.
  • Обработчики: что на что подписывать

    В Bot API почти всё приходит как Update, а внутри него есть “ветки”: сообщение, нажатие кнопки, инлайн-запрос. В коде вы выбираете обработчик под нужную ветку.

    Таблица самых востребованных обработчиков в python-telegram-bot:

    | Что сделал пользователь | Что приходит от Telegram | Как обычно обрабатывают | |---|---|---| | Написал /start | message с текстом /start | CommandHandler("start", ...) | | Написал текст | message | MessageHandler(filters.TEXT, ...) | | Отправил фото/файл | message.photo, message.document | MessageHandler(filters.PHOTO/filters.Document.ALL, ...) | | Нажал inline-кнопку | callback_query | CallbackQueryHandler(...) | | Пишет боту в инлайн-режиме | inline_query | InlineQueryHandler(...) |

    Документация по типам объектов: Update.

    Порядок обработчиков и “кто первый поймал”

    Если несколько обработчиков подходят под одно событие, обычно срабатывает наиболее ранний по приоритету (в зависимости от групп обработчиков и настроек). Практическое правило:

  • сначала ставьте точные обработчики (команды, callback-кнопки)
  • затем общие (эхо, fallback)
  • Это особенно важно, когда вы добавляете меню и состояния: вы не хотите, чтобы “эхо” перехватывало сообщения, которые должны идти в шаг диалога.

    Контекст и данные пользователя

    В обработчиках у вас есть:

  • update — конкретное событие
  • context — объект с доступом к боту и хранилищам данных
  • Типичные места для данных:

  • context.user_data — данные конкретного пользователя (удобно для “состояний”)
  • context.chat_data — данные чата
  • context.bot_data — общие данные на весь процесс
  • Это не замена базе данных, но хороший старт для учебных сценариев и простых FSM.

    Клавиатуры: Reply и Inline в реальном UX

    В предыдущей статье вы сравнивали два типа меню. Теперь посмотрим, как их реализовать.

    Reply-клавиатура

    Reply-кнопка отправляет боту обычный текст. Её плюс — простота, минус — текст легко “сломать” (пользователь может написать другое).

    Практика для UX:

  • делайте кнопки короткими
  • добавляйте кнопку “Отмена” в сценариях ввода
  • Inline-клавиатура

    Inline-кнопка не обязана порождать новое текстовое сообщение. Чаще всего она присылает событие callback_query с callback_data.

    Обработка нажатий:

    Что здесь важно:

  • await query.answer() должен вызываться почти всегда, иначе Telegram будет показывать “ожидание” после клика.
  • edit_message_text помогает делать “экранное меню” без спама сообщениями. Метод в Bot API: editMessageText.
  • callback_data лучше кодировать как компактный маршрут, например section:action.
  • Подключение обработчика:

    Мини-FSM на практике: состояние через context.user_data

    Чтобы связать UI и сценарий, достаточно простейшего состояния.

    Пример: после нажатия “Создать” мы ждём название.

    Этот подход:

  • подходит для учебных проектов
  • хорошо иллюстрирует модель из предыдущей статьи (шаги и переходы)
  • Ограничения:

  • при перезапуске процесса состояние пропадёт
  • для продакшена обычно нужен внешний storage
  • Инлайн-режим: как бот работает “внутри других чатов”

    Инлайн-режим позволяет пользователю писать @вашбот ... в любом чате и получать от бота список вариантов для вставки.

    Как включить:

  • откройте BotFather
  • включите inline mode для бота (/setinline)
  • Документация Telegram по инлайн-режиму: Inline mode.

    Обработчик inline_query

    В инлайн-режиме бот не “отвечает сообщением в чат” напрямую. Он возвращает список результатов, из которых пользователь выбирает.

    Подключение:

    Практика:

  • cache_time=0 удобно при разработке, чтобы ответы не кэшировались
  • в реальном боте кэширование снижает нагрузку
  • Медиа: отправка, повторное использование file_id, группы медиа

    Боты редко ограничиваются текстом. Telegram даёт удобные методы отправки фото, документов, видео и альбомов.

    Отправка фото и документа

    Методы Bot API:

  • sendPhoto
  • sendDocument
  • Пример отправки по URL (Telegram сам скачает файл):

    Пример отправки локального файла:

    Что такое file_id и почему это важно

    Когда пользователь отправляет боту файл (фото, документ), Telegram даёт вам file_id. Это идентификатор, по которому вы можете отправлять тот же файл повторно без повторной загрузки.

    Это даёт:

  • экономию времени
  • меньше трафика
  • быстрее ответы
  • Пример: сохранить file_id последнего фото пользователя.

    Альбомы (media group)

    Если нужно отправить несколько изображений одним блоком, используйте sendMediaGroup. Метод Bot API: sendMediaGroup.

    В python-telegram-bot это делается через список InputMediaPhoto или InputMediaVideo.

    Практика:

  • у альбомов есть ограничения по типам и количеству элементов
  • подпись обычно имеет смысл ставить только на первый элемент, чтобы не перегружать интерфейс
  • Приём документов и скачивание

    Если пользователь прислал документ, у вас будет file_id. Чтобы скачать файл на сервер, получите File и вызовите скачивание.

    Сущность File в API: File.

    Пример для python-telegram-bot:

    Важная практика безопасности:

  • не доверяйте имени файла
  • сохраняйте в выделенную папку
  • валидируйте тип и размер
  • Сборка “всё вместе”: небольшой бот с меню, кнопками, инлайн и медиа

    Ниже — пример точки входа, которая объединяет всё из статьи. Это не “идеальная архитектура”, а компактный учебный шаблон.

    Обратите внимание: в блоке menu:album показан каркас (куда вставлять отправку медиа). Для реальной отправки альбома добавьте InputMediaPhoto как в примере выше.

    Типичные ошибки при реализации

  • Не вызвали answerCallbackQuery, и у пользователя “крутится загрузка” после клика.
  • Слишком общий MessageHandler стоит раньше и перехватывает сообщения, которые должны идти в сценарий.
  • В callback_data пытаются хранить слишком много данных и упираются в лимиты.
  • Не используют file_id и каждый раз загружают один и тот же файл заново.
  • Спамят сообщениями вместо editMessageText там, где нужен “экран”.
  • Что дальше по курсу

    Теперь у вас есть инструменты, чтобы реализовывать сценарии из проектирования: команды как точки входа, меню на кнопках, пошаговые диалоги и отправка медиа. Следующий логичный шаг — усложнить диалоги (в том числе с возвратом назад и отменой), вынести бизнес-логику из обработчиков и добавить устойчивое хранение данных, чтобы состояния переживали перезапуск.

    4. Данные и интеграции: базы данных, платежи, вебхуки и API

    Данные и интеграции: базы данных, платежи, вебхуки и API

    В прошлых статьях вы научились принимать обновления, строить сценарии, делать меню на кнопках, диалоги со состояниями, инлайн-режим и работу с медиа. Теперь следующий практический уровень: сделать так, чтобы бот помнил данные, интегрировался с внешними сервисами и мог работать в продакшене через вебхуки и платежи.

    Эта статья отвечает на четыре вопроса:

  • где и как хранить данные бота
  • как безопасно ходить во внешние API
  • чем webhook отличается от long polling и как его использовать
  • как устроены платежи в Telegram и какие события нужно обработать
  • !Общая схема, как бот получает события и взаимодействует с базой, внешними API и платежами

    Данные: что именно хранит бот

    Даже у простого бота быстро появляются данные, которые нельзя держать только в context.user_data, потому что они потеряются при перезапуске.

    Типичные категории данных:

  • Пользователи: telegram_user_id, имя, язык, согласия.
  • Состояния диалога: текущий шаг сценария и черновики ввода.
  • Сущности предметной области: заявки, заметки, заказы, подписки.
  • Логи и аудиты: когда и что сделал пользователь.
  • Идемпотентность: какие события уже обработаны, чтобы не создать дубль.
  • Ключевое правило проектирования: храните отдельно временное состояние диалога и результат (например, «созданный заказ»). Состояние может быть очищено, а результат должен сохраняться.

    Выбор хранилища: SQLite, PostgreSQL, Redis

    В Telegram-ботах чаще всего встречаются три класса хранилищ.

    | Хранилище | Плюсы | Минусы | Когда брать | |---|---|---|---| | SQLite | просто, один файл, удобно для обучения | сложнее параллельность, не для высокой нагрузки | учебные проекты, один сервер | | PostgreSQL | надёжно, транзакции, масштабирование | нужен сервер БД | продакшен, несколько инстансов | | Redis | очень быстро, удобно для TTL и сессий | не заменяет реляционную БД для сложных данных | кеш, краткоживущие состояния |

    Практическая стратегия:

  • для курса и первых проектов начните с SQLite
  • для реальных продуктов чаще всего приходят к PostgreSQL
  • для состояний и кеша поверх БД часто добавляют Redis
  • Документация по SQLite в Python: sqlite3 — DB-API 2.0 interface for SQLite databases

    Минимальная схема данных для бота

    Чтобы не «утонуть» в моделях, полезно держать минимум таблиц.

    Пример для бота, который создаёт заявки:

    | Таблица | Что хранит | Пример полей | |---|---|---| | users | информация о пользователе | telegram_id, created_at | | requests | заявки/заказы | id, telegram_id, title, status, created_at | | processed_updates | защита от дублей | update_id, processed_at |

    Поле processed_updates.update_id связано с тем, что каждое событие Telegram приходит как Update и имеет update_id (см. описание объекта в документации: Update).

    Пример: сохранение заявки в SQLite

    Ниже упрощённый пример, который показывает принцип: отдельные функции для базы и отдельные обработчики для Telegram.

    Что важно в этом подходе:

  • вы не смешиваете SQL и Telegram-логику в одной функции
  • вы явно делаете commit(), чтобы запись гарантированно сохранилась
  • вы возвращаете id, чтобы дальше связывать действия пользователя с конкретной сущностью
  • Если используете асинхронный стек, для SQLite часто применяют отдельные библиотеки (например, aiosqlite), а для PostgreSQL — асинхронные драйверы и ORM. На уровне курса важно понять принцип: внешнее хранилище живёт отдельно от обработчиков Telegram.

    Идемпотентность: защита от дублей

    В реальности одно и то же действие может быть обработано дважды:

  • пользователь нажал кнопку несколько раз
  • сеть дала повтор
  • вы перезапустили бота посередине обработки
  • Идемпотентность означает: повторный вызов не должен создавать новый результат.

    Практика для ботов:

  • для опасных операций (создание заказа, списание, выдача доступа) используйте ключ операции
  • сохраняйте ключ в БД и проверяйте перед созданием новой записи
  • для webhook-режима дополнительно удобно сохранять update_id как «уже обработанный»
  • Интеграции с внешними API: как ходить в интернет правильно

    Боты часто интегрируются с внешними сервисами:

  • CRM
  • курсы валют, погода, расписания
  • ваша собственная админка или микросервис
  • Базовые правила интеграций

  • используйте таймауты, чтобы бот не зависал
  • обрабатывайте ошибки сети и коды ответа
  • кешируйте часто повторяющиеся запросы
  • не доверяйте данным извне без валидации
  • Пример HTTP-запроса с таймаутом

    В Python для асинхронных запросов часто используют aiohttp: aiohttp Documentation.

    Смысл total=5 простой: если внешний сервис «лежит», бот должен быстро вернуть пользователю понятный ответ, а не молчать.

    Что отвечать пользователю при сбое API

    Плохой UX — показывать пользователю техническую ошибку целиком.

    Хороший UX:

  • коротко объяснить, что сервис временно недоступен
  • предложить повторить позже
  • по возможности сохранить черновик действия, чтобы не вводить заново
  • Вебхуки: входящие обновления и внешние callback

    Слово webhook в ботах используется в двух смыслах, и их полезно различать.

    | Тип webhook | Кто вызывает | Куда | Пример | |---|---|---|---| | Webhook Telegram | Telegram | ваш HTTPS endpoint | доставка Update вместо getUpdates | | Webhook внешнего сервиса | внешний сервис | ваш HTTPS endpoint | платёжный провайдер прислал статус |

    Webhook Telegram: что нужно для работы

    Чтобы Telegram мог отправлять вам события, endpoint должен быть:

  • доступен из интернета
  • по HTTPS
  • отдавать успешный ответ быстро
  • Методы Bot API:

  • setWebhook
  • getWebhookInfo
  • Когда webhook лучше long polling

    Webhook обычно выбирают, когда:

  • бот живёт на сервере 24/7
  • важна стабильная доставка и масштабирование
  • вы хотите меньше «пустых запросов» к Telegram
  • Long polling удобнее, когда:

  • вы учитесь
  • вы разрабатываете локально
  • вам не хочется поднимать публичный HTTPS endpoint
  • Пример запуска webhook в python-telegram-bot

    В python-telegram-bot у Application есть режим webhook. Общая идея: вы указываете публичный URL и порт, а библиотека поднимет HTTP-сервер.

    Идея url_path=token проста: вы делаете URL сложнее угадать. При этом всё равно важнее защищать сервер сетевыми правилами и не светить токен.

    Если вы строите webhook endpoint самостоятельно (например, на FastAPI), документация фреймворка: FastAPI.

    Платежи в Telegram: как устроен поток событий

    Telegram Payments позволяют принимать оплату внутри Telegram через провайдера платежей.

    Основная документация: Telegram Payments.

    Что должен поддержать бот

    Минимальный «платёжный» сценарий включает:

  • отправку счёта пользователю
  • обработку события перед списанием
  • подтверждение успешной оплаты
  • Ключевые сущности и события в Bot API:

  • sendInvoice
  • PreCheckoutQuery
  • SuccessfulPayment
  • Сценарий оплаты по шагам

  • Пользователь выбирает товар или услугу в вашем сценарии.
  • Бот отправляет инвойс методом sendInvoice.
  • Перед списанием Telegram присылает событие pre_checkout_query.
  • Бот обязан быстро ответить answerPreCheckoutQuery, иначе оплата не пройдёт.
  • После оплаты в сообщение добавляется successful_payment, и вы выдаёте результат.
  • Главная мысль: создание заказа и подтверждение оплаты — разные этапы. Обычно вы создаёте заказ со статусом pending, а после successful_payment переводите в paid.

    payload: как связать оплату с вашим заказом

    При отправке инвойса вы указываете payload — строку, которая вернётся вам в событиях оплаты. Это удобное место, чтобы хранить идентификатор заказа.

    Практика:

  • payload не должен содержать секреты
  • payload должен однозначно связывать оплату и запись в БД
  • формат делайте коротким и предсказуемым, например order:12345
  • Валидация оплаты

    Даже если Telegram сообщил об успехе, в вашем коде полезно проверить:

  • что payload соответствует реально существующему заказу
  • что заказ ещё не отмечен как paid (защита от повторов)
  • что сумма и валюта совпадают с тем, что вы ожидали
  • Безопасность и эксплуатация: минимум для продакшена

    Секреты и ключи

  • токен бота храните в переменных окружения
  • ключи внешних API не держите в коде
  • ограничивайте доступ к серверу (фаервол, закрытые порты)
  • Логи и наблюдаемость

  • логируйте ошибки внешних API
  • фиксируйте ключевые бизнес-события: создан заказ, подтверждена оплата
  • не логируйте персональные данные и платёжные реквизиты целиком
  • Таймауты и ретраи

  • ставьте таймауты на внешние запросы
  • используйте ограниченные ретраи на временные ошибки
  • не делайте бесконечные повторы в обработчиках Telegram
  • Как связать всё в одном проекте

    Если собрать материал курса в единую «скелетную» архитектуру, обычно получается так:

  • обработчики Telegram отвечают за приём событий и UX
  • сервисный слой делает работу: создаёт заказ, вызывает внешнее API, пишет в БД
  • слой интеграций отдельно инкапсулирует HTTP-клиенты и ключи
  • хранилище (SQLite/PostgreSQL) хранит результаты и важные состояния
  • Такой подход помогает не превращать бота в один файл с сотнями строк и делает развитие сценариев предсказуемым.

    Что дальше

    Теперь у вас есть инструменты уровня «продуктового бота»: постоянные данные, внешние интеграции, webhook-режим и платежи. Следующий шаг в развитии проекта обычно включает:

  • полноценное управление состояниями (с устойчивым storage)
  • более строгую архитектуру (разделение слоёв)
  • деплой и окружения (dev/stage/prod)
  • 5. Тестирование, безопасность и развертывание в продакшн

    Тестирование, безопасность и развертывание в продакшн

    После того как бот научился обрабатывать сценарии, хранить данные, интегрироваться с внешними API, работать через webhook и принимать платежи, наступает следующий этап: сделать его надёжным и безопасным, а затем корректно развернуть в продакшене.

    Эта статья связывает всё, что вы уже сделали в курсе, с практикой эксплуатации:

  • тестирование: как проверять логику и обработчики без ручного кликанья в Telegram
  • безопасность: как не потерять токен, не принять поддельный webhook и не «сломать» БД вводом пользователя
  • развертывание: как упаковать, запустить, обновлять и наблюдать бота в продакшене
  • !Диаграмма пайплайна от кода до продакшена и места, где применяются тесты, безопасность и наблюдаемость

    Тестирование бота

    Тестирование в Telegram-ботах обычно делят на два уровня:

  • тестирование бизнес-логики (самое важное и простое)
  • тестирование Telegram-слоя (хендлеров, роутинга, разборов входящих событий)
  • Главная идея архитектуры из предыдущих статей: обработчики Telegram должны быть тонкими, а логика — вынесенной в сервисы. Тогда большая часть проекта тестируется как обычный Python/Node-проект.

    Что именно тестировать

    | Объект | Что проверять | Пример | |---|---|---| | Сервисный слой | правила, расчёты, статусы, идемпотентность | «создать заказ только один раз по ключу» | | Валидация ввода | парсинг дат, сумм, форматов, ограничений | «дата должна быть в формате ДД.ММ.ГГГГ» | | Интеграции | обработка таймаутов, кодов ответа, ретраи | «API вернул 500 → показать пользователю дружелюбное сообщение» | | Хендлеры | правильный роутинг: команда → состояние → следующий шаг | «после кнопки Создать бот ждёт название» |

    Unit-тесты: проверяем сервисы без Telegram

    Для Python самый частый стек:

  • pytest
  • unittest.mock (моки и подмены)
  • Пример: тестируем функцию, которая создаёт заявку и защищается от дубля по ключу операции. Здесь Telegram вообще не нужен.

    Почему это полезно:

  • тест быстрый и стабильный
  • в тесте нет сети, Telegram и webhook
  • легко расширять покрытие: ошибки, границы, форматы
  • Тестирование хендлеров: как не тестировать Telegram вручную

    Хендлеры можно тестировать, но важно понимать границу: вы не обязаны «симулировать весь Telegram». Обычно достаточно проверить:

  • что при входном событии хендлер вызывает нужный сервис
  • что выбирается нужный следующий шаг/состояние
  • что отправляется ожидаемое сообщение или кнопки
  • Подходы:

  • контрактный стиль: хендлер получает update/context, а вы подсовываете минимальные фейки
  • моки методов отправки: подменяете reply_text, edit_message_text и проверяете, что их вызвали
  • Если вы используете python-telegram-bot, держите под рукой документацию по объектам и структуре обновлений:

  • python-telegram-bot Documentation
  • Update
  • Практическое правило: чем тоньше ваши хендлеры, тем проще их тестировать.

    Интеграционные тесты: база и внешние API

    Интеграционные тесты проверяют связку нескольких компонентов:

  • сервис + база (SQLite/PostgreSQL)
  • сервис + HTTP-клиент
  • Важно:

  • не ходите в реальный внешний API в CI без необходимости
  • используйте моки HTTP или тестовый сервер
  • фиксируйте таймауты и сценарии ошибок
  • В Python полезно держать внешние вызовы в отдельном модуле (как обсуждалось в статье про интеграции), чтобы тесты могли подменить одну точку.

    Статический анализ и форматирование

    Это не заменяет тесты, но резко снижает число ошибок на старте.

    Популярные инструменты Python:

  • Ruff (линтер)
  • Black (форматирование)
  • mypy (проверка типов)
  • Безопасность Telegram-бота

    Безопасность бота — это не только «спрятать токен». В продакшене важны четыре зоны:

  • секреты (токен, ключи API)
  • входящие события (webhook, кнопки, команды)
  • данные (БД, платежи, файлы)
  • инфраструктура (сервер, доступы, логи)
  • Секреты: токен и ключи

    Минимальные правила:

  • храните токен только в переменных окружения или секрет-хранилище платформы
  • не логируйте токен
  • не коммитьте .env в репозиторий
  • при утечке сразу перевыпускайте токен через BotFather
  • В Telegram токен даёт полный контроль над ботом. Поэтому его защита — приоритет.

    Webhook: как принимать обновления безопасно

    Если вы работаете в webhook-режиме, ваша задача — принять HTTP-запрос от Telegram и превратить его в обработку.

    Основные риски:

  • запросы могут приходить не от Telegram (сканеры, боты, злоумышленники)
  • endpoint могут «ддосить» или засыпать мусором
  • Практики защиты:

  • делайте url_path сложным (часто используют токен или отдельный случайный путь)
  • ограничивайте доступ на уровне сети (фаервол, allowlist, правила платформы)
  • быстро отвечайте HTTP 200 и не держите соединение долго
  • ограничивайте размер тела запроса
  • Полезные методы Bot API:

  • setWebhook
  • getWebhookInfo
  • Обработка пользовательского ввода

    Пользовательский ввод в боте — это всё:

  • текст
  • callback_data
  • файлы
  • параметры /start (deep links)
  • Правила:

  • валидируйте формат на каждом шаге сценария
  • устанавливайте ограничения по длине и типам
  • не подставляйте ввод напрямую в SQL
  • Если вы используете SQLite напрямую, применяйте параметризованные запросы ? (как в предыдущей статье). Это базовая защита от SQL-инъекций.

    Callback-кнопки и права доступа

    Inline-кнопки дают callback_query.data. Ошибка многих новичков — считать, что если кнопка показана пользователю, значит действие разрешено.

    Проверяйте:

  • кому принадлежит сущность (например, «заказ пользователя A» не должен быть доступен пользователю B)
  • что состояние актуально (сообщение могло быть старым)
  • что действие повторно безопасно (идемпотентность)
  • Файлы и медиа

    Если бот принимает файлы:

  • ограничьте типы и размер (на уровне логики)
  • сохраняйте в отдельную директорию
  • не доверяйте имени файла
  • не исполняйте и не открывайте файл как код
  • Про работу с файлами и file_id см. статью про медиа и Bot API объект File.

    Платежи: проверка того, что «успех» относится к вашему заказу

    В платежном сценарии (см. предыдущую статью) минимальная безопасность:

  • payload должен однозначно связывать оплату и заказ
  • при pre_checkout_query и successful_payment сверяйте:
  • существует ли заказ
  • не оплачен ли он уже
  • совпадает ли сумма/валюта с ожидаемой
  • Документация:

  • Telegram Payments
  • sendInvoice
  • PreCheckoutQuery
  • SuccessfulPayment
  • Логи и персональные данные

    Логи помогают расследовать ошибки, но могут стать утечкой.

    Практика:

  • не логируйте токены, ключи и полные платёжные данные
  • минимизируйте персональные данные в логах
  • в продакшене задавайте уровни логов (обычно INFO/WARNING, а DEBUG включают временно)
  • Развертывание в продакшн

    Продакшн-развертывание — это ответ на вопросы:

  • где бот запускается
  • как он перезапускается при падении
  • как обновляется без ручных действий
  • как вы узнаёте, что он «сломался»
  • Long polling или webhook в продакшене

    | Подход | Плюсы | Минусы | Типичный выбор | |---|---|---|---| | Long polling | просто, не нужен публичный endpoint | больше сетевой «шумихи», сложнее масштабировать | маленькие боты, быстрый старт | | Webhook | лучше масштабирование, меньше лишних запросов | нужен HTTPS endpoint и инфраструктура | продакшн, сервер/платформа |

    Если бот должен работать стабильно 24/7, webhook чаще удобнее.

    Контейнеризация: Docker как стандарт упаковки

    Docker помогает сделать окружение воспроизводимым:

  • одинаково запускается локально и на сервере
  • зависимости фиксированы
  • проще деплоить
  • Официальная документация:

  • Docker Documentation
  • Практическая схема:

  • ваш код + зависимости → Docker-образ
  • образ запускается как контейнер
  • конфигурация (токен, URL, ключи) передаются переменными окружения
  • Процессы и перезапуск: systemd или платформа

    Если вы деплоите на свой VPS, вам нужен менеджер процессов, который:

  • поднимет бота при старте сервера
  • перезапустит при падении
  • соберёт stdout/stderr в логи
  • На Linux часто используют systemd:

  • systemd
  • Если вы деплоите на платформу (PaaS), она обычно делает это сама, но принципы те же: healthchecks, автоперезапуск, конфигурация через секреты.

    Миграции базы данных

    Когда бот уже в продакшене, схема БД будет меняться. Даже для простых проектов важно:

  • хранить изменения схемы в виде миграций
  • уметь накатывать миграции перед запуском новой версии
  • Для Python-проектов с SQLAlchemy часто используют Alembic:

  • Alembic
  • Если вы используете чистый SQLite в учебном проекте, минимальный вариант миграций — отдельные SQL-файлы и таблица с версией схемы. Смысл тот же: изменения должны быть повторяемыми.

    Наблюдаемость: как понять, что бот работает

    В продакшене вам нужны три вещи:

  • метрики (сколько событий, сколько ошибок)
  • логи (почему упало)
  • алерты (когда пора проснуться)
  • Минимальный набор:

  • структурные логи с уровнями
  • обработчик исключений, который фиксирует stacktrace
  • алертинг через внешнюю систему ошибок
  • Популярный вариант для ошибок:

  • Sentry
  • Практика:

  • логируйте ключевые бизнес-события (создан заказ, подтверждена оплата)
  • отдельно логируйте ошибки интеграций (таймауты, неверные ответы)
  • не смешивайте бизнес-логи и отладочные логи в один поток
  • CI/CD: автоматизация тестов и деплоя

    Минимальный полезный CI:

  • запускает тесты при каждом пуше
  • запускает линтер
  • собирает артефакт (например, Docker-образ)
  • Популярная система для репозиториев на GitHub:

  • GitHub Actions
  • Примерный порядок шагов в CI:

  • установить зависимости
  • запустить линтер и формат-проверки
  • запустить тесты
  • собрать Docker-образ (опционально)
  • задеплоить (опционально, после ручного подтверждения)
  • Чеклист перед продакшеном

    Ниже — короткий чеклист, который закрывает типовые проблемы.

  • Секреты
  • - токен и ключи в переменных окружения - секреты не попадают в логи
  • Устойчивость
  • - есть таймауты на внешние HTTP-запросы - ошибки API обрабатываются дружелюбно
  • Данные
  • - включена идемпотентность для критических операций - есть план миграций БД
  • Webhook
  • - endpoint защищён (сложный путь, сетевые правила) - бот отвечает быстро
  • Наблюдаемость
  • - есть логи и сбор ошибок - понятен процесс реакции на инцидент

    Как это связывается с предыдущими материалами курса

  • Из статей про сценарии и UX вы берёте принцип предсказуемых состояний и «глобальных выходов» вроде /start и отмены — это напрямую упрощает тестирование.
  • Из статьи про реализацию вы берёте дисциплину: обработчики тонкие, данные и сервисы отдельные — это делает проект тестируемым.
  • Из статьи про данные и интеграции вы берёте таймауты, идемпотентность, webhook и платежные события — всё это в продакшене становится обязательным.
  • Если вы внедрили практики из этой статьи, ваш бот перестаёт быть «демкой» и становится сервисом, который можно безопасно запускать для реальных пользователей.