MAATRIX / Блог / Telegram Mini App для записи на услуги: расписание, бронирование и VPS

Telegram Mini App для записи на услуги: расписание, бронирование и VPS

MAATRIX · 17 октября 2026 · 8 мин чтения

Два клиента одновременно выбирают свободное время на субботу. Оба нажимают «Записаться». Оба получают поздравление. В субботу выясняется, что специалист у вас один, а уверенных интерфейсов было два.

Поэтому сервис записи начинается не с красивого календаря, хотя календарь тоже нужен. Его основа — правило, по которому свободное время превращается в подтверждённую запись только для одного клиента. Telegram Mini App даёт удобное окно внутри мессенджера; расписание, проверку пользователя и защиту от двойного бронирования обеспечивает ваше приложение на сервере.

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

VPS для вашего сервиса записи

Разместите Mini App, сервер бронирования и PostgreSQL на своём VPS. Начните с пилота и проверьте одновременную запись, уведомления и восстановление базы.

Выбрать VPS для Mini App

Пусть первый маршрут помещается в голове

Клиент открывает приложение, выбирает услугу, специалиста и время, подтверждает запись и видит её номер. В разделе «Мои записи» он может проверить адрес, перенести или отменить визит по правилам сервиса.

Не заставляйте человека создавать ещё один пароль, если для вашей задачи достаточно подтверждённой Telegram-идентичности. Но не путайте удобный вход с полноценной проверкой личности для любых операций. Если услуга требует дополнительных подтверждений, добавляйте их отдельно и объясняйте причину.

В карточке времени показывайте дату, продолжительность и часовой пояс. Для удалённых консультаций полезно отобразить время клиента и исходный пояс расписания. Для очной услуги важнее адрес и местное время места приёма. Фраза «завтра в 10:00» без контекста неожиданно хорошо путешествует между городами.

На последнем экране повторите условия отмены. Клиент должен узнать их до подтверждения, а не в сообщении после неявки. Для первой версии это важнее анимации, которая торжественно превращает кнопку в галочку.

Что размещается на VPS

У проекта три основные части: веб-интерфейс Mini App, серверное API и PostgreSQL. Бот открывает приложение и, при наличии разрешения, отправляет подтверждения или напоминания. Интерфейс можно отдать как статические файлы, а API держать за HTTPS-прокси.

Создайте бота через BotFather, подготовьте публичный HTTPS-адрес приложения и настройте предусмотренный Telegram способ запуска — например, кнопку меню. Варианты открытия и взаимодействия перечислены в документации Telegram Mini Apps.

Проверьте запуск на телефоне в светлой и тёмной теме, небольшую высоту экрана и появление клавиатуры. Кнопка подтверждения не должна скрываться за нижней областью интерфейса. Если данные загружаются, покажите понятное состояние ожидания и возможность повторить запрос.

Административный интерфейс отделите от клиентского. Сотрудник редактирует смены и видит записи только после собственной авторизации с соответствующими правами. Скрытая ссылка на страницу администратора не является защитой.

Кто пришёл в приложение

Mini App получает данные запуска, но сервер не должен доверять полям, которые браузер прислал как готовую анкету. Передавайте исходную строку initData и проверяйте её подпись на сервере по алгоритму Telegram. initDataUnsafe удобно для отображения, но его название вполне честно предупреждает о границе доверия.

Дополнительно проверяйте давность auth_date, используя допустимое окно, выбранное для вашего сценария. После проверки можно выдать собственную короткую сессию приложения. Не принимайте user_id из тела запроса бронирования как доказательство того, кто делает запись.

Токен бота остаётся на сервере. Он не должен попадать в JavaScript, загружаемый клиентом, даже если файл минифицирован и выглядит достаточно загадочно. Минификация — не сейф, а способ сделать исходник менее приятным для чтения.

Сценарий проверки обязательно включает изменённое поле пользователя, старые данные запуска и отсутствие подписи. Во всех случаях сервер должен отказать до доступа к чужим записям. Положительный тест входа не проверяет защиту от подмены.

Расписание должно существовать отдельно от бронирований

Для фиксированной длительности заранее создайте слоты: специалист, начало, конец, доступность. Клиент получает только те, которые разрешены к записи сейчас. Отпуск, перерыв и уже занятое время исключаются по серверным правилам.

Храните момент времени в базе однозначно, например в timestamptz, а часовой пояс расписания — отдельным параметром. Для повторяющихся смен формируйте слоты в выбранном поясе, учитывая календарные особенности. Не прибавляйте механически одинаковое число секунд к локальному времени на месяцы вперёд без проверки переходов времени там, где они существуют.

Администратор должен видеть последствия изменения расписания. Если на время уже записан клиент, удаление смены не должно молча удалять его визит. Сначала согласуется перенос или отмена, затем освобождается место.

