Self-built product — live demo and source are public
Slotly: AI Booking Assistant
Booking forms make patients guess at a time; Slotly lets them just ask, then checks the calendar before it promises anything.
- Delivered
- 2026
- Automated tests
- 54
- Ways to book — chat or form
- 2
- Role-scoped staff access
- RBAC

The problem
A booking form asks the customer to do the clinic's thinking. Pick a service, pick a practitioner, pick a date, discover nothing is free, go back, try again. Every one of those steps is a place to give up, and the ones who give up at half past nine in the evening never appear in any report — the practice simply never learns the enquiry happened.
What people actually want to do is ask. "Any chance of a cleaning with Dr Chen next week, ideally after four?" That single sentence contains a service, a practitioner, a date range and a time constraint, and a form makes you disassemble it into four separate widgets.
I built Slotly to see whether a language model could take that sentence and still produce a booking you can trust — which is the hard part, because the failure mode of a chatty booking bot is that it cheerfully confirms an appointment that does not exist.
The approach: the model talks, the database decides
The rule the whole system is built around is that the assistant is allowed to interpret, but never to decide. It does not know what is free and it is not asked to. Availability comes out of the slot engine, which reads working hours, appointment buffers, minimum lead time and staff time-off from the database, and returns the set of times that genuinely exist.
The assistant's only route to a booking is a `create_booking` tool — a validated call into the same API the web form uses. If it asks for a slot that has since been taken, the call fails and the conversation offers alternatives. There is no path where a confident sentence from the model becomes an appointment that the calendar does not agree with, because the sentence is never what creates the appointment.
That constraint is also what makes the feature honest to sell. The worst case is a patient being told to ring the practice, rather than turning up for an appointment nobody has.
Bookings made through the assistant are written with `source: 'assistant'`, separate from form submissions. Without that you cannot answer the only question that decides whether the feature is worth keeping: is anyone actually using it?
What was built
A monorepo in three parts: a React 19 client built with Vite 7, Tailwind CSS v4 and TanStack Query; an Express API using Mongoose and Zod, with `@google/genai` driving the assistant; and MongoDB underneath. Client and API deploy as a single Vercel project, with the Express app running as a serverless function — one origin, so there is no CORS layer to get wrong.
Two ways to book, sharing one source of truth. The four-step wizard is for people who prefer to click; the chat assistant is for people who would rather just say what they want. Both go through the same validation and the same conflict checks, so neither can produce a booking the other would consider impossible.
The staff side is a real application rather than a list view. Login verifies a bcrypt hash and issues a seven-day JWT, rate-limited to five attempts a minute. Role-based access gates the admin endpoints, and staff are scoped to their own appointments — enforced server-side, so a staff account cannot read a colleague's diary by changing an ID in the URL. A 401 clears the session and returns you to login rather than leaving a half-authenticated page on screen.
Dashboard metrics — today's bookings, utilisation, revenue, seven-day trend, per-practitioner load, and the split between assistant and form bookings — are computed on the server from the appointment records. The client renders numbers; it never derives them, so two people looking at the same dashboard cannot see different figures.
Testing, and keeping a public demo alive
54 tests, aimed at the parts where being wrong is expensive. The slot engine is tested against working hours, buffers, lead time and time-off. The utilisation maths is tested as pure functions, including the interval-overlap cases that are easy to get subtly wrong and hard to notice. The admin surface is tested over the real HTTP stack against an in-memory MongoDB — login, authorisation, and the demo-reset endpoint included.
A public demo also has a problem no client project has: visitors change the data. Left alone for a week, the calendar fills with test bookings and cancellations and stops demonstrating anything. So a nightly Vercel cron drops and reseeds the demo at 04:00 UTC. That endpoint requires demo mode to be switched on and does a constant-time comparison against a secret, so finding the URL is not enough to trigger it.
Where it stands
Slotly is live and the source is public, so both claims on this page can be checked rather than taken on trust. Sign in to the staff dashboard with the demo credentials in the repo's README and everything described above is there to poke at.
It is a product I built to demonstrate an approach, not a system a dental practice currently runs on — the figures on the dashboard are seeded demo data, and I would rather say so than let a screenshot imply a customer base I do not have.
The part that transfers to client work is the constraint, not the chat window. When an AI feature sits in front of real business data, keeping every hard rule in the database and treating the model as an interface layer is what makes the result safe to put in front of customers. That is the pattern I reach for whenever a project puts an assistant near something that matters.
Screenshots





Have something like this to build?
Send me a message. You'll get a straight answer about whether it's worth building, roughly what it would cost, and how long it would take.