Skip to content

Saffron Table

A restaurant website and booking system for a fictional coastal Indian kitchen, built as a reusable product.

Kind
Live demo
For
A fictional business
What it is
Restaurant website
My role
Design and engineering
Built
2026
Saffron Table home page: the headline “Taste the coast before the technique” beside a 3D plate of saffron dessert on a dark dining-room background.
Saffron Table home page on a phone: the headline “Taste the coast before the technique.” over a blurred dining-room photograph, with Reserve a table and Explore the menu buttons.
Live capture · 11 Oct 2026The home page. Desktop visitors get an interactive 3D plate; phones and tablets get a photograph instead.Phone · Live capture · 14 Oct 2026The home page at phone width, with the photograph hero.

The idea

A cinematic, appetite-first site for a fictional coastal Indian kitchen: a menu that reads well on a phone, a guided table booking and a staff console. Running as a public demonstration: bookings use fictional availability and nothing you enter is saved.

Who it's for
Independent restaurants and cafés that need a fast, mobile-first site for menus, opening hours and reservations.
The problem
A restaurant's website usually stops at a menu and a phone number. Taking bookings online means respecting real rules: opening hours, closures, party sizes, how long a table is held and how many guests the kitchen can start at once. And two people must never be given the same last table.

What I built

Everything below works in the public demonstration today.

I designed and built Saffron Table end to end: the public site, the booking engine, the staff console, the database schema and the tests.

What works in the demo

  • Cinematic home with an interactive 3D plate on desktop and a photo hero on phones and tablets
  • Menu with search, dietary and allergen filters, dish pages and a quick view
  • Table booking walkthrough on fictional availability (demonstration only, nothing is saved or sent)
  • Manage-a-booking flow using fictional sample references
  • Read-only staff console with fictional bookings, menu, settings and analytics
  • Light and dark themes, keyboard support and reduced-motion support

The experience

Real screens, captured from the live site as a first-time visitor sees them.

Saffron Table menu page: the heading “The menu”, a search field, categories with dish counts (small plates, from the hearth, breads and sides, desserts, bar) and the first dish photographs.
Live capture · 14 Oct 2026The menu: 22 dishes, searchable, with dietary and allergen filters that combine.
Saffron Table booking, step one of four: party size buttons from 1 to 8 with 2 selected, a calendar for October 2026, a summary panel and a notice that the booking flow runs in demonstration mode.
Live capture · 14 Oct 2026Booking, step one of four. The notice that nothing is saved is on screen from the first step.
Saffron Table staff console overview showing fictional bookings, covers, service load charts and a banner reading “Demonstration admin. Fictional seeded data, read-only.”
Live capture · 11 Oct 2026The staff console: bookings, covers and service load, on fictional data. It is read-only, and the server refuses every change.

The engineering

How it is put together, and the problems that took the most care.

Everything specific to the restaurant (name, hours, menu, rules) lives in one business profile, so the product can be rebranded for a real restaurant. Bookings pass through one service with two interchangeable stores: PostgreSQL for a real restaurant, and a demonstration store that saves nothing.

  1. Interface

    Next.js App Router: the public site (home, menu, dish pages, booking, manage a booking) and the staff console, sharing one design system.

  2. Booking service

    Validates every request again on the server, applies rate limits keyed by a hash of the visitor's address, and logs outcome codes, never names, emails or phone numbers.

  3. Stores

    A PostgreSQL store that calls locked database functions with only the public key, and a demonstration store over fictional bookings. The configuration picks one and fails closed.

  4. Database

    PostgreSQL decides every booking: a lock per service date, every rule checked again inside it, unique idempotency keys and row-level security on guest data.

Technology

In the public demo
  • Next.js 16
  • React 19
  • TypeScript
  • Tailwind CSS v4
  • React Three Fiber
  • GSAP
  • Motion
  • Zod
  • Recharts
  • Postgres schema (Supabase-ready)
  • Vitest
  • Playwright

Hard problems, and how I solved them

  1. Never giving one table to two people

    Problem
    Two guests asking for the last table at the same moment must not both get it, and neither must a staff change made at the same time.
    Approach
    Every change that affects capacity takes a lock for its service date in PostgreSQL, then re-checks hours, closures, notice, party size, pacing and seating inside that lock before writing. One global lock order (settings, then dates, then the booking) removed a deadlock that the parallel-connection tests found.
  2. One set of rules, drawn and enforced

    Problem
    The calendar a guest sees and the database that takes the booking must agree, or people are offered times they cannot have.
    Approach
    TypeScript draws the calendar and the time slots; a SQL function decides at write time. A parity test runs both over every slot and party size and requires identical answers.
  3. Private links that stay private

    Problem
    Guests manage their booking without an account, so the link itself is the key.
    Approach
    The token is 256 random bits, shown once; only its SHA-256 digest is stored. It travels in the URL fragment, which browsers never send to servers, and the page removes it from the address bar.
  4. A demonstration that cannot pretend

    Problem
    A public demo must show the real flow without storing anyone's details or implying a table is held.
    Approach
    In the demonstration, guest details are validated in the browser and never sent, and the result says that nothing was saved and no table is held. A half-configured deployment pauses booking instead of falling back to the demo.

The evidence

What can be checked, and what the public version does not do.

Concurrency
Tested on PostgreSQL 18 with parallel connections, including a 50-round, four-way race with no deadlock and no overbooking
Automated tests
135 unit and component tests, 171+ browser tests at phone, tablet and desktop widths
Accessibility
axe on every public and console page at three widths; Lighthouse accessibility 100 on the home, menu, dish and booking pages

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 stored in a restaurant's own Supabase database
  • Confirmation and reminder emails

Explore the product

saffron-table-gamma.vercel.appTry Saffron Table yourself (opens in a new tab)

Running a restaurant or a café?

Saffron Table is what I would build for you: a menu that reads well on a phone, bookings that respect your real tables, hours and closures, and a console your staff can use on a busy night.