Серия «Анатомия Telegram Mini Apps: о разработке изнутри»

0

Нюансы разработки бизнес-приложения на платформе Telegram Mini Apps: что я понял про Telegram как платформу

Серия Анатомия Telegram Mini Apps: о разработке изнутри

Примеры кода в серии — на C#/.NET, потому что так написан наш прод. Но всё описанное — про механику Telegram, а не про язык: то же самое собирается на Node, Python или Go без изменений. Собственно, ради этой переносимой механики статья и написана.

О чём статья? Мы вайб-кодингом построили мост из Telegram в Google Meet, Zoom и другие сервисы видеовстреч — и набили все шишки, которые можно набить о miniapp при разработке бизнес-приложения. В этой статье — четыре реальных лайфхака, которые стопроцентно пригодятся вам при написании любого бизнес-приложения на Telegram miniapp. Вот некоторые из них:

  • готовый блок правил для памяти агента — ограничения веб-движка Telegram плюс требования каталогов (копируется в CLAUDE.md как есть);

  • функция «где я?» — платформа и режим, без которой каждая страница будет полем чудес;

  • туннель с первого дня — приём, который превращает деплой-на-каждый-чих в итерации по секундам;

  • как хранить состояние между вызовами бота, miniapp и внешним браузером;

  • бот, который «звонит» как телефон;

  • и другие;

А это вся серия:

  • Часть 1 (вы здесь) — история продукта и честный вердикт Telegram как платформе для бизнес-приложений: что дёшево, что больно, что прописать агенту до первой строчки кода.

  • Часть 2 — механизм сессий: как передать параметры из инлайн-бота в miniapp, а потом прочитать их во внешнем браузере; аутентификация, обратная связь в чат и как не словить бан за редактирование сообщений.

  • Часть 3 — UX-хаки: бот, который «звонит» как телефон, онбординг-воронка одним JSON-файлом и почему ссылки надо готовить до клика.

С чего всё началось

Звонки в Telegram работают — но именно как звонки: голос, видео, положил трубку. Встречи — другой жанр, и он в Telegram почти не развит. А вот в Google Meet и Zoom вокруг встречи выросла целая экосистема: транскрибация, AI-саммари, запись, расширения, интеграции с календарями и CRM. Когда разговор рабочий — хочется именно встречу, со всем этим обвесом.

Но переписка-то живёт в Telegram: там группа с коллегами, там клиент, которому «удобнее в телеге». И каждый раз, когда переписка дозревает до «давай голосом», начинается ритуал: открыть Google Meet или Zoom, создать встречу, скопировать ссылку, вернуться в чат, вставить, объяснить, куда нажимать.

Идея была наглая в своей простоте: пусть ссылку создаёт бот. Прямо в чате, одной кнопкой, в том сервисе, который доступен и у меня, и у собеседника. Так появился GoosleeBot — мост из Telegram в мир видеовстреч: Google Meet, Zoom, Teams, Jitsi, FaceTime и далее по списку.

Дальше был чистый вайб-кодинг: агент, промпты, итерации. Цифры такие: первый MVP — Google Meet, Zoom и Jitsi — был готов за два дня и честно доказал, что идея работает. А потом были четыре недели доводки. И вот что важно: главным расходом времени был не код — код агент пишет быстро. Время съело множество сценариев, которые пришлось охватить и протестировать: два собеседника или группа, первый звонок или сотый, подключён ли у автора провайдер, iOS или десктоп, свой чат или чужой — и каждую комбинацию надо прогнать руками в настоящем Telegram.

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

Как это выглядит для пользователя

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

Ни один участник не устанавливает ничего нового. В этом вся ставка: дистрибуция через чат — фича Telegram, которой нет ни у одной «нормальной» платформы.

Правила, которые нужно прописать агенту в память до старта

Это центральная часть статьи. Если вы вайб-кодите под Telegram — скопируйте этот блок в CLAUDE.md / system prompt агента как есть. Каждое правило оплачено часами отладки «а почему на айфоне не так».

