Skip to content

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
Serene home page: the headline “Come in from the day.” beside an arched window throwing late-morning light across a limestone wall, with a slider for the light in the studio.
Serene home page on a phone in the evening: an arched window against a dim limestone wall, above the headline “Come in from the day.” and an Explore treatments button.
Live capture · 14 Oct 2026The home page. The light on the wall follows the studio's local time; without JavaScript or with reduced motion it rests at midday.Phone · Live capture · 14 Oct 2026The home page at phone width, captured in the evening: the studio's light had already dimmed.

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.

Serene treatments page: the headline “Every treatment, with its lengths and prices.”, a search field, category filters with counts, length filters and the first treatment, Slow massage, with its lengths and prices.
Live capture · 14 Oct 2026Treatments, with search and filters kept in the URL, so they also work without JavaScript and can be shared.
Serene booking, step four: a calendar for October with Wednesday 14 selected and free times grouped into morning and afternoon, beside a summary of the chosen warm stone massage.
Live capture · 14 Oct 2026Booking, step four: free times computed by the engine from shifts, breaks, rooms, equipment and preparation buffers.
Serene demonstration confirmation headed “Your simulated booking is made.”, explaining that no appointment exists at a real studio, with the reference, treatment, therapist, time and price.
Live capture · 14 Oct 2026The simulated confirmation says that no appointment exists at a real studio, then offers the private link to move or cancel.
Serene studio console calendar with a “Demo Mode” banner: a day view with a column per therapist, fictional appointments placed at their times, breaks and preparation time hatched.
Live capture · 14 Oct 2026The studio console: a column per therapist, with breaks and preparation time hatched. Fictional data, generated by the same engine.

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.

  1. Studio configuration

    Brand facts, treatments, therapists, rooms, equipment, hours and policies, validated with Zod for referential integrity before anything renders.

  2. 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.

  3. 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.

  4. 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

  1. 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.
  2. 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.
  3. 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

serene-eight-pink.vercel.appTry Serene yourself (opens in a new tab)

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.