Booking Algorithm — Deep Dive
Every booking needs a table. Picking the wrong one wastes capacity, frustrates guests, and leaves money on the table.
Seat a party of 2 at a 6-top, and that table can't serve a larger party. Multiply by 50 bookings a night.
Guest requests a patio seat, gets the bar. Guest books for a quiet dinner, ends up next to the kitchen.
Staff manually juggling tables on a busy Saturday night. No time to think about optimization — just survival.
Our algorithm solves this automatically — every booking, every time.
The brain and the body. The algorithm thinks. The engine acts.
packages/booking-algo
packages/booking-engine
From a booking request arriving to a table being assigned
Each layer answers one question. If any rejects, later layers don't run.
"Can we accept more guests right now?"
"Which tables pass the 7 hard constraints?"
"Can we push tables together for large parties?"
"Does this time block fit without overlapping?"
"Which eligible table scores best on 6 factors?"
"Can we rearrange all reservations for a better plan?"
When a single table can't fit the party, the algorithm searches for tables to push together. But combined tables don't seat the sum of their parts.
The restaurant explicitly sets these up in the floor plan editor. "Tables 5 + 6 can combine into a 10-top." Uses the stored capacity as-is — the restaurant already factored in seat loss.
The algorithm finds physically adjacent tables using the adjacency graph from the floor plan. Chains up to 3 tables. Deducts seat loss per edge automatically based on table shapes and which sides touch.
When two tables are pushed together, chairs on the joining sides are removed. The algorithm handles this automatically, and restaurants can override per edge.
| Scenario | Raw | Loss | Effective |
|---|---|---|---|
| Two square 4-tops | 8 | 2 | 6 |
| Two narrow 2-tops facing | 4 | 0 | 4 |
| Round 6-top + square 4-top | 10 | 3 | 7 |
| Three 4-tops in a chain | 12 | 4 | 8 |
Staff can override seat loss per join in the floor plan editor. Setting it to 0 means "no seats lost at this join."
Every table gets a score from 0 to 1. The highest score wins.
Weights are configurable per service. Restaurants choose their strategy — or create a custom blend.
When a booking can't be fulfilled, the algorithm doesn't just say "no" — it suggests better options.
Staff can override the algorithm when they need to. Two lock levels give the right balance between automation and control.
Immovable. The algorithm never reassigns this table.
Preferred but movable. The algorithm prefers this table via scoring but will reassign if a better arrangement exists.
Control which tables are bookable on which channels. Not every table should be available to every booking source.
| Level | Source | Example |
|---|---|---|
| 1 — Most specific | Per-service override | "Table 5 is walk-in only for Saturday Dinner" |
| 2 | Per-table default | "Table 5 is usually walk-in only" |
| 3 | Per-zone default | "Garden Patio zone is walk-in only" |
| 4 — Broadest fallback | All active channels | Nothing configured — all channels allowed |
When staff view table suggestions, they see a quality score and human-readable reasons — not just a list.
| Score | Label | Color | Meaning |
|---|---|---|---|
| 0.80 — 1.00 | Best fit | Green | Right size, good section, good spacing |
| 0.60 — 0.79 | Good fit | Blue | Acceptable — slightly oversized or busy section |
| 0.40 — 0.59 | Available | Gray | Functional but not ideal — oversized or tight timing |
| Below 0.40 | Hidden | — | Poor fit — not shown to staff |