Как я сделал Telegram SuperApp для ресторанов с нуля: WebApp, iiko, WordPress и живой чат в одной системе
Больше года назад я начал замечать одну и ту же картину: ресторан платит агрегатору 20–30% с каждого заказа, не имеет своей базы гостей, не может запустить акцию без согласования с платформой. При этом у каждого руководителя есть Telegram — и он им пользуется каждый день.
Так появилась идея: сделать полноценный ресторанный SuperApp прямо внутри Telegram — без скачивания приложений, без комиссий агрегаторов, с полным контролем данных.
Получилось объёмнее, чем я планировал. В этой статье — честный рассказ о том, что я построил, почему именно так, и какие решения оказались нетривиальными.
Telegram WebApp — почему это работает
Платформа состоит из трёх параллельных процессов:
- main_admin.py — веб-сервер Flask + Waitress: панель администратора и WebApp API
- main_bot.py — асинхронный Telegram-бот на python-telegram-bot v20
- main_jobs.py — планировщик APScheduler: рассылки, синхронизация с iiko, фоновые задачи
Архитектура — «модульный монолит». Каждый модуль живёт в modules//, включается одной строкой в .env, может быть отключён без изменения остального кода.
Что реализовано:
- booking — бронирование столиков с выбором зала и схемы;
- menu — интерактивное меню с корзиной и модификаторами;
- loyalty — бонусная система, уровни, реферальная программа, сертификаты;
- mailing — рассылки: сегментация, медиа, inline-кнопки, статистика;
- reviews — сбор и модерация отзывов, ответы из админки;
- support — live-чат (WebSocket + fallback уведомления в Telegram);
- metrics — аналитика, NPS-опросы после закрытия брони;
- iiko — синхронизация меню, стоп-листов и лояльности;
- wordpress — плагин для WP-сайтов: бронь и отзывы прямо на странице.
Telegram WebApp — почему это работает
Telegram WebApp — это способ открыть веб-страницу прямо в мессенджере. Пользователь видит полноценный интерфейс, никуда не уходит. Авторизация происходит автоматически через Telegram, без паролей и форм.
Для ресторана это означает: гость добавляет бот в контакты один раз и дальше — меню, бронь, история визитов, бонусный баланс — всё в одном месте.
Я реализовал WebApp на чистом Vanilla JS — никаких React/Vue. Причина простая: Telegram WebApp открывается на слабых устройствах, и тяжёлый фреймворк даёт заметный лаг при загрузке. Vanilla JS + правильные HTTP-кеши = мгновенный старт.
iiko — самая сложная часть
iiko — лидер российского рынка POS-систем для ресторанов. У них есть API, но работа с ним требует понимания их модели данных.
Я реализовал три уровня интеграции:
1. Синхронизация меню Получение категорий, блюд, модификаторов и стоп-листов. Главная сложность — стоп-листы обновляются в реальном времени, а у разных заведений они разные. Решение: отдельный APScheduler-джоб, который каждые N минут тянет дельту и обновляет локальный кеш.
2. Синхронизация лояльности Это двусторонний процесс: списание баллов через iiko (при оплате за стойкой) и начисление через бота (за визиты, рефералов). Матчинг пользователей идёт по номеру телефона с нормализацией (российский формат +7/8).
3. Защита от дублей При рестарте джоба синхронизация не должна начислять баллы дважды. Реализован идемпотентный dry-run режим и таблица processed_sync_ids.
WordPress-плагин — неочевидная ценность
Почти у каждого ресторана есть сайт на WordPress. Я написал плагин (PHP), который:
- Добавляет шорткоды [dakuta_booking_button] и [dakuta_review_button]
- При нажатии открывает всплывающую форму бронирования/отзыва
- Форма отправляет данные через WordPress AJAX → наш Flask API
- API валидирует настройки (часы работы, лимиты гостей, окно дат) и записывает бронь в общую БД
Авторизация между плагином и ботом — HMAC-SHA256 подпись с nonce и TTL. Защита от replay-атак реализована через таблицу использованных nonce с очисткой по TTL.
Это означает: ресторан получает единую базу броней и отзывов и из Telegram, и с сайта.
Live-чат поддержки
Самая сложная часть с точки зрения real-time:
Пользователь открывает WebApp → чат в браузере через Socket.IO. Администратор видит входящий запрос в своей панели и отвечает там же. Всё это — WebSocket через Flask-SocketIO.
Проблема: Telegram WebApp закрывают → юзер уходит из сокета. Как не потерять ответ администратора?
Решение: при разрыве соединения сервер переключается в fallback-режим и отправляет следующее сообщение администратора уже как обычное уведомление в Telegram-бот пользователя.
Для надёжной детекции разрыва уменьшен ping_interval до 10 сек и ping_timeout до 15 сек (дефолтные значения Socket.IO слишком медленные для мобильных браузеров).
Модульность: как это устроено изнутри
Каждый модуль — стандартная структура:
Ядро (core/loader.py) при старте сканирует папку modules/, вызывает setup() у каждого активного модуля. Модуль сам регистрирует свои Blueprint'ы и обработчики.
Это позволяет добавить новый модуль без изменения ядра: создаёте папку, пишете init.pyсsetup(), добавляете в ENABLED_MODULES — и он работает.
Что я бы сделал иначе
SQLite → PostgreSQL раньше. SQLite отлично работает в WAL-режиме для одного заведения. Но как только появляется несколько одновременных пишущих процессов — нужен PostgreSQL. Я написал запросы на чистом SQL без ORM специально для облегчения миграции, но сам переход всё равно потребует времени.
Реальный очередь для уведомлений. Сейчас рассылки и уведомления идут через APScheduler. Для надёжности лучше RabbitMQ или Redis Queue. Для одного заведения — хватает. Для SaaS-платформы с сотнями клиентов — нет.
Тесты с самого начала. Smoke-тесты появились уже на финале. В следующий раз начну с тест-фикстур.
Итог
Система получилась рабочей и использует её в качестве основы. Архитектурные решения — модульность, отдельные процессы, чистый SQL, Vanilla JS — были осознанными компромиссами между скоростью разработки и возможностью поддержки.
Если вы работаете в HoReCa или занимаетесь автоматизацией ресторанов — буду рад обсудить как технические детали, так и опыт интеграции с iiko.
Видеодемо системы (5 минут):
Вопросы — в комментариях или Telegram: @dakutacanmore12