Skip to content
OwnlyPlans

Plan

Booking App for Clinics

Patients book free slots with doctors, staff manage hours and see the day's schedule. Double booking is impossible.

Remix

Overview

A real appointment system for a small clinic: patients sign up, pick a doctor and a free time, and manage their bookings. Staff set each doctor’s weekly hours and see today’s schedule.

What makes it solid: the database itself blocks double booking, and Row Level Security means patients only ever see their own appointments.

Before you start: Node.js 20+, a free Supabase project, and Claude Code or Cursor. About 2 hours.

Build it step by step

Sign in to tick steps off
  1. 1

    Create the project from the official starter

    Create a free Supabase project first (supabase.com → New project). Then run in a terminal:

    npx create-next-app -e with-supabase clinic-booking
    cd clinic-booking

    Rename .env.example to .env.local and paste your project URL and publishable (anon) key from Supabase → Project Settings → API. Run npm run dev.

    Prompt
    Read the project structure and README. Explain in 5 bullet points how auth works in this starter (where the Supabase clients live, how the session cookie is refreshed). Do not change any files yet.

    Done when You can sign up and sign in at localhost:3000.

    Uses Next.js + Supabase starter

  2. 2

    Add the project rules and the Supabase MCP

    Save CLAUDE.md in the project root. Create a personal access token in Supabase (Account → Access Tokens) and add the Supabase MCP with your project ref. Keep --read-only: your AI can read the schema but not change data.

    Prompt
    Read CLAUDE.md and confirm the rules in one short list. Then use the Supabase MCP to list the tables in my project.

    Done when The MCP is connected (in Claude Code, /mcp shows supabase) and lists your tables.

    Uses CLAUDE.md Supabase MCP (read-only)

  3. 3

    Create the database

    Open Supabase → SQL Editor, paste supabase-schema.sql and run it. Sign up once in the app, then run the commented line at the bottom of the file with your email to make yourself staff.

    Prompt
    Save the schema I ran as supabase/schema.sql. Generate TypeScript types for it into lib/database.types.ts (run: npx supabase gen types typescript --project-id YOUR_PROJECT_REF > lib/database.types.ts) and use them in the Supabase clients.

    Done when Four tables exist with RLS on, and npm run build passes with the generated types.

    Uses supabase-schema.sql Supabase Row Level Security guide

  4. 4

    Onboarding and roles

    Every new user gets a profile automatically (database trigger). Ask for a name and phone number once, and route people by role.

    Prompt
    After sign-in, if profiles.full_name is empty, show /onboarding with name and phone fields (Server Action to save). Then send patients to /book and staff to /staff. Add a header with the user name, role and a sign-out button.

    Done when A new account is asked for name and phone once, then lands on the right page for its role.

  5. 5

    Staff: doctors and weekly hours

    Staff add doctors (name, specialty, slot length) and weekly hours (e.g. Mon 09:00–13:00 and 15:00–18:00).

    Prompt
    Build /staff/doctors: list, add, edit and deactivate doctors, and edit each doctor's weekly hours (rows of weekday + start + end, add/remove rows). Only staff may open /staff pages: check the role on the server and redirect others to /book. Use shadcn/ui form components.

    Done when As staff you can add a doctor with hours. As a patient, /staff redirects you away and RLS blocks direct writes.

    Uses Supabase Row Level Security guide

  6. 6

    Free slots and booking

    Turn weekly hours into real times in the clinic time zone, remove busy times (busy_slots RPC) and past times, and show the next 14 days.

    Prompt
    Build /book: pick a doctor, then show the next 14 days with free times as buttons. Generate slots from availability + slot_minutes in CLINIC_TIMEZONE, remove past times and times returned by rpc('busy_slots'). Booking inserts an appointment in a Server Action with an optional reason. If the insert fails with code 23505, show "That time was just taken, pick another" and refresh the slots.

    Done when Two browsers trying the same slot: one books, the other sees the friendly message.

    Uses supabase-schema.sql

  7. 7

    My appointments

    Patients see upcoming and past appointments and can cancel upcoming ones.

    Prompt
    Build /appointments for patients: upcoming first (doctor, date, time in clinic time zone, reason), then past. A Cancel button on upcoming ones sets status to cancelled after a confirm step. The cancelled slot must become free again on /book.

    Done when Cancelling frees the slot immediately for everyone.

  8. 8

    Staff: today's schedule

    A day view with one column per doctor, so the front desk can see who is coming.

    Prompt
    Build /staff/schedule: date picker (default today), one column per active doctor, rows per slot, booked slots show patient name, phone and reason. Staff can mark an appointment done or cancelled. Make it readable on a tablet.

    Done when Staff see every booking for the day; patients still only see their own (test with two accounts).

  9. 9

    Check security and deploy

    Prove the privacy rules with two patient accounts, then deploy.

    Prompt
    Write a checklist and walk me through testing it: patient A cannot see patient B's appointments (UI and direct Supabase queries), patients cannot change their role, patients cannot book in the past. Then prepare for Vercel: list the env vars and add the production URL to Supabase Auth → URL configuration.

    Done when All checks pass and the app runs on your Vercel URL.

    Uses Supabase Row Level Security guide

Files and links

  • CLAUDE.md 1 KB Project root. Cursor users: save as AGENTS.md.
  • supabase-schema.sql 5 KB Tables, double-booking guard and RLS policies. Save as supabase/schema.sql.
  • Next.js + Supabase starter (opens in a new tab) vercel/next.js › examples/with-supabase Official starter with cookie-based auth.
  • Supabase MCP (read-only) MCP config Lets your AI read the schema. Read-only and scoped to one project.

    Check it before you connect it. This server runs with your permissions: npx -y @supabase/mcp-server-supabase@latest --read-only --project-ref=YOUR_PROJECT_REF It needs SUPABASE_ACCESS_TOKEN. Use your own and never share them.

    Claude Code
    claude mcp add-json supabase '{"command":"npx","args":["-y","@supabase/mcp-server-supabase@latest","--read-only","--project-ref=YOUR_PROJECT_REF"],"env":{"SUPABASE_ACCESS_TOKEN":"YOUR_PERSONAL_ACCESS_TOKEN"}}'

What people built

Show yours

Nobody has shared a build yet. Yours could be the first.

Show what you built

Built this plan? Sign in to share your demo video, live app and screenshots.

Your AI tool
Starter prompt

		

Download the plan