✍️
Louis Roa
BlogProjects
✍️
Louis Roa
PrivacyTermsContact
✍️
Louis Roa
BlogProjects
API/Backend

How I "vibe coded" a booking app

CreatedJuly 3, 2025
MaintainerLouis Roa
How I "vibe coded" a booking app

You don’t need to be a developer to ship software. Pick a problem, an AI assisted IDE, and the courage to build without asking for permission.

Technologies

Python
FastAPI
Google OR-Tools
FastMCP

Status

In Progress

There’s been a lot of noise lately about “vibe coding”. Open Cursor, spin up an agent, describe what you want, and let the AI figure out the code. The term came from Andrej Karpathy back in Feb 2025 and has since been memed into “word of the year” territory.

The amount of AI assist you receive is clearly some kind of a slider. All the way on the left you have programming as it existed ~3 years ago. All the way on the right you have vibe coding.


I work with devs all day. I get why “vibe coding” makes them twitch.

From a traditional engineering mindset, it sounds reckless: fuzzy requirements, half-baked prompts, no proper spec. It’s basically the exact anti-pattern they’re trained to avoid.

That mindset makes sense if you’re a seasoned dev.

I’m not.

I’m someone who wants to solve a real problem with code, without obsessing over frameworks, patterns, or whether an architect would approve my folder structure. If it works, I’m happy.

So I decided to put vibe coding to the test.

And so it happens, I had the perfect problem in mind.

The booking problem

A close friend runs an all-ladies spa. Bookings are chaos.

You’ve got quick one-off services: “late afternoon massage, done.” Friends coming in together for matching nails. Full “treat yourself” days: hair, nails, massage, facial.

And so on…

And all of it is handled the usual way: WhatsApp, DMs, phone calls, spreadsheets, memory. It’s human and personal… and completely unsustainable.

The obvious alternative is an online booking system.

Broadly speaking, there are three options:

  1. Use an off-the-shelf giant like Mindbody or Fresha. Easy to start, but you don’t own the data, they take a cut, and you’re stuck inside their flow.

  2. Build a custom booking app. Great in theory. In practice, it takes months of dev work, a proper budget, and a lot of back-and-forth with engineers.

  3. Vibe code it. Use AI, move fast, accept that you’ll break things, and see how far a non-dev can get before they lose their mind.

Picked option 3 for the plot.

Planning

Do you start with frontend? Backend? Both?

Short answer: I asked ChatGPT.

Predictably, the advice was: start with a clear spec. Fair. The problem is I didn’t actually know what a “good spec” looked like. Enter Spec Kit: a tool that turns messy requirements into something that looks less like a brain dump and more like a plan.

Be mindful that you don’t just run it once and hand it blindly to a coding agent, but it gives you a solid baseline: clearer requirements, tech stack hints, constraints, and structure.

From there, Phase 1 became obvious a little bit clearer.

Phase 1: Database + API

After a few iterations (and burning through a few Deep Research credits), the starting point crystallized:

  • Design a db schema that closely models the reality of my friend’s spa.

  • Build an API backend that can handle that complexity.

I went with Postgres for the database.

The schema covers services, professionals, skills, rooms, timeslots, holds, bookings, payments. Everything you’d expect a real spa to care about. Once that clicked, I moved on to the API.

Stack: Python + FastAPI

If it’s good enough for OpenAI, it’s good enough for me.

But the interesting part isn’t FastAPI. It’s what’s doing the real work underneath: Google’s CP-SAT solver.

That’s where it all starts to feel like cheating.

The math behind “what time works?”

When you think “booking system,” you picture a calendar showing free slots.

In reality, a serious scheduler has to juggle:

  • Services with different durations and requirements. Some can overlap; some absolutely can’t.

  • Professionals with specific skills. Sarah can do a deep tissue massage, but not a particular facial.

  • Rooms and equipment. Some rooms can host two people, some one; some services need specific setups.

  • Groups. Friends or couples who want services together or in sync.

  • Itineraries. Multi-step experiences that must happen in a valid order, inside working hours, without clashes.

Try brute-forcing that with nested if/else and you’re in spaghetti town.

Constraint Programming (CP) fixes this. Instead of manually calculating every possibility, you describe the rules and let the solver search for valid solutions.

In my friend’s words (he explains it better):

“CP tackles NP-hard problems by aggressively pruning impossible options, checking integer-based constraints efficiently, and mapping one hard problem into another (like turning bookings into a Traveling-Salesman-style formulation).”

In theory, it’s heavy. In practice, with the constraints at spa-scale, it’s fast enough.

All of this collapses into one critical endpoint

/availability

Given a date, a set of selected services, optional preferred professionals, existing bookings, and the rest of the rules, the solver returns feasible time windows that respect everything.

The backend runs in a container on Google Cloud.

Simple. Clean. Mathy. Beautiful.

Phase 2: Frontend (after getting it wrong first)

Confession: my first attempt was to build everything in v0 with Next.js and Supabase before the backend logic was solid. Pure vibes. No spine.

Yeah… it did not work.

However, once the backend was real, the frontend became obvious.

One of the unsung heroes in this process: Swagger / OpenAPI. Autogenerated API docs are perfect when you’re working with AI agents.

My loop in Cursor looked something like this:

  • Feed the OpenAPI spec to a “frontend” agent (preferably sonnet4.5-thinking).

  • Let it scaffold UI components wired to live endpoints.

  • When something broke (“/hold needs extra fields”), I’d:

    • Ask it to draft a backend change.

    • Paste that into a “backend” agent (preferably gpt5-codex).

    • Implement, test, deploy.

    • Tell the frontend agent to try again.

Rinse, repeat.

v0 by Vercel ended up being the easiest way to turn backend reality into a usable UI. Paired with shadcn/ui, it stayed minimal, fast, and didn’t fight the rest of the stack.

Again, a strong backend made the frontend feel almost trivial.

The four steps to full relaxation

From a guest’s perspective, it’s dead simple.

They pick services. The UI is powered directly by /services, so durations, prices, categories, everything comes from the source of truth.

Pardon my Spanish

They pick a professional (or don’t). If they care, they choose. If not, CP-SAT quietly optimizes in the background.

Auto-match = CP-SAT


They pick a time. With date + services + preferences set, the app calls /availability. Behind the scenes, the solver considers existing bookings, rooms, rules, workloads. On the screen, the guest just sees valid start time options.

All boils down to an array of starting times.


They confirm & pay. This part is still evolving, but one feature I love is the hold flow:

When a guest confirms details, the system:

  • Creates a hold via /hold, reserving the slot for a limited time.

  • Generates a unique payment link.

If someone else is paying (bless them), you just send them the link.

POST /hold – locks in the tentative booking while payment is processed.


Backend logs it all. Frontend just shows “Booking Confirmed ✨”.

Confirmation Screen. Same result for different payment sources


Again: backend first made this easy.

Phase 3: Letting AI drive the whole thing

By this point, I had the fundamentals:

  • A solid CP-SAT backend doing the hard scheduling work.

  • A clean Next.js frontend where guests could book without friction.

Next question: what if it’s not a human? 🤖

I wanted an AI agent to look at availability, understand constraints, place holds, confirm bookings, reshuffle if needed. Basically run the whole thing end-to-end, safely.

The naïve approach is: throw your API docs into a prompt and pray the model doesn’t hallucinate your endpoints.

In reality, that’s fragile. Every model has different training sets, every integration becomes bespoke, and the AI is still “guessing” how to talk to your app.

Model Context Protocol (MCP) is where this stops.

Instead of wiring my API separately into each model, I put an MCP server in front of it.

The MCP server describes, in a standard way, what’s available:

  • Resources: things the agent can read to understand the world. Be it: current bookings, services, rooms, schedules, constraints.

  • Tools: actions it’s allowed to take. Create a hold, confirm a booking, release a spot, search options for a given date.

Full list of available tools the AI agent has at its disposal

From the AI’s perspective, there’s no guessing. It connects to the MCP server, asks what it can do, gets a structured menu, and calls those tools according to the schema.

From my side, I only expose what I’m comfortable with. If “delete everything” isn’t exposed, it doesn’t exist in the agent’s universe. I define the contract once, and any AI agent (now or in the future) can use it.

That’s the shift: from “an app humans click” to “an environment both humans and AI can operate in.” Same logic, same constraints, no bespoke glue.

I built the MCP server with FastMCP, wrapped around the booking API, and pointed Sonnet 4.5 in Cursor at it with a simple prompt:

“Demonstrate all the MCP booking tools.”

No extra instructions.

It:

  • Checked API health.

  • Listed services.

  • Queried availability for a Swedish massage.

  • Created a hold for a real timeslot.

  • Confirmed the booking with a fake payment reference.

  • Then went further: tested a multi-service flow (massage + facial), found valid sequences with handoffs between staff, queried recent bookings to verify everything.

Watching an AI use your API like this feels like magic
It even queried recent bookings and a date range to verify everything was recorded correctly.

Eight tool calls. No errors. No retries. No handholding.

It naturally followed the correct workflow: check availability → hold → confirm → verify.

These used to be domain-specific flows that required step-by-step, hard-coded instructions.

Now the AI just… uses the system.

I didn’t have to stuff the entire API documentation into the context window or write a custom client for each model. MCP gave the agent a clear, language-agnostic way to understand and operate my booking API.

So what does this mean if you’re not a dev?

Over roughly four months of weekends and off days, I:

  • Built and deployed a CP-SAT powered booking backend.

  • Shipped a working Next.js frontend.

  • Wrapped it all in an MCP server so AI agents can drive it.

Is it production-ready? Not yet.

Is it stable? Surprisingly, yes. It comfortably handles ~200 concurrent sessions in testing. That’s enough for the aftermath of a good marketing campaign.

Did I replace professional devs? No. Relax.

Here’s the point. The barrier to building a serious MVP has collapsed.

For a long time, shipping something like this meant being “in the club”. Knowing multiple frameworks, deeply understanding software architecture, and bribing an engineer friend with beers for half a year.

If you weren’t technical, the message was simple: your ideas are welcome, but please queue behind the backlog.

That’s not where we are anymore.

If you deeply understand a problem, are willing to learn just enough of the software dialect, and can work with modern AI tools, you now have real leverage.

A spa owner can design their own booking logic.
An ops manager can automate the annoying stuff.
A marketer can wire up workflows that used to die in “we’ll get to it one day”.

What used to be “too hard” for non-devs is now within reach of the people closest to the problem: one solid backend (even co-written with AI), a few well-structured prompts, MCP-style tooling, and the stubbornness to iterate.

That’s the actual promise of vibe coding. Not skipping rigour. Skipping gatekeeping.

You can just build things.

And honestly, you probably should.

✍️
Louis Roa
PrivacyTermsContact