Ready-to-run appointment booking: services, staff schedules, live availability, customer accounts and an admin calendar.
Find a file Use this template
w4c-templates 3a9325374c
Some checks failed
CI / quality (push) Has been cancelled
chore(template): publish Booking.Next
2026-10-11 23:33:46 +03:00
.github/workflows chore(template): publish Booking.Next 2026-10-11 23:27:02 +03:00
.w4c chore(template): publish Booking.Next 2026-10-11 23:27:02 +03:00
app chore(template): publish Booking.Next 2026-10-11 23:27:02 +03:00
components chore(template): publish Booking.Next 2026-10-11 23:27:02 +03:00
docker chore(template): publish Booking.Next 2026-10-11 23:27:02 +03:00
lib chore(template): publish Booking.Next 2026-10-11 23:27:02 +03:00
messages chore(template): publish Booking.Next 2026-10-11 23:27:02 +03:00
prisma chore(template): publish Booking.Next 2026-10-11 23:27:02 +03:00
public chore(template): publish Booking.Next 2026-10-11 23:27:02 +03:00
tests chore(template): publish Booking.Next 2026-10-11 23:27:02 +03:00
.dockerignore chore(template): publish Booking.Next 2026-10-11 23:27:02 +03:00
.env.example chore(template): publish Booking.Next 2026-10-11 23:27:02 +03:00
.eslintrc.json chore(template): publish Booking.Next 2026-10-11 23:27:02 +03:00
.gitignore chore(template): publish Booking.Next 2026-10-11 23:27:02 +03:00
middleware.ts chore(template): publish Booking.Next 2026-10-11 23:27:02 +03:00
next.config.ts chore(template): publish Booking.Next 2026-10-11 23:27:02 +03:00
package-lock.json chore(template): publish Booking.Next 2026-10-11 23:27:02 +03:00
package.json chore(template): publish Booking.Next 2026-10-11 23:27:02 +03:00
postcss.config.mjs chore(template): publish Booking.Next 2026-10-11 23:27:02 +03:00
README.md chore(template): publish Booking.Next 2026-10-11 23:27:02 +03:00
tsconfig.json chore(template): publish Booking.Next 2026-10-11 23:27:02 +03:00
vitest.config.ts chore(template): publish Booking.Next 2026-10-11 23:27:02 +03:00

Booking / Appointments — Next.js (templates2)

A ready-to-run appointment-booking application: services and staff, real-time availability, a four-step booking flow with confirmation email and a calendar invite, a customer account and an admin calendar — on the shared Next.js core (auth, roles, Prisma, mock payments/email, SEO, CI, Docker).

Quickstart

npm ci
cp .env.example .env          # SQLite + mock providers by default — no keys needed
npm run db:setup              # prisma db push + seed
npm run dev                   # http://localhost:3000

Seeded demo accounts:

Role Email Password
Admin admin@example.com password
Customer user@example.com password

Seeded data: 3 services, 2 team members with Mon–Fri 09:00–17:00 working hours, and a handful of bookings around today (pending, confirmed, completed, no-show and cancelled).

How booking works

  1. Browse services at /services (duration + price, admin-managed) and open a detail page.
  2. Book at /book (or /book/<slug>): pick a service → an optional team member → a date → a slot → your details → confirm.
  3. Slots come from GET /api/availability — server-computed for the service/staff/date in the site timezone (SITE_TIMEZONE), with past and taken slots excluded.
  4. POST /api/bookings re-validates everything server-side (real slot, working hours, not in the past) and checks for a clash inside a transaction, so a slot can never be double-booked.
  5. On success a (mock) confirmation email is sent and the confirmation page offers an .ics download (/api/bookings/<id>/ics) for the visitor's calendar.
  6. Signed-in customers manage their bookings at /account/bookings (upcoming / past, cancel).

Admin

Role-gated under /admin:

  • Services (/admin/services) — CRUD, duration, price, active flag and staff assignment.
  • Bookings (/admin/bookings) — day/week calendar, customer/date/status filters, manual booking, and status transitions (pending → confirmed → completed, cancelled, no-show).
  • Team (/admin/staff) — CRUD plus a working-hours editor.

All admin mutations are authorized server-side, validated with zod and written to the audit log.

Timezones

Instants are stored in UTC. Slots are generated from working hours (WorkingHour, minutes from midnight) in SITE_TIMEZONE using Intl — no date libraries. Set SITE_TIMEZONE (e.g. Europe/Berlin) to change the business timezone; UTC is the default.

Scripts

Script What it does
npm run dev Dev server with HMR
npm run build / npm start Production build / serve
npm run lint / npm run typecheck ESLint / tsc --noEmit
npm test Unit tests (Vitest) — slot generation + overlap
npm run test:e2e HTTP end-to-end smoke (server must be running)
npm run db:setup prisma db push + seed
npm run db:seed Seed only

Environment

Variable Default Notes
DATABASE_URL file:./dev.db SQLite in dev; Postgres in production
NEXT_PUBLIC_SITE_URL http://localhost:3000 Absolute URLs (sitemap, OG, calendar)
SITE_TIMEZONE UTC IANA timezone for slots and working hours
RESEND_API_KEY (empty) When set, real email replaces the log provider
STRIPE_SECRET_KEY (empty) Optional; mock payments work without it

Deployment

docker compose -f docker/docker-compose.yml up --build

Quality

node ../templates2/qa.mjs Booking.Next        # from the repo root: node templates2/qa.mjs Booking.Next

The harness isolates a clean copy, then runs install → verify → test → build → boot → routes → e2e → screenshot. See ../CONTRACT.md for the Definition of Done.