How the assistant picks slots
A structured request walks in. The scheduler walks out with two or three slots that fit the customer’s window, your working hours, the service’s real duration, the buffer you need before the next appointment, your blackout dates, and which staff member can do which service. The trick is doing this entirely on top of Google Calendar — never a parallel database that drifts.
The calendar is the source of truth
Most booking systems get into trouble by keeping a parallel availability database. The calendar says one thing; the database says another; somebody books over an existing event because the database is stale. The fix here is to never have the parallel database in the first place. Every availability check goes to Google Calendar’s freebusy API at request time, and every confirmed booking is written to the calendar atomically (the next post is about that).
The freebusy API is fast (typically under 100 ms for a 7-day window across a small number of calendars) and free at the volumes a small business sees. Caching is tempting but unnecessary; the latency budget for a slot proposal is several seconds, of which the calendar query is a small slice.
Stage 1 — Calendar query
The scheduler asks the calendar for free intervals across every staff member who can perform the requested service. The service-rules file maps each service to a list of qualified resources (people, rooms, machines), and the scheduler queries the calendars of all of them in a single freebusy call. The result is a list of free intervals per resource, in the customer’s requested window.
Stage 2 — Working hours
The freebusy API doesn’t know your working hours; it just knows what’s on the calendar. The scheduler intersects each free interval with the business’s open hours from the rules file. A free interval from 11pm to 9am is real on the calendar, but useless to the customer; this stage drops it.
Per-staff working hours are supported here too — the rules file can specify that stylist A only works Tuesday–Saturday, while stylist B works Monday–Friday, and the scheduler intersects against the right set per resource.
Stage 3 — Duration and buffers
The service has a real duration (a basic haircut takes 30 minutes; a colour takes 90; a first visit takes 60 because of intake forms). It also has buffers — the time you need before and after the appointment for setup, cleanup, or breathing room. The scheduler slides a window of (duration + pre + post) minutes across the surviving free intervals at a configurable step size (15 min by default), and emits one candidate start time per fit.
Buffers are why this isn’t just “is this slot free?” If the previous appointment ends at 2:00 and your post-buffer is 10 min, the next bookable start is 2:10, not 2:00. Skipping this is how you end up with no time to clean up between clients.
Stage 4 — Blackouts and capacity
Two more cuts. The blackout list (public holidays, your annual leave, the day the salon is closed for inventory) drops candidate starts that fall on those dates. Capacity caps drop candidates that would push the day or the resource over a configured limit — useful for businesses where the constraint isn’t just “the staff member is busy” but “we only do four colours per day so we don’t run out of dye.”
Stage 5 — Rank and pick
What survives gets ranked by preference, and the top 2–3 are returned. The default ranking puts earliest-in-window first (most customers want the soonest slot), then prefers the customer’s usual staff member if known, then prefers slots that smooth the day’s utilisation rather than concentrate it.
The ranking is configurable in the rules file, not hard-coded. Some businesses want the opposite — pack the morning so afternoons are free; some want premium services to go to the senior stylist by default. One config line, no deploy.
When nothing fits
Sometimes there’s nothing in the customer’s window. The scheduler doesn’t shrug; it offers the nearest alternative window (“Tuesday afternoon is fully booked, but I have Wednesday morning”), or escalates to a human if the alternative would be a substantial change. A polite decline is one of the four moves — not an error.
In plain words
Five filters in order. Get free time from the calendar. Trim it to working hours. Fit the service’s actual duration plus buffers. Drop blackouts and over-capacity slots. Rank what’s left and propose the top two or three. The scheduler does no thinking the calendar and the rules file haven’t already authorised.
All posts