Блок А. Веб-движок Telegram — не браузер

  1. Никогда не использовать `100vh`. Только `viewportStableHeight` / CSS-переменную `var(--tg-viewport-height)` и подписку на событие `viewportChanged`. Что сломается: на iOS низ страницы уедет под панель, на Android клавиатура «сожмёт» экран и разложит вёрстку.

  2. Никаких `window.open` и `target="\_blank"`. Только `Telegram.WebApp.openLink()` для внешних ссылок и `openTelegramLink()` для внутренних. Что сломается: на части клиентов клик молча не сделает ничего.

  3. Никаких `alert` / `confirm` / `prompt`. Только `showAlert` / `showConfirm` / `showPopup`. Что сломается: то же самое — молчание вместо диалога, причём не везде, а «у некоторых пользователей», что хуже.

  4. Не полагаться на cookies для авторизации в miniapp. Webview теряет их непредсказуемо. Авторизация — токеном, переданным явно (заголовок или параметр). Что сломается: пользователь «разлогинивается» между открытиями, а вы неделю ищете несуществующий баг на сервере.

  5. `localStorage` — это кэш, а не хранилище. Всё важное — на сервере (или в `CloudStorage`). Что сломается: состояние пользователя внезапно обнулится, и вы об этом не узнаете.

  6. Навигация «назад» — через `BackButton` Telegram, а не через history браузера. Что сломается: системная кнопка «назад» на Android закроет miniapp целиком вместо возврата на шаг.

  7. Первым делом на каждой странице — определить, где ты: платформа и режим (miniapp или обычный браузер). От этого ветвятся CSS и поведение. Функция ниже.

  8. Всё, по чему пользователь кликает, должно быть готово до клика. Привычная веб-схема «клик → сервер обработал → сформировал URL → редирект» в Telegram не работает: переадресации нет. Конечный URL должен лежать в кнопке уже в момент её отрисовки — то есть всю «нагрузку редиректа» надо вычислить заранее (подробный разбор — в третьей статье).

  9. Тестировать минимум на трёх клиентах: iOS, Android, Desktop. Это три разных webview с разным рендером и разным поведением. «Работает у меня на десктопе» — это ноль из трёх.

Блок Б. Требования публикации — с первого дня, а не «потом отполируем»

У каталогов (и у самого Telegram, и у витрин miniapp-ов) есть требования к приложению. Переделывать под них готовый продукт — самая дорогая работа в проекте. Поэтому в память агента, жёстко:

  1. Мультиязычность с первого экрана. Ни одной строки текста в разметке — всё через локаль-файлы. Язык пользователя приходит сам: `initDataUnsafe.user.language\_code`. Добавить второй язык в проект, где строки зашиты в вёрстку, — это переписать проект

  2. Тема — только через `themeParams`. Все цвета — из CSS-переменных `--tg-theme-\*`, тёмная и светлая темы обязательны, подписка на `themeChanged`. Ни одного захардкоженного цвета. Что сломается: белый текст на белом фоне у половины аудитории — и отказ каталога.

  3. Каталог проверяет: языки, обе темы, все платформы. Это требования релиза, а не полировка. Агент должен считать их частью definition of done каждой страницы.

Функция «где я?» — обязательный первый кирпич

Одна и та же страница у нас открывается на iOS, Android, десктопе — и иногда просто в браузере (пользователь скопировал ссылку). CSS и поведение различаются во всех четырёх случаях, поэтому первым в проекте появился вот такой помощник:

```js

function whereAmI() {

const tg = window.Telegram?.WebApp;

const inMiniApp = !!tg \&\& tg.initData !== ''; // пустой initData = обычный браузер

const platform = tg?.platform ?? 'browser'; // ios | android | tdesktop | macos | weba | ...

const isMobile = platform === 'ios' || platform === 'android';

return { inMiniApp, platform, isMobile };

}

// дальше — класс на body и ветвление поведения

document.body.classList.add(`plt-${platform}`, inMiniApp ? 'in-tg' : 'in-browser');

```

Где это стреляет на практике:

  • CSS. Отступы под шапку/низ, safe area на iOS, реакция на клавиатуру на Android — всё вешается на классы `plt-\*`.

  • Редиректы. После OAuth-авторизации у Google мобильного пользователя надо вернуть в Telegram диплинком `tg://`, а десктопного — обычным `https`-редиректом на страницу. Перепутаешь — получишь либо зависший браузер, либо выброшенного из миниаппа пользователя.

  • Заглушка для «не-Telegram». Если `initData` пуст — это не miniapp, и вместо приложения показываем страницу «откройте через бота».

Мелочь? Мелочь. Но без неё каждая страница превращается в поле чудес.

Лайфхак: туннель с первого дня

Telegram не умеет «localhost»: и webhook бота, и URL miniapp-а должны быть публичными HTTPS-адресами. Поэтому первым инструментом в проекте — раньше базы, раньше CI — должен стать туннель: ngrok, cloudflared, dev tunnels в Visual Studio — что угодно, дающее постоянный публичный адрес на вашу локальную машину.

Рабочий цикл получается такой: бот и miniapp настроены на адрес туннеля, код правится локально с hot reload, а проверяешь — в настоящем Telegram на настоящем телефоне, сразу. Без туннеля каждая итерация — это деплой; с туннелем — секунды. Помните про количество сценариев, которое съело четыре недели? Без туннеля это были бы не недели.

Вердикт: Telegram как платформа для продуктивити-приложений

