Телеграм бот для объединения сообщений из Telegram, ВКонтакте, Max и сторонних API источников в единую систему технической поддержки.
Сообщения отправляются в Telegram-группу, где под каждого пользователя создаётся отдельная чат-тема (топик).
Бот поддерживает все типы сообщений: текст, изображения, файлы, голосовые сообщения, видео, стикеры, контакты и другие медиафайлы.
Документация: https://docs.tg-support-bot.ru/
Презентация работы бота: https://youtu.be/hIpYreHOxIk
Инструкция по установке через Docker Compose: https://youtu.be/ZAtP9qJ5q9M
Telegram-группа поддержки: https://t.me/pt_tg_support
Для новых пользователей я сделал тестовую площадку, где можно посмотреть, как всё устроено внутри: — как выглядит проект — как работает административная панель — как происходит отправка сообщений и многое другое
🔹 Тестовая группа для сообщений: https://t.me/tg_support_bot_test
🔹 Доступ к админке: https://support.iliya-code.ru/admin/ Логин: manager@mail.ru Пароль: manager_123
🔹 Сообщество ВКонтакте: https://vk.com/club217903474
🔹 MAX: https://vk.com/club217903474
🔹 Telegram-бот: https://t.me/TgSupportTest1Bot
Буду рад вашей обратной связи! 🚀
- Как это работает
- Основные возможности
- Технологический стек
- Установка и настройка
- AI помощник
- Подключение Avito
- Подключение Email
- Живой чат для сайта
- API интеграция
- Мониторинг и логирование
- Поддерживаемые типы сообщений
- Интерактивные клавиатуры
- Архитектура
- Документация
- Вклад в проект
- Лицензия
┌─────────────┐ ┌─────────────┐ ┌─────────────────┐
│ Telegram │────────▶│ │◀────────│ ВКонтакте │
│ Users │ │ │ │ Users │
└─────────────┘ │ │ └─────────────────┘
│ │
┌─────────────┐ │ TG Bot │ ┌─────────────────┐
│ Max │────────▶│ Server │◀────────│ External API │
│ Users │ │ │ │ Sources │
└─────────────┘ │ │ └─────────────────┘
│ │
┌─────────────┐ │ │ ┌─────────────────┐
│ Website │────────▶│ │◀────────│ Avito │
│ Widget │ │ │ │ Users │
└─────────────┘ └──────┬──────┘ └─────────────────┘
│
▼
┌──────────────────────┐
│ Telegram Group │
│ ┌────────────────┐ │
│ │ Topic: User 1 │ │
│ ├────────────────┤ │
│ │ Topic: User 2 │ │
│ ├────────────────┤ │
│ │ Topic: User 3 │ │
│ └────────────────┘ │
└──────────────────────┘
- Получение сообщения: Пользователь отправляет сообщение боту через Telegram, ВКонтакте, виджет сайта или внешний API
- Создание топика: Бот автоматически находит или создаёт тему (топик) в Telegram-группе для этого клиента
- Пересылка в группу: Сообщение пересылается в соответствующую тему с информацией об отправителе
- Ответ менеджера: Менеджеры отвечают прямо в теме — бот отслеживает их сообщения
- Отправка клиенту: Ответ автоматически пересылается клиенту от имени бота (без раскрытия личности менеджера)
- Telegram: Полная поддержка Telegram Bot API
- ВКонтакте: Интеграция с VK API для сообщений сообщества
- Max: Интеграция с мессенджером Max (экосистема VK/Mail.ru)
- Avito: Встроенный канал поддержки через Avito Messenger API (только текст в v1 — без вложений и без формы отзыва с кнопками, см. раздел ниже)
- Email: Встроенный канал поддержки — приём писем по IMAP-опросу, ответы по SMTP; работает с любым провайдером (только текст в v1, см. раздел ниже)
- Website Widget: Готовый виджет живого чата для встраивания на сайт
- External API: REST API для подключения сторонних источников
- Все типы медиафайлов (текст, изображения, документы, голосовые, видео, стикеры, контакты)
- Автоматическая организация диалогов в топики Telegram-группы
- Приватность: клиенты не видят, кто из менеджеров им отвечает
- Настраиваемые шаблоны имен топиков
- AI помощник: Интеграция с OpenAI, DeepSeek, GigaChat для генерации ответов
- Очереди сообщений с Laravel Queue
- Webhook обработка в реальном времени
- Виджет сайта на fetch-polling (без отдельного WebSocket сервера)
- Рабочее место менеджера (
/admin/chats): полноэкранный чат-воркспейс со списком диалогов - Настройки (
/admin/settings/*): интеграции каналов, AI-помощник, API/вебхуки, команда операторов — всё хранится в БД (таблицаsettings), без правки.env - Роли: админ видит все экраны настроек; менеджер — только «Общие». Удаление чата доступно только админу
- Два режима работы менеджеров: через Telegram-супергруппу (топики) или через админ-панель
- Laravel Telescope: Дашборд отладки (
/telescope) — запросы, исключения, логи, SQL, очереди, кэш - Логи: Ротируемые файлы в
storage/logs/, просмотр черезphp artisan pailили во вкладке Logs Telescope
- Блокировка пользователей
- Закрытие обращений
- История всех сообщений
- Управление внешними источниками
Backend:
- Laravel 12 (PHP 8.2+)
- PostgreSQL (база данных)
- Laravel Queue (обработка фоновых задач, sync)
- spatie/laravel-data (DTO)
Admin & Frontend:
- Livewire 3 + Blade (вся админка: вход
/admin/login, рабочее место чата/admin/chats, настройки/admin/settings/*) - Стандартная Laravel-аутентификация
- Tailwind CSS v4 (дизайн-система админки)
- Виджет живого чата
Интеграции:
- Telegram Bot API
- VK API
- Max Bot API (prog-time/max-php-sdk)
- Avito Messenger API (встроенный модуль ядра,
app/Modules/Avito/) - IMAP / SMTP через webklex/php-imap + встроенный Laravel Mail (встроенный модуль ядра,
app/Modules/Email/) - AI: OpenAI / DeepSeek / GigaChat
API & документация:
- REST API + L5-Swagger (
/api/documentation)
DevOps:
- Docker + Docker Compose (сервисы:
pet,pgdb,nginx,laravel_queue,laravel_scheduler) - Nginx (reverse proxy, SSL)
Мониторинг и логирование:
- Laravel Telescope (дашборд отладки: запросы, логи, SQL, очереди, исключения)
- Ротируемые лог-файлы (
storage/logs/,php artisan pail) - prog-time/tg-logger (логирование в Telegram)
Качество кода:
- PHPUnit 11 (тесты)
- PHPStan level 6 / larastan (статический анализ)
- Laravel Pint (форматирование, PSR-12 + Laravel)
Пошаговые инструкции по установке и настройке вынесены в документацию и Wiki:
- 📘 С чего начать: docs.tg-support-bot.ru
- 🚀 Установка через Docker Compose: инструкция
- 🖥 Установка на хостинг: инструкция
docker-compose.yml монтирует рабочую копию в контейнер (.:/var/www), и этот bind-mount перекрывает содержимое образа. Поэтому vendor/, node_modules/ и public/build/, собранные на этапе docker build, в смонтированном каталоге не видны. docker/scripts/entrypoint.sh подхватывает это автоматически при первом старте контейнера app: если vendor/autoload.php или public/build/manifest.json отсутствуют, он сам выполняет composer install и npm ci && npm run build, прежде чем стартовать php-fpm — руками эти команды выполнять не нужно. Контейнеры queue/scheduler в это время ждут, пока app закончит установку (не запускают её параллельно — иначе три процесса писали бы в один и тот же смонтированный каталог одновременно). Все процессы внутри (php-fpm, queue, scheduler) работают под www-data — uid 33, поэтому каталоги, в которые пишет приложение, должны принадлежать этому uid на хосте до запуска — сам entrypoint работает под тем же www-data и не может создать/перевладеть их сам.
# 1. Конфигурация
cp .env.example .env
# 2. Каталоги под запись + владелец www-data (uid 33).
# Без этого шага entrypoint (composer/npm) и artisan упрутся в permission denied.
mkdir -p vendor node_modules storage bootstrap/cache public/build
chown -R 33:33 vendor node_modules storage bootstrap/cache public/build
# 3. Сборка образа и запуск — первый старт займёт минуту-две: entrypoint
# ставит PHP/JS-зависимости и собирает фронтенд, прежде чем открыть порт.
# Прогресс можно смотреть через `docker compose logs -f app`.
docker compose up -d --build
# 4. Ключ приложения и миграции
docker exec -it pet php artisan key:generate
docker exec -it pet php artisan migrate
docker exec -it pet php artisan storage:linkКаталоги из шага 2 не отслеживаются git и не синхронизируются mutagen, поэтому выставленный владелец сохраняется между деплоями. При следующих docker compose up (без --build) entrypoint отрабатывает мгновенно — vendor//public/build/ уже на месте, повторно composer install/npm run build не запускаются.
После запуска войдите в админ-панель
/admin/loginи настройте каналы и AI на странице Настройки (/admin/settings/*). Все токены и ключи хранятся в БД в зашифрованном виде — править.envдля этого не нужно.
Бот поддерживает интеграцию с AI для автоматической генерации ответов.
- OpenAI (GPT-4, GPT-3.5)
- DeepSeek
- GigaChat (Сбер)
AI настраивается полностью через админ-панель (хранится в БД, в .env ключей AI нет): учётные данные провайдера (/admin/settings/ai/{provider}, проверка ключа перед сохранением), отдельный Telegram-бот для публикации AI-ответов (/admin/settings/integrations/telegram_ai) и поведение — главный переключатель, авто-ответ (черновик на проверку менеджеру либо прямая отправка) и системный промпт (/admin/settings/ai).
Подробные пошаговые инструкции — в документации:
- 📘 Подключение AI-помощника: инструкция
- 🤖 OpenAI: инструкция
- 🤖 DeepSeek: инструкция
- 🤖 GigaChat: инструкция
AI работает на всех платформах пользователей (Telegram, VK, Max, Avito, Email) и только при MANAGER_INTERFACE=telegram_group. Ответы генерируются на основе истории диалога из таблицы messages (ограничение по токенам — ai.max_context_tokens, по умолчанию 3000). Триггер — только текстовые сообщения; вложения AI не запускают.
Avito — встроенный канал поддержки, часть ядра (app/Modules/Avito/), а не платный подключаемый модуль. Обращения из чата объявлений Avito попадают в ту же воронку, что и Telegram/VK/Max: в форум-топики Telegram-супергруппы (если она настроена) и/или в рабочее место /admin/chats.
- Откройте Настройки → Интеграции → Avito (
/admin/settings/avito) в админ-панели. - Укажите Client ID и Client Secret от Avito Messenger API (OAuth
client_credentials). - При необходимости укажите Base URL (по умолчанию
https://api.avito.ru) и секрет вебхука — он встраивается в путь URL для проверки подлинности входящих запросов. - Нажмите «Сохранить» — перед сохранением сервис проверяет доступы через
core/v1/accounts/self; при ошибке ничего не сохраняется, при успехе автоматически подтягивается ID аккаунта Avito. - Зарегистрируйте вебхук в Avito Messenger:
docker exec -it pet php artisan avito:set-webhook
Все учётные данные хранятся только в БД (таблица settings), править .env не нужно — файла config/avito.php в проекте нет.
- Только текст. Вложения от пользователей Avito не принимаются; файл, приложенный к ответу менеджера, пропускается с предупреждением в логах — сам текст всё равно отправляется.
- Нет inline-кнопок. Avito Messenger не поддерживает интерактивные клавиатуры, поэтому форма оценки после закрытия обращения отправляется как обычный текст без кнопок. Callback с оценкой от пользователя не приходит, поэтому запись отзыва остаётся в статусе «ожидает оценки» — обработка callback'ов оценки помечена как TODO до уточнения механизма коллбэков Avito.
Email — встроенный канал поддержки, часть ядра (app/Modules/Email/). В отличие от остальных каналов у него нет HTTP-вебхука: входящие письма опрашиваются по IMAP по расписанию (php artisan email:poll, раз в минуту), исходящие ответы уходят по SMTP. Обращения попадают в ту же воронку, что и Telegram/VK/Max/Avito: в форум-топики Telegram-супергруппы (если она настроена) и/или в рабочее место /admin/chats. Работает с любым провайдером (Яндекс, Mail.ru, Gmail с паролем приложения, корпоративный ящик) — пресетов конкретных провайдеров и OAuth в v1 нет.
- Откройте Настройки → Интеграции → Email (
/admin/settings/email) в админ-панели. - Укажите логин и пароль почтового ящика (для Gmail/Workspace — пароль приложения, обычный пароль аккаунта не подойдёт).
- Укажите IMAP-хост/порт/шифрование (приём) и SMTP-хост/порт/шифрование (отправка) вашего провайдера.
- Укажите адрес и имя отправителя — показываются пользователю в поле «От кого».
- Нажмите «Сохранить» — перед сохранением сервис проверяет доступы реальным подключением и по IMAP, и по SMTP; при ошибке любой из сторон ничего не сохраняется.
Планировщик (email:poll) уже зарегистрирован в routes/console.php и работает через тот же docker-сервис scheduler, что и остальные задачи по расписанию — отдельно ничего запускать не нужно. Пока Email не настроен, команда тихо ничего не делает.
Все учётные данные хранятся только в БД (таблица settings), править .env не нужно.
- Только текст. Вложения от пользователей не принимаются; файл, приложенный к ответу менеджера, пропускается с предупреждением в логах — сам текст всё равно отправляется.
- Нет inline-кнопок. У почты нет интерактивных клавиатур, поэтому форма оценки после закрытия обращения отправляется как обычный текст. Ответной оценки от пользователя бот не получает, поэтому запись отзыва остаётся в статусе «ожидает оценки» — как и у Avito.
- Треды писем не хранятся в БД. Заголовки
In-Reply-To/Referencesдля правильной цепочки письма формируются из последнего входящего письма диалога, которое запоминается в кэше (Redis) с TTL 90 дней, а не в отдельной колонке/таблице — миграция намеренно не добавлялась (см. issue #214). Если запись в кэше истечёт, ответ всё равно уйдёт, но без точной привязки к цепочке письма в почтовом клиенте пользователя.
Проект включает готовый виджет живого чата для встраивания на сайт.
Виджет — это самодостаточный скрипт (public/widget/widget.js) на vanilla JS, который общается с бэкендом через REST-эндпоинты с fetch-polling (отдельный Node.js/WebSocket сервер больше не нужен).
Краткая инструкция:
- Создайте источник и публичный ключ виджета в админ-панели на странице API/вебхуков:
/admin/settings/api-webhooks/{source} - Вставьте перед закрывающим тегом
</body>на вашем сайте один тег<script>:
<script
src="https://yourdomain.com/widget/widget.js"
data-domain="https://yourdomain.com"
data-key="pub_xxxxxxxx"
data-greeting="Напишите нам, мы онлайн!"
data-manager="Поддержка"
defer
></script>- Виджет аутентифицируется заголовком
X-Widget-Keyи отправляет сообщения через/api/widget/{external_id}/messages; все сообщения поступают в Telegram-группу.
📘 Подробнее — в документации: Виджет живого чата
Бот предоставляет REST API для подключения внешних систем. Запросы аутентифицируются bearer-токеном из таблицы external_source_access_tokens (управление — /admin/settings/api-webhooks); неактивные токены и IP вне allowlist отклоняются middleware ApiQuery.
Основные эндпоинты ({external_id} — ID пользователя в вашей системе):
| Метод | Путь | Описание |
|---|---|---|
GET |
/api/external/{external_id}/messages |
Список сообщений |
GET |
/api/external/{external_id}/messages/{id_message} |
Одно сообщение |
POST |
/api/external/{external_id}/messages |
Отправить сообщение |
PUT |
/api/external/{external_id}/messages |
Редактировать сообщение |
DELETE |
/api/external/{external_id}/messages |
Удалить сообщение |
POST |
/api/external/{external_id}/files |
Загрузить файл |
Пример запроса:
curl -X POST https://yourdomain.com/api/external/user_12345/messages \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"source": "crm-system",
"external_id": "user_12345",
"text": "Здравствуйте, у меня вопрос по заказу"
}'Параметры:
source— идентификатор внешнего источника (обязательный)external_id— ID пользователя в вашей системе (обязательный)text— текст сообщенияattachment— массив вложений (опционально)
Когда команда отвечает внешнему пользователю, на external_sources.webhook_url отправляется webhook.
Подробная документация API доступна через Swagger: https://yourdomain.com/api/documentation
URL: https://yourdomain.com/telescope
Доступ защищён сессионной авторизацией админки: middleware-стек ['web', 'auth', App\Http\Middleware\TelescopeAccess::class] — гость перенаправляется на /admin/login (302), не-админ получает 403, админ открывает дашборд. HTTP Basic auth не используется (его 401-челлендж вырезается edge-прокси перед доменом). Не зависит от APP_DEBUG; чтобы выключить дашборд полностью — TELESCOPE_ENABLED=false.
Дашборд отладки: запросы, исключения, логи (Log::channel('app')), SQL-запросы, очереди/джобы, кэш, события. Записи хранятся в таблицах telescope_entries (PostgreSQL) и обрезаются ежедневно (telescope:prune --hours=48). В окружении local пишется всё; в остальных — только сбои/исключения/расписание.
Логи приложения пишутся в ротируемые файлы storage/logs/ (laravel-*.log — общий стек, app-*.log — события через Log::channel('app')). Просмотр в реальном времени:
docker exec -it pet php artisan pail
# или
tail -f storage/logs/laravel-$(date +%F).log- ✅ Текстовые сообщения
- ✅ Фото
- ✅ Документы
- ✅ Голосовые сообщения
- ✅ Видео
- ✅ Видео-кружки (video notes)
- ✅ Стикеры
- ✅ Аудио
- ✅ Контакты
- ✅ Локации
- ✅ Опросы (polls)
- ✅ Текстовые сообщения
- ✅ Фото
- ✅ Документы
- ✅ Голосовые сообщения
- ✅ Видео
- ✅ Стикеры
- ✅ Аудио
- ✅ Текстовые сообщения
- ✅ Файлы (изображения, документы)
- ✅ Текстовые сообщения
- ✅ Фото
- ✅ Документы / файлы
- ✅ Голосовые сообщения (аудио)
- ✅ Видео (пересылается как документ)
- ✅ Контакты (пересылаются как текст с именем и телефоном)
- ✅ Геопозиция (пересылается как текст с координатами и ссылкой на Google Maps)
- ✅ Текстовые сообщения
- ❌ Вложения (изображения, файлы) — не поддерживаются в v1, ни на приём, ни на отправку
- ✅ Текстовые сообщения (HTML-письма приводятся к тексту для менеджера)
- ❌ Вложения — не поддерживаются в v1, ни на приём, ни на отправку
- ✅ Все типы через API (определяется параметром
message_type)
Бот поддерживает отправку интерактивных клавиатур пользователям через специальный синтаксис в тексте сообщения.
Кнопки добавляются в текст сообщения с помощью двойных квадратных скобок:
[[Текст кнопки|тип:значение]]
| Тип | Синтаксис | Описание |
|---|---|---|
| URL | [[Открыть сайт|url:https://example.com]] |
Кнопка со ссылкой |
| Callback | [[Назад|callback:back]] |
Inline callback кнопка |
| Phone | [[Отправить номер|phone]] |
Запрос контакта пользователя |
| Text | [[Вариант 1]] |
Текстовая кнопка (reply keyboard) |
Inline клавиатура с URL и callback кнопками:
Добрый день! Чем могу помочь?
[[Открыть сайт|url:https://example.com]]
[[Вернуться назад|callback:back]]
[[Позвать оператора|callback:operator]]
Кнопки в одном ряду (без переноса строки между ними):
Выберите вариант:
[[Да|callback:yes]] [[Нет|callback:no]]
Reply клавиатура с запросом контакта:
Для продолжения поделитесь своим номером телефона
[[Отправить номер|phone]]
Текстовые кнопки:
Выберите категорию:
[[Техническая поддержка]]
[[Вопрос по оплате]]
[[Другое]]
| Платформа | Inline Keyboard | Reply Keyboard |
|---|---|---|
| Telegram | ✅ | ✅ |
| ВКонтакте | ✅ | ✅ |
| Avito | ❌ (не поддерживается Avito Messenger) | ❌ |
| ❌ (нет интерактивных элементов в письме) | ❌ | |
| External API | ✅ (через webhook) | ✅ (через webhook) |
- Кнопки автоматически удаляются из текста сообщения
- Inline кнопки (url, callback) имеют приоритет над reply keyboard
- Максимум 8 кнопок в одном ряду для Telegram
- Для VK кнопки конвертируются в соответствующий формат VK API
Документация: https://docs.tg-support-bot.ru/
API Documentation: https://yourdomain.com/api/documentation (Swagger)
Telegram группа поддержки: https://t.me/pt_tg_support
GitHub Issues: https://github.com/prog-time/tg-support-bot/issues
Мы приветствуем вклад сообщества!
Пожалуйста, ознакомьтесь с CONTRIBUTING.md перед началом работы.
Как помочь проекту:
- Сообщайте об ошибках через GitHub Issues
- Предлагайте новые функции
- Улучшайте документацию
- Создавайте Pull Request'ы
Если проект был вам полезен, поддержите его:
- ⭐ Поставьте звезду на GitHub
- 📢 Расскажите о проекте друзьям и коллегам
- 🤝 Внесите вклад в разработку
Проект распространяется под лицензией MIT.
Подробнее: LICENSE
GitHub: https://github.com/prog-time
Проект: https://github.com/prog-time/tg-support-bot
Telegram: https://t.me/pt_tg_support
Сделано с ❤️ для сообщества