Case · Booking platform · Warsaw · 2026
The studio that left the marketplace
A Warsaw beauty studio needed its own booking system instead of a marketplace listing. I designed the data model, built the backend and the client, and shipped a product the owner runs every day.
11 weeks
from spec to production
79
test files
24
database migrations
4
interface locales
Why the studio wanted out
The studio ran its bookings through a marketplace app, and the arrangement had worn thin in two ways: features the owner needed that the platform did not have, and booking behaviour that kept producing problems at the front desk. Owning the system meant the schedule rules, the languages and the policies could finally match how the studio actually works.
The decision I count as the main one
Double booking in a scheduling system is not a rare bug — it is a matter of time. Two clients open the same slot at the same moment, and whichever check runs in application code eventually loses that race.
So the check does not live in application code. A GiST exclusion constraint
in Postgres forbids overlapping confirmed bookings for the same master at
the schema level, and the btree_gist extension it needs was enabled in
the very first migration — concurrency was part of the data model, not a
patch. The application cannot bypass it, even if I get the slot logic
wrong.
Where I got it wrong
The first version of sign-in used a magic link. It worked on desktop — and quietly broke in the installed PWA, where the link from the email opened the browser and the session landed outside the app. The user came back to an app that still considered them logged out. I replaced it with a six-digit code, entered in the same place where sign-in began.
The main flow got reversed too. Originally a client picked a master first, then a service — and ran into the fact that new clients do not know the masters by name. Now it is service first, then master, then time.
Clients choose what they want done first. Who does it is the second question — and the answer is often "whoever is free".
What I deliberately did not do
There is no online payment, and none is planned — the owner's decision: clients pay at the studio, and no-shows are handled by an automatic ban past a threshold. There is no CI: this is a solo project, the checks run locally, and at this scale a pipeline would add ceremony without adding safety.
Six known behavioural gaps are written down in tests/_TODO_BUGS.md
instead of being quietly forgotten — for instance, the walk-in client
lookup is capped at the first 200 users and will fail silently past that.
Documented limits beat discovered ones.
Nuxt 4 · Vue 3 · Supabase · PostgreSQL · Vercel