|
|
||
|---|---|---|
| .github/workflows | ||
| .w4c | ||
| app | ||
| components | ||
| docker | ||
| lib | ||
| messages | ||
| prisma | ||
| public | ||
| tests | ||
| .dockerignore | ||
| .env.example | ||
| .eslintrc.json | ||
| .gitignore | ||
| middleware.ts | ||
| next.config.ts | ||
| package-lock.json | ||
| package.json | ||
| postcss.config.mjs | ||
| README.md | ||
| tsconfig.json | ||
| vitest.config.ts | ||
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 | 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
- Browse services at
/services(duration + price, admin-managed) and open a detail page. - Book at
/book(or/book/<slug>): pick a service → an optional team member → a date → a slot → your details → confirm. - 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. POST /api/bookingsre-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.- On success a (mock) confirmation email is sent and the confirmation page offers an
.icsdownload (/api/bookings/<id>/ics) for the visitor's calendar. - 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.