2026 · Дизайн + инженерия
Deutsch mit Seele
CRM школы внутри Telegram — заявки, переписка, рассылки и аналитика в одном Mini App

Контекст
Частная школа немецкого языка, которую ведёт одна преподавательница. Раньше всё жило в её личных чатах: запросы, тесты уровня, заявки на пробное занятие, вопросы о ценах — вперемешку с перепиской, без всякой возможности увидеть, кто до сих пор ждёт ответа. Продукт — клиентский бот на четырёх языках и полноэкранный Telegram Mini App к нему: CRM лидов с папками, статусами и тегами, полная история переписки с ответами от имени бота, заметки, отложенные и регулярные рассылки, редактор всех текстов бота и дашборд воронки. Дизайн, фронтенд, бэкенд, база и передача владелице — из одних рук.
Задача
Сделать рабочую бизнес-систему для человека без технического бэкграунда, который управляет ею только с телефона. Каждый экран обязан жить на 320 пикселях внутри интерфейса самого Telegram. Владелица должна менять любое слово бота — на четырёх языках, без разработчика и без деплоя. Рассылка должна дойти до всей аудитории, не упершись ни в лимиты Telegram, ни в ограничения времени serverless-функции. А сам бот должен ощущаться личным: тест уровня, принимающий ответы текстом, голосом или видео, подбадривающий, пока ждёт, и заявки, которые приходят структурированными лидами, а не россыпью сообщений.
Сделано
Next.js 16 + React 19 + TypeScript на Vercel, grammY для обоих ботов, Postgres на Neon с Drizzle ORM и миграциями, Zod на каждой границе, дизайн-токены Tailwind v4, TanStack Query в панели. Приём вебхуков идемпотентный — Telegram ретраит при таймауте, поэтому таблица дедупликации не даёт ответить лиду дважды. Рассылка идёт через очередь Upstash QStash пачками с паузами под пропускную способность Telegram, по снимку получателей на момент запуска, чтобы написавший посреди рассылки не получил случайное сообщение; регулярные запуски — cron-правила с честной оговоркой про переход на зимнее время. Медиа не касается собственного хранилища: файлы проходят через приватный Telegram-канал, потому что file_id принадлежит тому боту, который его загрузил — то самое ограничение, из-за которого кружочек доходит квадратным видео, если не перезалить его правильным методом. Тексты бота живут в базе за шестидесятисекундным кешем с вшитым в код запасным вариантом: правка доходит до бота в течение минуты, а сломанная база не оставляет бота немым. Панель — полноэкранный Mini App: проверка подписи initData, роли владельца и администратора, безопасные зоны, светлая и тёмная темы с семью акцентами, запись голосовых и вложения от имени бота.
Клиентская часть, на четырёх языках. Пройдитесь по меню так, как это сделала бы ученица — тексты настоящие, владелица правит их из панели.