Serene
An appointment platform for a fictional wellness studio, on a scheduling engine that understands therapists, rooms, equipment and buffers.
- Kind
- Live demo
- For
- A fictional business
- What it is
- Appointment booking platform
- My role
- Design and engineering
- Built
- 2026


The idea
A calm booking platform for a fictional wellness studio: real availability from a scheduling engine that understands therapists, rooms, equipment and buffers, self-service changes through a private link, and a staff console. Running as a public demonstration: bookings are simulated in your browser, no one will expect you and nothing you enter is saved.
- Who it's for
- Clinics, wellness studios, salons and consultants who schedule appointments and lose time to back-and-forth messages.
- The problem
- A treatment can only be booked when the right therapist is working, a suitable room is free, any scarce equipment is available and there is time to prepare between clients. Studios usually settle that over messages, and mistakes become double bookings.
What I built
Everything below works in the public demonstration today.
I designed and built Serene end to end: the public site, the scheduling engine, the booking flow, the staff console, the database functions and the tests.
What works in the demo
- Daylight homepage whose light follows the studio's real local time, with a static midday scene without JavaScript and for reduced motion
- Treatment and practitioner discovery with search and filters kept in the URL (also without JavaScript) and a “who can I see for…” matcher
- Five-step booking: treatment, length, therapist or anyone, day and time, review; availability calculated by the scheduling engine from shifts, breaks, time off, closures, rooms, equipment and preparation buffers
- Simulated confirmation (demonstration only), then view, move or cancel through a private link, with cut-offs and a move limit
- Read-only staff console with fictional data generated by the same engine: day and week calendars, appointments, team schedules, time off, treatments, rooms and equipment, reports and settings, where every change is refused by the server
- Content-Security-Policy without eval or third-party origins, keyboard support, daylight and evening themes and reduced-motion support
The experience
Real screens, captured from the live site as a first-time visitor sees them.




The engineering
How it is put together, and the problems that took the most care.
The studio is data: services, team, rooms, hours and policies in one validated configuration. A pure scheduling engine draws availability from it, and in a real deployment PostgreSQL functions decide every write under locks, so the calendar a client sees and the one the studio keeps cannot disagree.
Studio configuration
Brand facts, treatments, therapists, rooms, equipment, hours and policies, validated with Zod for referential integrity before anything renders.
Scheduling engine
Pure TypeScript interval algebra: shifts, breaks, time off, closures, rooms, equipment and buffers become bookable times, in the studio's own time zone.
Booking service
One flow from treatment to confirmation, with a demonstration store (signed browser data, nothing stored) and a PostgreSQL store. Configuration picks one and fails closed.
Database
For a real studio: locked, audited PostgreSQL functions with exclusion constraints, so overlapping bookings cannot be stored. Built and tested, not connected to the public demo.
Technology
- In the public demo
- Next.js 16
- React 19
- TypeScript
- Tailwind CSS v4
- GSAP
- Motion
- Zod
- Vitest
- Playwright
- Built and tested, not used by the demo
- PostgreSQL 18
Hard problems, and how I solved them
One engine, written twice
- Problem
- The browser needs to draw availability instantly; the database must be the final word when something is written.
- Approach
- Pure TypeScript draws the calendar and PostgreSQL functions decide every write. A parity suite runs both against the same cases and requires the same answers.
Double bookings impossible by construction
- Problem
- Checks in application code can race: two requests can both see a free slot.
- Approach
- Row locks and exclusion constraints make an overlapping booking unstorable. Concurrency tests race bookings, staff edits, closures and cancellations on separate database connections.
Staff changes that never strand a client
- Problem
- A shift change or new time off can silently invalidate appointments that are already confirmed.
- Approach
- Such a change is refused with the list of affected appointments, never applied quietly. Every change is idempotent and written to an append-only audit log.
The evidence
What can be checked, and what the public version does not do.
- Database tests
- 65 tests on a real PostgreSQL 18 server; the suites ran 20 times in a row, ten of them under extra CPU load
- Automated tests
- 119 unit tests; 182 browser tests at 1440, 820 and 375 px with axe
- Lighthouse (production)
- Mobile 94–100, desktop 100 on every page; accessibility 100; CLS 0
Figures from the project's own release record, written when it shipped. The public demonstration runs on fictional data.
Not in the public demo
- Real bookings in a studio's own PostgreSQL database (the locked, audited booking and staff functions are built and tested against PostgreSQL, but not connected to the public demo)
- Staff sign-in on a hosted identity provider, with password reset and two-factor sign-in
- Email or SMS confirmations and reminders
- Payments
Explore the product
Still taking appointments by message?
Serene's scheduling engine understands people, rooms, equipment and preparation time. A clinic, salon or studio can take bookings online without the back-and-forth, and without double bookings.