Для разных длительностей услуг задача сложнее: два слота с разным началом могут пересекаться. Уникальность одного времени начала этого не предотвращает. В первой версии ограничьте услуги одинаковой длительностью и непересекающимися заранее подготовленными слотами; позже можно перейти к проверке интервалов.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США и РФ. Оплата картой РФ и по СБП.

АРЕНДОВАТЬ СЕРВЕР

Защита от двойной записи живёт в базе

Проверка «слот свободен» перед вставкой недостаточна: между проверкой и записью может успеть другой запрос. Нужна гарантия базы. Для нашей модели один подтверждённый визит занимает один слот.

Упрощённая схема выглядит так:

CREATE TABLE booking_slots (
  id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  resource_id bigint NOT NULL,
  starts_at timestamptz NOT NULL,
  ends_at timestamptz NOT NULL,
  CHECK (ends_at > starts_at),
  UNIQUE (resource_id, starts_at)
);

CREATE TABLE bookings (
  id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  slot_id bigint NOT NULL REFERENCES booking_slots(id),
  customer_id bigint NOT NULL,
  status text NOT NULL CHECK (status IN ('confirmed', 'cancelled')),
  created_at timestamptz NOT NULL DEFAULT now()
);

CREATE UNIQUE INDEX one_confirmed_booking_per_slot
  ON bookings(slot_id) WHERE status = 'confirmed';

Это основа учебной модели, без оплаты, временного удержания и полного справочника клиентов. customer_id определяет сервер после авторизации. Смысл ограничений описан в документации PostgreSQL; частичный уникальный индекс применяет правило к выбранным строкам.

При бронировании сервер проверяет доступность и срок слота, затем в транзакции создаёт запись. Нарушение уникальности обрабатывается как понятный конфликт: «Это время только что заняли, выберите другое». Не возвращайте клиенту текст SQL-ошибки.

Добавьте ключ повторного запроса. Если мобильная связь оборвалась после записи, повтор нажатия должен вернуть уже созданное бронирование, а не заставить человека гадать, получилось ли. Отключённая кнопка помогает интерфейсу, но серверная идемпотентность всё равно нужна.

Подтверждение в базе важнее уведомления

Сначала зафиксируйте бронирование, затем поставьте уведомление в очередь отправки. Если Telegram временно недоступен, запись должна оставаться видимой в «Моих записях». Ошибка уведомления не должна удалять визит автоматически.

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

Напоминания связывайте с текущим состоянием брони. Перед отправкой ещё раз проверьте, что визит не отменён и не перенесён. Иначе автоматизация будет уверенно приглашать человека на время, которое сама же вчера освободила.

Удобно хранить журнал уведомлений с ключом «запись — тип напоминания — версия времени». Он помогает предотвращать дубли и разбираться в повторных попытках. При переносе старая задача отменяется или становится неактуальной по этому ключу.

Отмена и перенос заслуживают отдельного сценария

Клиент может отменить только собственную запись и только в рамках объявленных условий. Сервер проверяет права и допустимость действия заново, даже если кнопка была показана несколько минут назад. Время могло измениться, а правило отмены — уже перестать выполняться.

Перенос лучше оформлять одной согласованной операцией: новое место занято, старое освобождено. Если новое время успели забронировать, прежняя запись должна сохраниться. Последовательность «сначала отменить, затем попробовать записать» оставляет человека без обоих вариантов при ошибке.

Сотруднику также нужен журнал изменений: кто перенёс визит, когда и по какой причине. Для спорной ситуации это полезнее воспоминаний о том, что «вроде нажимали на четверг».

Если позже добавляется предоплата, появляется отдельное состояние ожидания оплаты и срок удержания. Подтверждать платёж нужно по проверенному серверному уведомлению платёжной системы, а не по возврату пользователя на красивую страницу успеха.

Как принять первую версию

Откройте один слот на двух телефонах и одновременно подтвердите запись. Успешной должна оказаться одна попытка. Затем повторите запрос победителя с тем же ключом: он должен получить прежний результат.

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

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

Ресурсы для пилота на MAATRIX

Для небольшой системы записи с API и PostgreSQL можно начать испытания на Uab Start: 2 vCPU, 4 ГБ памяти и 80 ГБ диска. При сложном интерфейсе, дополнительных обработчиках и большей нагрузке стоит проверить Heka Standard с 4 vCPU и 8 ГБ. Это ориентиры для пилота; число обслуживаемых клиентов зависит от реализации и измерений.

Mini App размещается как ваше веб-приложение и настраивается самостоятельно. Готовая установка Telegram-бота не превращается автоматически в календарь с бронированием. Резервируйте базу, храните секреты отдельно и проверяйте восстановление на копии.

Первая версия может быть внешне простой. Если она не теряет записи, не обещает занятое время и позволяет человеку спокойно отменить визит, у неё уже есть самое важное качество сервиса: на её подтверждение можно положиться.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США и РФ. Оплата картой РФ и по СБП.

АРЕНДОВАТЬ СЕРВЕР

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →