CodingIdeas.ai
← Browse All Ideas

Build Guide

How to Build a Booking App

There are 47 million solo service providers globally still taking bookings over WhatsApp — every one of them is a potential customer for your scheduling app.

Intermediate1–2 weeks

Booking apps are one of the most monetisable categories for solo founders: service providers will pay $20–50/month to stop managing appointments manually.

Data model

The core tables you'll need before writing any UI.

Providerid, user_id, name, slug, timezone, booking_url_enabled
Serviceid, provider_id, name, duration_minutes, price, buffer_minutes
Availabilityid, provider_id, day_of_week (0–6), start_time, end_time
Bookingid, provider_id, service_id, customer_name, customer_email, start_at (UTC), end_at (UTC), status (pending/confirmed/cancelled), stripe_payment_intent

Build order

The sequence that minimises rewrites — build in this order.

1

Provider profile and services

Create a provider profile with name and timezone. Add a services list — each service has a name, duration (e.g. 60 min), price, and buffer time between appointments.

2

Availability configuration

Add a weekly availability grid — the provider sets which hours they work each day. Store as day_of_week + start_time + end_time rows. Show a preview of open slots.

3

Public booking page

Create /book/[slug] — a public page for customers. Show a date picker. For the selected date, calculate open slots by subtracting existing bookings from availability windows.

4

Slot calculation logic

Write a function: given a date, the provider's availability, existing bookings, service duration, and buffer time — return an array of available start times as UTC ISO strings. This is the core algorithm.

5

Stripe payment at booking time

When a customer selects a slot and fills in their details, create a Stripe Payment Intent. Only confirm the booking after payment succeeds via the webhook. Never book without confirmed payment.

6

Email confirmations and reminders

On booking confirmed, send email to both provider and customer via Resend. Schedule a reminder 24h before via a Vercel cron job that queries bookings starting in the next 24–25h window.

7

Google Calendar sync

Use the Google Calendar API with OAuth. On each new booking, create a calendar event on the provider's Google Calendar. On cancellation, delete it. Store the Google event ID on the booking row.

Done when

Observable behaviors that confirm V1 is complete — verify each one before you ship.

  • Customer visits /book/[slug] and sees available slots for the next 7 days

  • Booking is only confirmed after Stripe payment succeeds — not before

  • Provider receives an email confirmation within 60 seconds of a new booking

  • Google Calendar event appears on the provider's calendar within 30 seconds of booking

  • Two customers cannot book the same slot simultaneously — race condition is handled

First Run Requirement

Seed a demo provider (Jane Smith, Personal Trainer) with a 60-min session (£60) and Mon–Fri 9am–5pm availability so /book/jane-smith works on first visit. No provider setup needed to demo.

Build it with AI — Architect Prompt

Paste this into Claude, Cursor, Windsurf, or any AI coding tool. It includes the full context of this guide — data model, build order, done conditions, and pitfalls — so the AI starts with everything it needs.

ClaudeCursorWindsurfCopilotGemini
architect-prompt.txt
<context>
App: Booking App
Difficulty: Intermediate
Estimated build time: 1–2 weeks
Tech stack (intermediate): Next.js + Supabase + Stripe + Resend + Google Calendar API

Data model:
  Provider: id, user_id, name, slug, timezone, booking_url_enabled
  Service: id, provider_id, name, duration_minutes, price, buffer_minutes
  Availability: id, provider_id, day_of_week (0–6), start_time, end_time
  Booking: id, provider_id, service_id, customer_name, customer_email, start_at (UTC), end_at (UTC), status (pending/confirmed/cancelled), stripe_payment_intent

FIRST RUN REQUIREMENT:
Seed a demo provider (Jane Smith, Personal Trainer) with a 60-min session (£60) and Mon–Fri 9am–5pm availability so /book/jane-smith works on first visit. No provider setup needed to demo.

DONE WHEN — verify each before marking V1 complete:
  □ Customer visits /book/[slug] and sees available slots for the next 7 days
  □ Booking is only confirmed after Stripe payment succeeds — not before
  □ Provider receives an email confirmation within 60 seconds of a new booking
  □ Google Calendar event appears on the provider's calendar within 30 seconds of booking
  □ Two customers cannot book the same slot simultaneously — race condition is handled

Recommended build order:
  1. Define API contract + schema + seed data (always first)
  2. Provider profile and services — Create a provider profile with name and timezone. Add a services list — each service has a name, duration (e.g. 60 min), price, and buffer time between appointments.
  3. Availability configuration — Add a weekly availability grid — the provider sets which hours they work each day. Store as day_of_week + start_time + end_time rows. Show a preview of open slots.
  4. Public booking page — Create /book/[slug] — a public page for customers. Show a date picker. For the selected date, calculate open slots by subtracting existing bookings from availability windows.
  5. Slot calculation logic — Write a function: given a date, the provider's availability, existing bookings, service duration, and buffer time — return an array of available start times as UTC ISO strings. This is the core algorithm.
  6. Stripe payment at booking time — When a customer selects a slot and fills in their details, create a Stripe Payment Intent. Only confirm the booking after payment succeeds via the webhook. Never book without confirmed payment.
  7. Email confirmations and reminders — On booking confirmed, send email to both provider and customer via Resend. Schedule a reminder 24h before via a Vercel cron job that queries bookings starting in the next 24–25h window.
  8. Google Calendar sync — Use the Google Calendar API with OAuth. On each new booking, create a calendar event on the provider's Google Calendar. On cancellation, delete it. Store the Google event ID on the booking row.
  9. End-to-end verification — walk every Done When condition above (always last)

Known pitfalls to avoid:
  - Not locking slots during checkout — two customers can select the same slot simultaneously. Use a database lock (SELECT FOR UPDATE) or a short-lived reservation row to hold the slot while payment processes.
  - Storing times in local timezone — always store start_at and end_at in UTC. Convert to the provider's timezone only for display. A provider in Tokyo and a customer in London will both see the correct local time.
  - Forgetting buffer time in slot calculation — if a service is 60 min with 15 min buffer and a booking starts at 9am, the next available slot is 10:15am, not 10:00am.
</context>

<role>
You are a Senior Full-Stack Engineer and product architect who has shipped production Booking Apps before. You know exactly where developers get stuck and how to structure the project to avoid rewrites.
</role>

<task id="step-1-clarify">
Before writing any code or spec, ask me 3–5 clarifying questions that will meaningfully change the architecture. Focus on: scale expectations, auth requirements, platform (web / mobile / both), must-have vs nice-to-have features for the MVP, and any hard constraints (budget, deadline, existing infrastructure).

<example>
BAD: "What tech stack do you want to use?" — too broad, doesn't change architecture decisions.
GOOD: "Do you need real-time sync across devices, or is single-device with periodic refresh acceptable? This decides whether we use WebSockets or simple REST polling and significantly affects infrastructure complexity."
</example>

⚠️ Do NOT start planning or writing code until I answer. Present the questions, then stop and wait.
</task>

<task id="step-2-architect">
After I answer your questions, produce the following in order:

1. TECHNICAL SPECIFICATION
   - System architecture using → to show data and event flow
   - Core data model (refer to data model in <context>)
   - API contract — list ALL routes with request/response shapes BEFORE any implementation
     WHY: agreeing on contracts first prevents rewrites when frontend and backend shapes diverge
   - External APIs and integration points

2. MVP PLAN in three phases:

   SETUP   ✦ Step 1 (always): API contract + schema migration + seed data
     Done when: schema is migrated, seed script runs, app starts with demo data, zero manual setup.

   CORE FEATURES — build in this exact order:
   2. Provider profile and services
   3. Availability configuration
   4. Public booking page
   5. Slot calculation logic
   6. Stripe payment at booking time
   7. Email confirmations and reminders
   8. Google Calendar sync

   DONE WHEN — one observable condition per feature:
   □ Customer visits /book/[slug] and sees available slots for the next 7 days
   □ Booking is only confirmed after Stripe payment succeeds — not before
   □ Provider receives an email confirmation within 60 seconds of a new booking
   □ Google Calendar event appears on the provider's calendar within 30 seconds of booking
   □ Two customers cannot book the same slot simultaneously — race condition is handled

   STRETCH GOALS — post-launch additions that are explicitly out of V1 scope.

3. BLOCKER ANALYSIS
   Flag: API rate limits, auth complexity, scope risks, cold-start problems, top 2–3 failure modes.

   FIRST RUN REQUIREMENT: Seed a demo provider (Jane Smith, Personal Trainer) with a 60-min session (£60) and Mon–Fri 9am–5pm availability so /book/jane-smith works on first visit. No provider setup needed to demo.
   ✓ Done when: app launches with seed data and the full user journey works without any manual setup.

<self_check>
Before presenting your output, verify:
□ Every answer I gave to clarifying questions is reflected in the spec
□ Step 1 is ALWAYS: API contract + schema + seed — never UI first
□ Done When criteria are observable user behaviors, not internal states
□ The plan is realistic for one person to ship within 1–2 weeks
□ All known pitfalls from <context> are addressed in the spec
</self_check>
</task>

<task id="step-2.5-agents-md">
Generate an AGENTS.md file at the project root. This file is read automatically by Claude Code, Cursor, Windsurf, and all major AI coding tools at the start of every session.

Include:
- Project overview (2–3 sentences)
- Tech stack with exact version numbers
- Folder structure with one-line descriptions per directory
- Key architectural decisions and the WHY behind each
- Coding conventions: camelCase components, kebab-case files, max 200 lines per file, one concern per file
- Available commands: dev, build, test, lint, db:migrate, db:seed
- MVP scope boundaries — features explicitly out of V1

Note in the file: "Cursor users: symlink .cursorrules → AGENTS.md. Claude Code users: symlink CLAUDE.md → AGENTS.md."
</task>

<task id="step-3-implement">
Implement the full project in the exact order from step 2. For each step:
- Write complete code (no placeholders or TODOs)
- Confirm the step works before moving to the next

<constraints>
- Step 1 is ALWAYS: define all API routes + TypeScript request/response interfaces + run schema migration
  WHY: agreeing on contracts before writing a single component prevents shape mismatches that require rewrites
- Final step is ALWAYS: start the app and walk every Done When condition from <context> end-to-end
  WHY: a spec that passes unit tests but breaks the core user journey is not done
- Max 200 lines per file. WHY: every file must fit in one AI context window for complete reasoning
- One concern per file. WHY: mixing auth logic into API routes makes it impossible to reuse — extract to lib/auth.ts
- TypeScript strict mode, no `any` types. WHY: catches data shape mismatches at compile time, not in production
- All database queries in server components or API routes only. WHY: keeps credentials server-side
- All environment variables documented in .env.example. WHY: next developer sets up in under 5 minutes
</constraints>
</task>

How to use this prompt

  1. 1.Copy the prompt above
  2. 2.Open Claude, Cursor (Cmd+L), or Windsurf
  3. 3.Paste the prompt and send — the AI will ask 3–5 clarifying questions
  4. 4.Answer the questions, then it generates your full project spec
  5. 5.Continue in the same session to implement step by step

Common mistakes

What trips up most developers building this for the first time.

⚠️

Not locking slots during checkout — two customers can select the same slot simultaneously. Use a database lock (SELECT FOR UPDATE) or a short-lived reservation row to hold the slot while payment processes.

⚠️

Storing times in local timezone — always store start_at and end_at in UTC. Convert to the provider's timezone only for display. A provider in Tokyo and a customer in London will both see the correct local time.

⚠️

Forgetting buffer time in slot calculation — if a service is 60 min with 15 min buffer and a booking starts at 9am, the next available slot is 10:15am, not 10:00am.

Recommended tech stack

Pick the level that matches your experience.

No-code

Calendly clone on Bubble.io + Stripe — functional in 3 days

Intermediate

Next.js + Supabase + Stripe + Resend + Google Calendar API

Advanced

Next.js + Supabase + Stripe + Twilio (SMS) + Google/Outlook Calendar + multi-staff support

Take it further — related ideas

Each comes with revenue math, a full build guide, and a prompt to paste into Claude or Cursor.