Showtime — Cinema Seat Booking
Cinema ticket booking with five-minute seat holds: a Ktor API on PostgreSQL and a Flutter app. When two people tap the same seat at the same instant, exactly one of them gets it.

See it running
The problem
Listing films and tapping seats is the easy half. A ticketing system lives or dies on the hold: picking a seat reserves it for five minutes while you pay. Two people tapping the same seat must not both get it, an expired hold must free its seat even if a background job has died, and confirming a hold that lapsed a millisecond ago must fail before any money moves.
How it’s built
A unique index over unreleased holds makes the database settle every race: the second insert simply collides. Taking a hold first releases lapsed holds in the same transaction, and availability compares the expiry with the database clock, so a seat comes back the instant its hold runs out, with no sweeper. Confirmation checks expiry inside the insert itself, and a unique constraint on booked seats is the final guard. In the app, the countdown runs against the server’s deadline rather than the phone’s clock, and “someone else has those seats”, “your hold ran out” and “the server did not answer” are three different messages.
What it does
- Twenty threads racing for one seat: exactly one hold
- Expired holds free their seats instantly, with no background job
- A lapsed hold cannot be confirmed, so no one pays for a seat they do not have
- Available, selected, held by someone and booked: four seat states shown at once
- Booked end to end on an Android emulator against the live API
Learn to build software like this
The free courses teach the same craft — from the basics to a real, running project.







