{
    "id": "bhaskar/clinic-booking-app",
    "kind": "plan",
    "title": "Booking App for Clinics",
    "summary": "Patients book free slots with doctors, staff manage hours and see the day's schedule. Double booking is impossible.",
    "author": "Admin",
    "stars": 0,
    "url": "https://ownlyplans.com/bhaskar/clinic-booking-app/",
    "stack": [
        "Next.js",
        "shadcn/ui",
        "Supabase",
        "Tailwind"
    ],
    "tools": [
        "claude-code",
        "cursor"
    ],
    "difficulty": "intermediate",
    "license": "cc-by-4.0",
    "version": "1.0",
    "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.\n\nWhat makes it solid: the database itself blocks double booking, and Row Level Security means patients only ever see their own appointments.\n\nBefore you start: Node.js 20+, a free Supabase project, and Claude Code or Cursor. About 2 hours.",
    "steps": [
        {
            "title": "Create the project from the official starter",
            "body": "Create a free Supabase project first (supabase.com → New project). Then run in a terminal:\n\nnpx create-next-app -e with-supabase clinic-booking\ncd clinic-booking\n\nRename .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": "You can sign up and sign in at localhost:3000.",
            "files": [
                "Next.js + Supabase starter"
            ]
        },
        {
            "title": "Add the project rules and the Supabase MCP",
            "body": "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": "The MCP is connected (in Claude Code, /mcp shows supabase) and lists your tables.",
            "files": [
                "CLAUDE.md",
                "Supabase MCP (read-only)"
            ]
        },
        {
            "title": "Create the database",
            "body": "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": "Four tables exist with RLS on, and npm run build passes with the generated types.",
            "files": [
                "supabase-schema.sql",
                "Supabase Row Level Security guide"
            ]
        },
        {
            "title": "Onboarding and roles",
            "body": "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": "A new account is asked for name and phone once, then lands on the right page for its role.",
            "files": []
        },
        {
            "title": "Staff: doctors and weekly hours",
            "body": "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": "As staff you can add a doctor with hours. As a patient, /staff redirects you away and RLS blocks direct writes.",
            "files": [
                "Supabase Row Level Security guide"
            ]
        },
        {
            "title": "Free slots and booking",
            "body": "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": "Two browsers trying the same slot: one books, the other sees the friendly message.",
            "files": [
                "supabase-schema.sql"
            ]
        },
        {
            "title": "My appointments",
            "body": "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": "Cancelling frees the slot immediately for everyone.",
            "files": []
        },
        {
            "title": "Staff: today's schedule",
            "body": "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": "Staff see every booking for the day; patients still only see their own (test with two accounts).",
            "files": []
        },
        {
            "title": "Check security and deploy",
            "body": "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": "All checks pass and the app runs on your Vercel URL.",
            "files": [
                "Supabase Row Level Security guide"
            ]
        }
    ],
    "files": [
        {
            "type": "markdown",
            "name": "CLAUDE.md",
            "note": "Project root. Cursor users: save as AGENTS.md.",
            "file": "claude",
            "url": "https://ownlyplans.com/bhaskar/clinic-booking-app/claude/"
        },
        {
            "type": "markdown",
            "name": "supabase-schema.sql",
            "note": "Tables, double-booking guard and RLS policies. Save as supabase/schema.sql.",
            "file": "supabase-schema",
            "url": "https://ownlyplans.com/bhaskar/clinic-booking-app/supabase-schema/"
        },
        {
            "type": "git",
            "name": "Next.js + Supabase starter",
            "note": "Official starter with cookie-based auth.",
            "url": "https://github.com/vercel/next.js/tree/canary/examples/with-supabase"
        },
        {
            "type": "mcp",
            "name": "Supabase MCP (read-only)",
            "note": "Lets your AI read the schema. Read-only and scoped to one project.",
            "file": "supabase-mcp-read-only",
            "url": "https://ownlyplans.com/bhaskar/clinic-booking-app/supabase-mcp-read-only/"
        },
        {
            "type": "link",
            "name": "Supabase Row Level Security guide",
            "note": "Read once: it is what keeps patient data private.",
            "url": "https://supabase.com/docs/guides/database/postgres/row-level-security"
        }
    ],
    "install": "",
    "how_to_use": "Call get_step with step 1, do it, check \"done when\", then continue."
}