cd ~cases/kids-cafe-bot.md

case 02LIVE · RUNNING AT THE CLIENT

Kids' café bookings in Telegram: from 3–4 to 5–7 parties a week

A kids' café took bookings by phone and in messengers. Parties, the playground, workshops: everything ran on calls and chats. I built a Telegram bot where clients book by themselves, staff see the schedule, and the owner changes prices herself and gets reminders and records in one place. The café used to have 3–4 parties a week. Now it's 5–7, and 4–5 of them are booked through the bot. Calls dropped by roughly 15–20%.

Timeline
~2 weeks to production, ~3 weeks to handover
Stack
Python · aiogram 3 · SQLite · SQLAlchemy async · APScheduler · Telethon e2e · pytest · systemd
Built by
Forge Logic
5–7parties a week instead of 3–4
4–5of them booked through the bot
−15–20%phone calls
723automated tests at the end (started with 49)
~2 wksfrom the first line of code to production
3roles: client, staff, admin
42e2e scenarios that run right inside Telegram (8 at the start)
157findings from the first code audit, then 8 refactoring phases
16development and polishing phases
Kids' café bookings in Telegram: from 3–4 to 5–7 parties a week0:30

What was broken

Bookings came in by phone and messages, and nobody saw the full picture of what was taken. Two big parties renting the whole café could easily land at the same time.

Workshops had their own problem. They were often cancelled because not enough kids signed up. People did sign up, but nobody told them in time that the group had filled.

What the owner wanted

  • Telegram only. No separate website or domain at the start.
  • She changes prices and packages herself, without a developer.
  • A warm tone, because it’s parents writing.

The solution

The first thing the bot does is figure out who’s writing: a client, someone from staff, or the admin. That decides which menu the person sees. Nobody sees anyone else’s menu.

Telegram → role detection → role menu → service layer → SQLite. The scheduler reads the same database.
  • A client can book the playground, a party, a workshop or a table, register a child’s birthday, and check their bookings and details. Contacts include a map link.
  • Staff see bookings for today and the next few days and mark them “done” or “no-show”. There’s a QR code of the bot for the reception desk. You can only get into this panel with a one-time code from the admin.
  • The admin panel is where packages, prices, workshops, animators and tables are edited. All bookings are visible there and can be cancelled. It also has newsletters for those who opted in, stats and an error log.
  • Between the menus and the database sits a service layer holding all the logic: prices, checking whether a slot is free, validating what the user typed. Buttons just call these functions. Otherwise one rule would have to be written in four places, and sooner or later the copies would drift apart.
  • The database is SQLite: one file on disk, no separate database server needed. For one café that’s more than enough. Tests run on a separate database and never touch the live one.
  • Anyone who signs up for a workshop gets two notifications: when the group has filled and when the class is on.
  • A scheduler sends reminders a day before a booking and once a year wishes the kids a happy birthday.

Development story

feat(core)#01

Kick-off

The owner had no ready picture of how it should work. So we started with a spec: went through everything that hurts right now, decided what the bot should do, and built the skeleton from that.

fix(animators)#02

An animator can't be at two parties

An animator physically can’t be at two parties at once, even when the café isn’t fully rented. The first version of the picker came out clumsy: either take every animator or cancel the booking. I redid it. Now the choice is per slot, there’s a “Don’t choose” button, and anyone busy at that time simply isn’t in the list.

fix(roles)#03

Everyone gets their own menu

The admin and staff saw the client menu on top of their own. I made one function that detects the role at entry, and now everyone sees only their own panel.

ops(audit)#04

Audit and refactoring

After a dozen phases, technical debt had piled up. The code audit came back with 157 findings, and it took eight phases to work through them. The four critical ones, all about data races, I closed in a separate phase.

fix(state)#05

Old menus after a restart

After every server restart, old menus were hanging in the admin’s chat. The reason was simple: the bot kept dialog state only in memory, and a restart wiped it. I moved the state into the same SQLite. Now it survives restarts, and the bot cleans up its old messages itself.

fix(notify)#06

The admin didn't see new bookings

New-booking notifications weren’t reaching the admin. It turned out the notification logic knew about the owner and staff and simply forgot about the admin. Fixed.

Mini App mockup

On top of the working bot I put together a clickable Telegram Mini App mockup. Same flows, but instead of a chain of messages it’s one screen: calendar, cards, everything visible at once.

01 HomeHome
02 Choosing a packageChoosing a package
03 Date and free hoursDate and free hours
04 Guests and animatorsGuests and animators
05 Photo zone and workshopPhoto zone and workshop
06 ConfirmationConfirmation
07 Staff panelStaff panel
The café name, people and animators in the mockup are made up; prices are illustrative. The step logic comes from the working bot.

What I took away

  • Over 700 green tests don’t mean the bot is comfortable to use. Almost every inconvenience I found by walking through the flows by hand myself.
  • A commit after every phase is a must. Nearly every feature touched the data core, and without a rollback point one bad run would have eaten a day.
  • Scope grows by itself. It started as a booking bot, and a week later it was a CRM with three roles. At some point I should have stopped and lived with the product instead of bolting on one more feature.

Result

Before the bot the café had 3–4 parties a week. Now it’s 5–7, and 4–5 of them come through the bot. People call less, by roughly 15–20%: they mostly book on their own now. And they come back noticeably more often.

The bot runs on a server as a system service: if it falls over, it gets itself back up. Clients book parties, the playground, workshops and tables. Staff see the schedule and mark who showed up. The admin manages prices and hears about failures in Telegram.