Практическое руководство

Как спроектировать онлайн-запись и бронирование

Как спроектировать онлайн-запись и бронирование: доступность, временное удержание, подтверждение, отмена и часовые пояса. Как проверить конкурирующие запросы.

Материал WebexlabПодготовлено 6 мин чтения

Краткий ответ

Онлайн-запись требует единого правила доступности ресурса и атомарного подтверждения брони. Свободный слот на экране ещё не гарантирует возможность записи: между просмотром и подтверждением его может занять другой человек. Для удержания, оплаты, отмены и повторов нужны отдельные состояния.

Определите ресурс и вместимость

Бронировать можно время специалиста, помещение, оборудование или место в группе. У каждого ресурса свои ограничения. Один специалист не может вести два приёма одновременно, а группа допускает несколько участников до установленной вместимости. Модель должна отражать реальную единицу ограничения.

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

Разделите отображение и подтверждение

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

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

Карта состояний

Карта состояний — сравнение
СостояниеЗначениеЧто требуется определить
ДоступноРесурс можно запроситьИсточник и актуальность
Временно удержаноИдёт завершение записиСрок и освобождение
ПодтвержденоЗапись принятаИдентификатор и уведомление
Ожидает оплатыУсловия ещё не выполненыДедлайн и связь с бронью
ОтмененоЗапись прекращенаВозврат доступности

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

Продумайте время и календарь

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

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

Обработайте повтор и потерянный ответ

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

Документация Stripe показывает один технический вариант такого контракта. Это не универсальный рецепт для расписания: срок ключа, повтор с изменёнными параметрами и поиск результата проектируют для выбранной системы.

Согласуйте оплату и отмену

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

Условия отмены и возврата должны быть согласованы владельцем услуги и отражены в интерфейсе. Техническая статья не задаёт универсальных коммерческих или правовых правил. Система реализует конкретные утверждённые условия и сохраняет понятную историю изменений.

Проверки до пилота

  • Два пользователя одновременно выбирают последний доступный слот.
  • Удержание истекает при открытой и закрытой странице.
  • Повторяется запрос после потери ответа.
  • Уведомление приходит повторно или с задержкой.
  • Изменяется расписание с уже существующими бронями.
  • Пользователь отменяет запись и проверяет итоговый статус.

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

Сценарий одновременного бронирования

Создайте в тестовом расписании один доступный ресурс на определённое время и откройте его двумя пользователями. Оба видят свободный слот. Затем отправьте подтверждения так, чтобы запросы конкурировали. Ожидаемый результат зависит от вместимости: для единичного ресурса подтверждается только допустимая запись, второму пользователю объясняется изменение доступности.

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

Повторите упражнение с потерей ответа победившему пользователю. Повторный запрос должен позволить безопасно узнать результат. Затем проверьте отмену и появление доступности для следующей записи. Так проверяется весь цикл ресурса, а не отдельная операция создания.

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

Почему одинакового времени начала недостаточно

Проверка уникальности пары «ресурс + начало» не выявит все пересечения. В учебном расписании кабинет занят с 10:00 до 11:00, а следующая заявка начинается в 10:30. Время начала разное, но обязательства конфликтуют. Для услуг разной длительности проверяют весь занятый интервал, включая согласованный перерыв на подготовку.

Почему одинакового времени начала недостаточно — сравнение
Запрос при занятом кабинете А с 10:00 до 11:00Ожидаемое решение
Кабинет А, 10:30–11:30Отказ из-за пересечения
Кабинет А, 11:00–12:00Допустимо, если между приёмами нет обязательного перерыва
Кабинет Б, 10:30–11:30Допустимо, если нет других общих ограничивающих ресурсов

Все интервалы примера относятся к одной дате и одному явно указанному часовому поясу. Конец интервала считается свободной границей. Если после приёма нужен перерыв 15 минут, первый кабинет фактически занят до 11:15, и начало в 11:00 становится недопустимым. Такое правило должно одинаково применяться в календаре и при подтверждении.

В документации PostgreSQL 17 показано ограничение EXCLUDE для непересекающихся диапазонов, в том числе по одному помещению. Это пример механизма для единичного ресурса. Групповая вместимость, несколько связанных ресурсов, удержания и отмены требуют собственной модели; одного ограничения из документации недостаточно для готовой системы записи.

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

Термины из материала

Источники и документация

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

Следующий шаг

Применить к вашему проекту

Поможем описать состояния записи и проверить поведение при одновременных запросах.

Обсудить задачу
Все материалы блога