Skip to content
sp1le.tech
UA
Running 2026 Telegram commerce, real business

Tandyr

A food business that takes orders two ways: inside Telegram as a Mini App, and from a plain website for people who will never install a messenger to buy dinner. One catalogue, one order pipeline, one place for staff to work - which happens to be the Telegram they already have open.

FastAPI · aiogram 3 · React · SQLite Open it · tandir.top

Constraint

The customer is a kitchen, not a tech company. Orders must arrive whether the buyer is in Telegram or on a web page, the staff side has to be usable from a phone mid-shift, and nobody there will ever open a terminal.

Decisions

  • 4 records
  • each with its bill

Decision record

One FastAPI backend serving both the Mini App and the public site

Instead of
A separate website and a separate bot
Because
Two codebases mean two catalogues drifting apart, and the kitchen would have to edit prices twice. They edit once.
Costs me
Web checkout has no Telegram user id, so identity had to become optional throughout the order model instead of assumed.

SQLite with FTS5 for catalogue search

Instead of
Postgres, or a dedicated search service
Because
One location, a catalogue of tens of items, a handful of concurrent shoppers. FTS5 is already inside the file and answers instantly, with nothing extra to run or back up.
Costs me
The day they open a second location and need concurrent writers, this is the first thing I replace. I would rather replace it then than run Postgres for one kitchen now.

Discounts are scoped rules - one product, a category, or everything - and the most specific rule wins

Instead of
Editing prices by hand for every promotion
Because
A kitchen runs promotions constantly and forgets to roll them back. A rule with an on/off flag is reverted by flipping it, not by remembering twenty prices.
Costs me
Two overlapping rules of the same scope resolve by the larger percentage. That is a policy I chose for them, and it has to be explained every time a 15% and a 20% promotion collide.

Staff work through a Telegram FSM dialogue

Instead of
A web admin panel
Because
An admin panel is a new thing to teach, a new login to lose and another screen to keep responsive. Telegram is already open on their phone and already authenticated.
Costs me
Anything table-shaped - a monthly report, a bulk price edit - is genuinely awkward in a chat and has to leave the bot.

Numbers

  • measured, not rounded

Size of the thing

4 213
lines, backend
21
backend modules
15
Mini App screens
2
order entry points, one pipeline

Stack

  • FastAPI
  • aiogram 3
  • React
  • Vite
  • SQLAlchemy
  • SQLite FTS5
  • systemd
  • nginx

Retro

  • written after, not before

What I would change

The public site came after the Mini App, and the schema still shows the order in which things happened: orders.telegram_id is nullable and every order carries a source of telegram or web, but users and carts are keyed by a Telegram id. A web buyer can place an order and cannot have a cart or a history. That is a real seam, not a cosmetic one. Starting again, the account model would be identity-agnostic from the first migration instead of Telegram-first with a web exception bolted on.

Next

Contact

  • Full-cycle software engineer

Start a conversation

Tell me what you are building and what is in the way. I answer personally, usually the same day.