cd ~кейси/kids-cafe-bot.md

кейс 02LIVE · ПРАЦЮЄ У КЛІЄНТА

Бронювання дитячого кафе в Telegram: з 3–4 до 5–7 свят на тиждень

Дитяче кафе приймало бронювання по телефону й у месенджерах. Свята, майданчик, майстер-класи: все трималось на дзвінках і переписках. Я зробив Telegram-бот, через який клієнти бронюють самі, персонал бачить розклад, а власниця сама міняє ціни й отримує нагадування та облік в одному місці. Раніше кафе мало 3–4 свята на тиждень. Зараз 5–7, і 4–5 із них бронюють через бот. Дзвінків стало менше десь на 15–20%.

Термін
~2 тижні до продакшну, ~3 тижні до передачі власникам
Стек
Python · aiogram 3 · SQLite · SQLAlchemy async · APScheduler · Telethon e2e · pytest · systemd
Виконавець
Forge Logic
5–7свят на тиждень замість 3–4
4–5з них бронюють через бот
−15–20%дзвінків
723автотести у фіналі (починав з 49)
~2 тиж.від першого рядка коду до продакшну
3ролі: клієнт, персонал, адмін
42e2e-сценарії, які ганяються прямо в Telegram (на старті було 8)
157знахідок дав перший аудит коду, далі 8 фаз рефакторингу
16фаз розробки й доробок
Бронювання дитячого кафе в Telegram: з 3–4 до 5–7 свят на тиждень0:30

Що боліло

Бронювання приходили дзвінками й повідомленнями, і повної картини зайнятості не бачив ніхто. Два великі свята з орендою всього кафе цілком могли стати на один і той самий час.

З майстер-класами своя біда. Їх часто скасовували, бо не набиралось дітей. Охочі записувались, але ніхто вчасно не повідомляв їм, що група зібралась.

Що хотіла власниця

  • Тільки Telegram. Окремий сайт і домен на старті не потрібні.
  • Ціни й пакети вона міняє сама, без програміста.
  • Тон теплий, бо пишуть батьки.

Рішення

Першим ділом бот розбирається, хто йому пише: клієнт, хтось із персоналу чи адмін. Від цього залежить, яке меню людина побачить. Чужого меню не бачить ніхто.

Telegram → визначення ролі → меню ролі → сервісний шар → SQLite. Планувальник читає ту саму базу.
  • Клієнт може забронювати майданчик, свято, майстер-клас або столик, записати день народження дитини, подивитись свої бронювання й дані. У контактах є посилання на карту.
  • Персонал бачить бронювання на сьогодні й найближчі дні та ставить позначки «виконано» або «не прийшов». Для ресепшену є QR-код бота. Потрапити в цю панель можна лише з одноразовим кодом від адміна.
  • В адмінці редагуються пакети, ціни, майстер-класи, аніматори й столики. Звідти ж видно всі бронювання, і їх можна скасувати. Там же розсилка новин тим, хто на неї погодився, статистика і журнал збоїв.
  • Між меню і базою стоїть сервісний шар, у ньому вся логіка: ціни, перевірка, чи вільний час, перевірка того, що ввів користувач. Кнопки просто викликають ці функції. Інакше одне правило довелось би писати в чотирьох місцях, і рано чи пізно копії б розійшлись.
  • База SQLite: один файл на диску, окремий сервер бази не потрібен. Одному кафе цього вистачає з головою. Тести ганяються на окремій базі й робочу не чіпають.
  • Хто записався на майстер-клас, отримує два сповіщення: коли група набралась і коли заняття проводиться.
  • Планувальник за розкладом шле нагадування за добу до бронювання і раз на рік вітає дітей з днем народження.

Історія розробки

feat(core)#01

Старт

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

fix(animators)#02

Аніматор не може бути на двох святах

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

fix(roles)#03

Кожному своє меню

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

ops(audit)#04

Аудит і рефакторинг

Після десятка фаз назбирався технічний борг. Аудит коду видав 157 знахідок, розгрібав їх вісім фаз. Чотири критичні, всі про гонки даних, закрив окремою фазою.

fix(state)#05

Старі меню після перезапуску

Після кожного перезапуску сервера в адміна в чаті висіли старі меню. Причина проста: бот тримав стан діалогів тільки в пам’яті, і перезапуск його стирав. Переніс стан у ту саму SQLite. Тепер він переживає перезапуск, а свої старі повідомлення бот прибирає сам.

fix(notify)#06

Адмін не бачив нових бронювань

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

Макет Mini App

Поверх робочого бота зібрав клікабельний макет Telegram Mini App. Сценарії ті самі, але замість ланцюжка повідомлень один екран: календар, картки, все видно одразу.

01 ГоловнаГоловна
02 Вибір пакетуВибір пакету
03 Дата й вільні годиниДата й вільні години
04 Гості й аніматориГості й аніматори
05 Фотозона й майстер-класФотозона й майстер-клас
06 ПідтвердженняПідтвердження
07 Панель персоналуПанель персоналу
Назва кафе, імена й аніматори в макеті вигадані, ціни умовні. Логіка кроків узята з робочого бота.

Що я виніс для себе

  • Понад 700 зелених тестів ще не означають, що ботом зручно користуватись. Майже всі незручності я знайшов, коли сам пройшов сценарії руками.
  • Коміт після кожної фази обов’язковий. Майже кожна фіча чіпала ядро даних, і без точки відкату один невдалий прогін з’їв би день.
  • Скоуп росте сам. Починалось як бот для бронювань, а за тиждень вийшла CRM на три ролі. Треба було в якийсь момент зупинитись і пожити з продуктом, а не докручувати ще одну фічу.

Результат

До бота кафе мало 3–4 свята на тиждень. Зараз 5–7, і 4–5 із них приходять через бот. Дзвонять менше, десь на 15–20%: бронюють тепер переважно самі. І помітно частіше повертаються.

Бот крутиться на сервері як системна служба: впав, сам піднявся. Клієнти бронюють свята, майданчик, майстер-класи й столики. Персонал бачить розклад і відмічає, хто прийшов. Адмін керує цінами, а про збої дізнається в Telegram.