Book anything β doctors, salons & turfs β with zero double-bookings. A full-stack booking platform where the database itself makes overlapping appointments impossible.
BookIt is a full-stack, multi-vertical appointment booking platform for three kinds of business β doctors & clinics, salons & grooming, and sports turfs & courts. Customers browse providers, see real-time bookable slots computed from each provider's live schedule, and book or cancel in a few clicks. Admins manage providers, weekly schedules, services, breaks, time-off and every booking from a dedicated dashboard.
The headline feature is correctness under pressure: two people can never hold the same slot, even in a race between concurrent requests. BookIt guarantees this with three independent layers β a per-provider advisory lock, in-transaction slot re-validation, and a PostgreSQL GiST exclusion constraint that makes an overlapping booking impossible at the database level.
The one-liner: a React + Vite SPA talks to an Express + TypeScript API that validates every request with Zod, computes availability from live schedules, and leans on PostgreSQL exclusion constraints + advisory locks so double-booking is impossible by construction β not by hope.
π Seeded logins Β Β·Β admin: admin@bookit.local / admin123 Β Β·Β customer: customer@bookit.local / customer123
A hero and three category cards (doctors / salons / turfs), plus a feature strip: live slot availability, conflict-proof booking, and email confirmations.
Today's load, next-7-days pipeline, monthly revenue, 30-day cancel rate, active providers & customers, a per-provider upcoming-load table, and recent bookings.
- Browse providers by category (doctor / salon / turf) with search, star ratings & reviews.
- Per-provider service catalog β duration, buffer time, price and payment policy (pay-at-venue / deposit / full prepay).
- Live slot availability computed from weekly schedules, breaks, time-off and existing bookings.
- Clean 3-step booking flow: service β date & slot β details, with coupon codes and loyalty-point redemption.
- Recurring series β book weekly / biweekly runs (up to 12 sessions) with skip-and-report for unavailable dates.
- Customer accounts (optional β guest checkout always works): booking history, favorites β€, loyalty points; past guest bookings link automatically on signup.
- Self-service manage page: look up by code + email, reschedule to a new slot, cancel with automatic slot release and policy-based refunds.
- Waitlist: full day? Get an email the moment a cancellation frees a slot.
- π Dark mode across the whole app.
- Per-service policy: pay at venue, deposit %, or full prepayment.
pending_paymentbookings hold the slot at the database level for a configurable window; expired holds release automatically (sweeper + inline expiry).- Built-in MockPay gateway β HMAC-signed checkout mirroring Razorpay's flow, so a real adapter drops in behind the same
PaymentProviderinterface. Zero external accounts needed. - Refund policy engine (full / fee / none by time-to-appointment), automatic refunds on cancellation, admin manual refunds, printable receipts.
- Coupons (percent / fixed, windows, usage caps) and loyalty points (earn on completion, redeem up to 50% of price β race-safe).
- Transactional outbox + dispatcher: every email (confirmation, cancellation, reschedule, receipt, reminders, waitlist, series) is queued in Postgres and delivered with retries + exponential backoff β restarts lose nothing.
- Automated reminders 24h and 1h before each appointment (voided/re-planned on cancel & reschedule).
.icscalendar invites attached to confirmations (REQUEST) and cancellations (CANCEL) with stable UIDs and SEQUENCE bumps.- Channel abstraction β SMS/WhatsApp adapters can plug in without touching the dispatcher.
- Dashboard + analytics β booked value vs collected-online vs refunded, bookings & net revenue per day, weekdayΓhour peak-hours heatmap, top services, outcome rates, new-vs-returning customers (hand-rolled SVG, light/dark aware).
- Bookings table β filters, complete / no-show / cancel actions, CSV export (BOM + injection-safe).
- Day view & week view β visual timelines with click-through booking details.
- Customer CRM β searchable customer list with lifetime spend, no-show counts, loyalty balance, full history and private notes.
- Payments & coupons β payment ledger with refund actions; coupon CRUD.
- Reviews moderation β hide/unhide customer reviews.
- Waitlist management, provider/schedule/time-off/service CRUD as before.
- JWT-authenticated admin + customer APIs (separate token kinds); Zod request validation everywhere.
- Email via SMTP (nodemailer); with no SMTP config, rendered emails land in
server/outbox/*.htmlβ so the flow works end-to-end with zero setup. - Booking audit trail (
booking_events): created, status changes, payments, refunds, reschedules, emails sent.
Double-booking is prevented with three independent layers, so even a race between concurrent requests is safe:
| Layer | Mechanism | What it guarantees |
|---|---|---|
| 1 | pg_advisory_xact_lock(42, provider_id) |
Serialises concurrent bookings per provider; different providers book fully in parallel. Released automatically at commit/rollback. |
| 2 | In-transaction slot re-validation | The requested start must still be a slot the availability engine would generate right now β a hand-crafted API call can't book a closed day. |
| 3 | Postgres GiST exclusion constraint | The last line of defence. Even raw SQL cannot persist an overlap. |
CONSTRAINT bookings_no_overlap EXCLUDE USING gist (
provider_id WITH =,
tstzrange(starts_at, ends_at) WITH &&
) WHERE (status IN ('pending_payment', 'confirmed', 'completed'))The partial WHERE means cancelled / no-show bookings automatically free their
slot β and a booking that's being paid for (pending_payment) still holds
its slot until it's captured or the hold expires. A conflicting insert fails
with SQLSTATE 23P01, which the API maps to 409 Conflict, and the UI
refreshes the slot grid.
π The full request-to-database walkthrough lives in
docs/ARCHITECTURE.md.
| Layer | Technology |
|---|---|
| Frontend | React 18 Β· TypeScript 5 Β· Vite 6 Β· React Router 6 |
| Backend | Node.js Β· Express 4 Β· TypeScript 5 |
| Database | PostgreSQL 13+ (GiST exclusion constraints, advisory locks, range types) |
| Validation | Zod |
| Auth | JWT (jsonwebtoken) + bcryptjs |
| Nodemailer (SMTP, with HTML outbox fallback) | |
| Tooling | npm workspaces Β· tsx Β· concurrently |
- Node.js 18+
- PostgreSQL 13+ running locally (or a hosted connection string)
# 1. Clone the repository
git clone https://github.com/bhanu87777/BookIt-Appointment-Booking-System.git
cd BookIt-Appointment-Booking-System
# 2. Install dependencies (npm workspaces installs client + server)
npm install
# 3. Configure the server environment
cp server/.env.example server/.env
# β set DATABASE_URL to your local Postgres, and change JWT_SECRET
# 4. Create the database, apply the schema, and load demo data
npm run db:setup # 6 providers, services, schedules, sample bookings
# 5. Run the API (:4000) and client (:5173) together
npm run devOpen http://localhost:5173 β the admin panel is at http://localhost:5173/admin
(admin@bookit.local / admin123).
| Command | Description |
|---|---|
npm run dev |
Start API (:4000) and client (:5173) together |
npm run build |
Production build of server + client |
npm run db:migrate |
Create the database (if absent) and apply the schema |
npm run db:seed |
Load demo providers, services, schedules & bookings |
npm run db:setup |
db:migrate + db:seed in one step |
No mail provider? No problem. Leave SMTP unset and every confirmation /
cancellation email is written to server/outbox/*.html β open them in a browser
to see exactly what the customer would receive.
BookIt-Appointment-Booking-System/
βββ assets/
β βββ screenshots/ # README imagery
βββ docs/
β βββ ARCHITECTURE.md # request-to-database walkthrough
β βββ BookIt_1_Features_Walkthrough.pdf
β βββ BookIt_2_Codebase_Guide.pdf
βββ client/ # React + Vite SPA
β βββ src/
β βββ pages/ # home, browse, booking flow, confirmation, manage
β βββ admin/ # dashboard, bookings, day view, provider editor
β βββ components/ # shared layout / shell
β βββ api.ts # typed fetch wrapper (attaches admin JWT)
β βββ App.tsx # route table
βββ server/ # Express + TypeScript API
β βββ src/
β βββ db/
β β βββ schema.sql # schema incl. exclusion constraints
β β βββ migrate.ts # creates DB + applies schema (idempotent)
β β βββ seed.ts # demo data
β βββ services/
β β βββ slots.ts # availability engine
β β βββ booking.ts # transactional booking (locks + validation)
β β βββ email.ts # confirmation / cancellation emails
β βββ routes/ # public.ts + admin.ts
β βββ middleware/ # auth (JWT) + central error handler
β βββ config.ts # typed env config
βββ server/.env.example
βββ LICENSE
βββ package.json # npm workspaces root
| Method | Path | Description |
|---|---|---|
GET |
/api/providers?type=doctor |
Providers (with services) in a category |
GET |
/api/providers/:id/slots?serviceId&date=YYYY-MM-DD |
Available slots for a date |
POST |
/api/bookings |
Create a booking (409 on conflict) |
GET |
/api/bookings/lookup?code&email |
Look up a booking |
POST |
/api/bookings/:code/cancel |
Customer cancellation |
POST |
/api/auth/login |
Admin login β JWT |
GET |
/api/admin/stats |
Dashboard metrics |
GET / PATCH |
/api/admin/bookings⦠|
List / change booking status |
PUT |
/api/admin/providers/:id/schedule |
Replace weekly schedule + breaks |
POST / DELETE |
/api/admin/providers/:id/time-off Β· /api/admin/time-off/:id |
Manage time-off |
- Real payment gateway β the
PaymentProviderinterface is Razorpay-shaped; addrazorpay.ts+ a webhook route and setPAYMENT_PROVIDER=razorpay - SMS / WhatsApp reminders β register a new channel in the notification dispatcher
- Provider self-service portal β providers manage their own schedules
- Test suite β unit tests for the slot engine + integration tests on the conflict layers
Contributions, issues, and feature requests are welcome!
- Fork the project
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Distributed under the MIT License. See LICENSE for details.
Bhanu Prakash M
π‘ If BookIt helped or impressed you, consider giving the repo a β β it genuinely helps!





