Задача

У клієнта — 4 квадроцикли на прокат. Раніше бронювання йшло через дзвінки й переписку в Telegram: клієнт питає час, адміністратор дивиться в блокнот, іноді два людини домовляються на один і той самий квадроцикл одночасно. Один такий збіг на місці — і хтось із клієнтів приїжджає даремно.

Задача була прибрати людський фактор із самого моменту бронювання: людина сама обирає час у застосунку, а система гарантує, що на цей слот більше ніхто не забронює той самий квадроцикл.

Все бронювання — на одному екрані

Головний екран мініаппа одразу показує адресу, графік роботи (09:00–19:00) і кнопку «Забронювати». Без окремих сторінок і переходів — вибір кількості квадроциклів, доп. пасажирів, тривалості, дати й часу зібраний в один екран, який рахує суму наживо, поки людина клацає варіанти.

Доступний час рахується не по «плюс-мінус», а по реальному розкладу: система бере графік роботи, вже існуючі брони на цю дату й показує тільки ті проміжки, де фізично вистачає вільних квадроциклів на заявлену кількість. Обрали 2 квадроцикли на годину — бачите тільки слоти, де вільні саме 2, а не «десь є один».

Далі — контактні дані й підсумок замовлення на тому ж екрані. Поля імені й телефону на фото навмисно замазані чорним — це реальна форма з тестовими даними, які ми не публікуємо.

Головне: бронь не можна перехопити

Ось тут і вирішувалась початкова проблема. Коли людина натискає «Оформити», квадроцикл на цей слот миттєво стає недоступним для всіх інших — це так званий soft-reserve. Але недоступним не назавжди: на оплату дається обмежений час (5 хвилин), і поки він не сплив, у застосунку клієнта тане живий таймер зі статусом «Очікує оплату».

Якщо людина встигла оплатити — бронь підтверджена, квадроцикл закріплений. Якщо ні — таймер згорає, слот автоматично звільняється і повертається в загальний розклад, ніби брони й не було. Це прибирає одразу дві проблеми: і подвійні бронювання неможливі, і слоти не «зависають» назавжди зайнятими через людей, які просто передумали посеред оформлення.

Окремо — захист від зловживань: одна людина не може наплодити купу «підвислих» броней поспіль, кількість спроб за добу обмежена.

Так виглядає підтверджена й оплачена бронь у клієнта: дата, час, кількість квадроциклів і пасажирів, сума — і зелений бейдж «Підтверджено» замість непевного «ну ми вас записали, здається».

Оплата і сповіщення

Оплата — LiqPay, прямо у вікні Telegram, без переходу на сторонні сайти. Після оплати статус брони оновлюється сам, клієнт бачить підтвердження у «Моїх бронюваннях», а власнику прилітає сповіщення в Telegram — без потреби постійно перевіряти адмінку вручну.

Адмінка, де видно все за секунду

У власника — окрема панель: список броней на день, скільки заброньовано, скільки вже оплачено, і загальний дохід за день одним поглядом. Картка кожного замовлення показує ім'я, телефон, статус оплати й склад замовлення. Туди ж можна вручну додати бронювання — наприклад, якщо клієнт подзвонив, а не писав через застосунок.

Ім'я й телефон клієнта на фото так само замазані — у реальній адмінці власник бачить їх повністю, тут ми просто не публікуємо чужі контакти.

Технічна частина, коротко

FastAPI + SQLAlchemy + PostgreSQL на Railway, Telegram Mini App із перевіркою справжності init-data (щоб застосунок не можна було відкрити в обхід Telegram і підмінити дані), LiqPay з перевіркою підпису колбека, підготовка під синхронізацію із Google Calendar. Секрети — тільки у змінних оточення.

Результат

Клієнт отримав систему бронювання, яка сама стежить за тим, щоб один квадроцикл не здали двічі, сама рахує ціну під будь-яку комбінацію квадроциклів і пасажирів, і сама показує власнику, що взагалі відбувається за день — без блокнота і без плутанини в переписці.