Что дёшево — неприлично дёшево:

  • Дистрибуция. Продукт распространяется пересылкой кнопки в чат. Ноль установок, ноль лендингов на старте: собеседник видит кнопку — собеседник уже пользователь.

  • Аутентификация из коробки. Telegram сам подписывает данные пользователя и отдаёт их miniapp-у. Не нужно ни регистрации, ни паролей, ни «войти через Google» — нужно только правильно проверить подпись (об этом — вся вторая статья).

  • Inline-механика. Бот работает в любом чате, даже там, где его нет в участниках. Это и есть «мост»: продукт живёт внутри чужих разговоров, а не ждёт пользователей у себя.

  • Realtime — работает, и его нужно делать. Мы сомневались, взлетит ли SignalR (WebSocket) внутри telegram-webview. Взлетел: полноценный хаб с группами живёт в бою на всех платформах. Обновление статуса звонка прилетает в miniapp мгновенно, без перезагрузок. Fallback на polling мы держим — но как страховку, а не как основной канал. Если ваш агент предлагает «давай просто поллинг каждую секунду» — не соглашайтесь, соединение честно работает.

Что больно:

  • Зоопарк клиентов. iOS, Android, Desktop, web — четыре разных Telegram с разным webview. Отсюда правило №9 и функция «где я?».

  • Веб-движок с характером. Весь блок А выше — это его портрет.

  • Требования каталогов. Языки и темы — не опция. Кто узнаёт об этом в конце разработки, тот переписывает вёрстку.

  • Из скучного: приём апдейтов от Telegram у нас переключается флагом между webhook и polling — удобно для отладки, и это всё, что стоит знать об этой теме.

Итого: если ваш продукт — про коммуникацию, координацию или «сделать что-то не выходя из чата», Telegram даёт фору любой платформе. Плата за это — дисциплина по отношению к webview. Дисциплину можно делегировать: просто отдайте агенту правила из этой статьи.

Что дальше в серии

Часть 2 — про самое неочевидное. Инлайн-кнопка в чате — одна на всех участников, и открывает она просто ссылку. Как передать в miniapp параметры конкретного звонка? Как понять, кто именно нажал, и не дать себя обмануть? Как вернуть ответ из miniapp обратно в чат? И отдельная ловушка: часть флоу неизбежно уходит во внешний браузер (например, OAuth-авторизация у Google) — а там переменные miniapp не работают вовсе, и из контекста Telegram остаётся только то, что вы сами положили в URL. Расскажу про механизм сессий, который закрывает всё это разом — причём это не трюк для проброса параметров, а полноценный серверный аналог сессии: типизированное хранилище значений, на котором держится вся серверная логика звонка. Бонус: как редактировать сообщения в чате асинхронной очередью и не словить бан от Bot API.

Часть 3 — про фокусы. Как заставить бота «звонить» — с повторными уведомлениями, как настоящий входящий вызов (спойлер: удаляем и переотправляем сообщение). Почему ссылки нужно готовить заранее — и это не про классическое «пре-генерите URL»: в обычном вебе вы кликаете, сервер обрабатывает запрос, формирует ссылку и делает переадресацию — в Telegram эта схема не работает в принципе, редиректа нет, и всю «нагрузку редиректа» приходится вычислять заранее, до клика. Как провести пользователя по продукту JSON-файлом вместо онбординг-движка: скрипт-чат, который печатает, показывает слайды и пишет воронку в аналитику.


Всё описанное написано для Telegram, но в большей части справедливо и для MAX — механика ботов, miniapp и сессий там строится по тем же принципам. Если есть желание сделать адаптацию под MAX и российские сервисы видеовстреч — велком в личку.

Потрогать сам мост: @GoosleeBot · gooslibot.com

Показать полностью 4
Отличная работа, все прочитано!

Темы

Политика

Теги

Популярные авторы

Сообщества

18+

Теги

Популярные авторы

Сообщества

Игры

Теги

Популярные авторы

Сообщества

Юмор

Теги

Популярные авторы

Сообщества

Отношения

Теги

Популярные авторы

Сообщества

Здоровье

Теги

Популярные авторы

Сообщества

Путешествия

Теги

Популярные авторы

Сообщества

Спорт

Теги

Популярные авторы

Сообщества

Хобби

Теги

Популярные авторы

Сообщества

Сервис

Теги

Популярные авторы

Сообщества

Природа

Теги

Популярные авторы

Сообщества

Бизнес

Теги

Популярные авторы

Сообщества

Транспорт

Теги

Популярные авторы

Сообщества

Общение

Теги

Популярные авторы

Сообщества

Юриспруденция

Теги

Популярные авторы

Сообщества

Наука

Теги

Популярные авторы

Сообщества

IT

Теги

Популярные авторы

Сообщества

Животные

Теги

Популярные авторы

Сообщества

Кино и сериалы

Теги

Популярные авторы

Сообщества

Экономика

Теги

Популярные авторы

Сообщества

Кулинария

Теги

Популярные авторы

Сообщества

История

Теги

Популярные авторы

Сообщества

Недвижимость и ремонт

Теги

Популярные авторы

Сообщества