The Restaurant Floor That Rearranged Itself
A table-reservation system for an Istanbul restaurant where the real engineering wasn't the booking form but a live floor plan that read the night's reservations off the database every half hour and regrouped, recoloured, and reset every table on its own — with every staff screen kept in agreement in real time.
A reservation system looks, from the outside, like nothing more than a calendar with better manners — a form where a name and a time and a party size go in and a tidy row comes out — and for the first few weeks of building one for a restaurant in Istanbul I believed that too, right up until it became clear that the booking was the easy half and the genuinely hard problem was the floor itself: a living, shifting arrangement of tables that drift together for a party of ten, break apart again when the night thins out, and change colour as guests arrive, settle in, and leave. This is a write-up of that harder half, the quieter machinery behind the booking form, because that is the part of the project I most want a reader to see.
The part that isn't the booking form
The restaurant ran the way most do, in sittings: an early evening seating and a later one, a Sunday breakfast, an open buffet, each with its own window of hours and its own rhythm. A host taking bookings over the phone holds the whole room in their head — which tables can be pushed together for the big group at eight, which corner empties out in time for the couple at half past nine, which section is closed tonight — and the quiet ambition of the software was to hold that same picture without ever asking a human to redraw it by hand. The booking form, the customer records, the statistics the owner liked to look at, all of that was real work but it was ordinary work; the thing that turned the project from a calendar into a system was the floor plan, and the floor plan only earned its keep once it could change on its own.
The floor as a living data model
The application was a full-stack Nuxt 3 build, a Vue front end talking to a Nitro server in Node, with everything persisted through Prisma into PostgreSQL, and the first real design decision was how to make a physical room addressable. Every table carried two positions rather than one: a home position, where it sat when the floor was at rest, and a live position, where it actually stood at this moment in the middle of service — and that small duplication, a default_location it could always be returned to and a current_location that drifted as the night wore on, turned out to be the hinge the whole feature swung on.
one table on the floor:
table_no 12
shape "round"
default_location (540, 300) ← home
current_location (580, 285) ← now, mid-service
colour the seated reservation’s status
The tables belonged to named sections — a garden bar, a main salon, a living room with a fireplace — and the front end drew them onto a floor plan as circles and rectangles sized to their real dimensions, each one filled with a colour it did not choose for itself. The colour came instead from whatever reservation currently owned the table, read off a status whose label could be something as plainly human as Gelmedi, "not arrived", so that a glance at the screen was meant to tell you the same thing a glance across the room would: this table is empty, this one is seated, this one is still waiting on its guests.
Rearranging the floor every half hour
This is the heart of it. Every half hour a timer would wake, ask the database which reservations were live at that precise moment, and for each party that had been promised more than one table it would take the lowest-numbered table as an anchor and walk the others out from it in a patient diagonal — forty pixels across and fifteen up for each table in the group — committing the whole rearrangement in a single transaction, so that the floor never flickered through a half-moved state with tables caught mid-stride between where they had been and where they now belonged.
a party of ten, three tables pushed together:
table 1 the anchor — stays where it is
table 2 +40 across, −15 up
table 3 +80 across, −30 up
( one transaction, then pushed live to every screen )
What I found quietly satisfying about the design is that there was never a "group" in the database at all. A group was not an entity you created and destroyed; it was simply the fact of several tables sharing a single reservation, made visible by the coordinates the sweep computed for them, and so it could come into being and dissolve again without anything ever needing to be explicitly torn down. A companion sweep, running on its own half-hour offset, did the dissolving: it looked for any table standing away from its home position that no longer had a live reservation to justify the move, and it sent each of those quietly back to where it belonged. Building and testing this against real clock time was the hardest part of the entire project, because the logic only made sense in motion — a table is grouped because a party is seated now, and ungrouped because that now has passed — and getting it to behave correctly meant reasoning constantly about the exact moment the code believed it was living in.
Keeping every screen in agreement
A restaurant floor on a busy night is not run by one person but by several at once — a host at the door, waiters threading between the tables, someone watching the whole room from a screen at the back — and the one thing the system could not afford was for two of those screens to disagree, so every move, every reset, and every newly written reservation went out over a WebSocket the moment it happened, and every other screen quietly redrew itself to match, until the floor on the glass and the floor in the room were telling the same story. The server announced each change on its own named channel, a tablesMoved when the half-hour sweep regrouped a party, a tablesReset when the companion sweep sent tables home, and the front end answered each announcement the same way: it went back to the database, fetched the floor afresh, and recomputed every colour, so that no client was ever left quietly reasoning from a stale picture of the room.
What the project demonstrates
Stepping back, what the project really shows is a single physical reality — a restaurant floor that hosts already knew how to manage by hand — modelled faithfully enough in software that it could manage itself: a full-stack Nuxt and Node application over PostgreSQL, a floor plan rendered from live data, scheduled jobs that reshaped that floor on a clock, and a real-time layer that kept every screen honest about it. There is an honest coda I owe the work, too: the system was finished and deployed, but it never actually opened to a single diner, because the restaurant's appetite for adopting it ran into business questions that had nothing to do with whether the software worked, and I have made my peace with the fact that a thing can be built well and still never get its night in service.
The most interesting engineering in a reservation system is not the reservation; it is everything the restaurant already knew how to do by hand — pushing tables together, pulling them apart, reading the room by colour — quietly taught to a database and made to keep itself honest every half hour.
What I keep from it is less a feature than a habit of mind: that the surest way to make software genuinely useful to people who work with their hands is to model the world they already live in faithfully enough that the screen and the room never have to be reconciled by a person.
Part of a short series of write-ups on the things I've built. See also The Savings Plan That Rewrites Itself, a savings app that rewrites its own plan, and The Job Finder That Reads Every Listing, a job search that reads every listing with local language models.