THE PROBLEM
A booking app with someone else's name on it
Most small businesses take bookings by phone and text, or send customers to a booking app's page. That page looks like the app rather than the business, asks little about the job itself, and knows nothing about the jobs the owner booked by phone, which is how the same hour gets sold twice.
So we built our own, once, to sit on each business's own website and work the way a service business works.
WHAT IS BUILT
Three parts on one calendar, and the rules they keep
FOR CUSTOMERS
- A service, a day and a time, then their details and up to five photos of the job.
- Where the work happens decides the times: at the customer's place offers arrival windows, at the business offers exact times, and a call is booked as a call.
- A confirmation email with a calendar invite, sent in the business's own name.
ON THE BUSINESS'S OWN SITE
- One line of code puts it on the business's website, in a frame that fits what is inside it.
- Only on the sites the business lists. Anywhere else, a plain "Book online" link takes its place.
- It stays light even on a phone in dark mode, so it matches the page around it.
FOR THE OWNER
- Today: the day as one strip, a new online booking highlighted, the booking now or next, then the day in order with open stretches and blocked time.
- A booking's own screen: call, text, email or directions in one tap, the photos, and whether they booked before.
- Block time, add a job taken by phone, and see the week.
- An alert for every booking, photos included, with a calendar invite so it lands on their phone's calendar.
RULES THAT HOLD
- Double bookings are refused by the database, not only checked on screen, and each time is checked again as it saves.
- One to twenty identical spots (bays, chairs, crews): each booking is given a spot, and one more than the business has is refused.
- Limits per person, never per business: three bookings a day per phone or email, five an hour per connection, and a bot check that refuses when it cannot check.
- The owner edits the wording of the confirmation, never the booking details in it.
HOW IT FLOWS
From a tap on the website to the owner's calendar
Nobody types anything twice, and nobody has to approve a booking that fits the rules.
- Picks a serviceUp to three services, each saying where the work happens.
- Picks a timeOnly times with a free spot are offered.
- Details and photosName, a way to reach them, the address when it matters, and photos.
- Checked againThe time is re-checked as it saves; a clash is refused.
- Customer confirmedAn email with the details and a calendar invite.
- Owner alertedAn email with the photos and an invite for their own calendar.
- On TodayIt appears in the owner's day, marked as new.
- The jobThe owner calls, texts or drives there from the booking's screen.
Runs on its ownA person does it
HOW IT IS TESTED
Tested before anyone books on it
- 258unit tests, run under four different server time zones
- 154checks in a real browser, as staff, owners and customers
- 3 into 2bookings fired at once into two spots, five rounds; a third never gets in
- 2screen sizes for every owner screen: a phone and a computer
Test emails go only to a test address, and the tests never book on a real business. Left before the first client: moving, cancelling and marking a job done, installing the owner's screens on a phone, the customer's own page to manage a booking, address suggestions as they type, and putting it live.
WHAT I DID
What I did
What a booking must have, what refuses it, and the limits that stop abuse without blocking customers.
Mocked up first and approved before building, phone first for the owner.
Double bookings refused in the database itself, with a lock so two people taking the last spots both get one.
The booking flow, the frame that fits any site, and the fallback link everywhere else.
Confirmations and alerts with calendar invites, in the business's name, with wording the owner can edit.
258 unit tests and 154 browser checks, including bookings fired at the same moment.
BUILT WITH
Built with
- Next.js
- TypeScript
- Tailwind CSS
- Supabase (Postgres, row-level security)
- Resend
- Cloudflare Turnstile
- Playwright
- PGlite
- Claude Code