Arrivals, seating & visits
Record arrivals and partial parties, seat a visit at tables, correct mistakes, complete service and clear tables for the next party.
A booking proves a plan; a visit proves people came. Arrivals, seating and departure are recorded on the visit — a record that is born the moment the first guest is marked arrived and ends, terminally, at departure. Every visit command runs under the venue’s write lock, so two staff members working the same party can never double-count a guest or seat two parties onto one table.
Where the actions live
- The console booking page — open a booking from the service board. It shows “Record arrival”, “Seat the party” and “Complete & clear”, each one only while it applies.
- The operator panels at
/app/panels— “Arrivals / seating / clear (DEV-024 panel)” exposes the same commands with the extra fields (corrections, request-key replay), and “Service view / walk-in / move table (DEV-025 panel)” adds table moves and its own walk-in intake.
Roles: hosts and door staff record arrivals; managers correct counts; seating and clearing need host or above — door staff never seat.
Visit states
| State | Meaning | How it is reached |
|---|---|---|
| (no visit row) | Nobody recorded yet | the visit is created lazily on the first arrival |
NOT_ARRIVED |
An earlier arrival was undone | a manager correction back to 0 |
PARTIALLY_ARRIVED |
Some of the party is here | an arrival below the party size |
ARRIVED |
The whole party is here | an arrival reaching the party size |
SEATED |
The party is at its planned tables | the seat command |
DEPARTED |
Finished; tables released | complete-and-clear — terminal |
There is exactly one visit per booking, ever. Before the first arrival there is no visit row at all — the board simply shows no “Arrived” text for the booking.
Record an arrival
On the console booking page, “Record arrival” takes “Guests at the door” (default 1) and answers “Arrival recorded — {n} of {party} at the venue.”. The panel form takes “Arriving count (blank = 1)” plus a request key (leave blank to mint a fresh one).
The rules the door works under:
- Only a
CONFIRMEDbooking takes arrivals. A cancelled, no-showed or still-pending request refuses withRULE_VIOLATION. Fix the booking first — see Changing & cancelling. - The counter can never pass the party size. An arrival that would exceed it fails with
RULE_VIOLATION— including the loser when two staff record the final guests at the same moment. - Partial parties are normal. Record 2 of 4 now and the rest when they reach the door; the visit flips to
ARRIVEDexactly when the count reaches the party size. - The request key is the replay identity. Re-sending the same arrival under the same key returns the current truth instead of counting anyone twice; a different arrival under a used key is refused with
VISIT_EVENT_MISMATCH— use a fresh key for the new intent. - Departed parties stay departed. Another arrival after
DEPARTEDanswersVISIT_INVALID_TRANSITION(“The party has already departed.”).
Correct a wrong count
Corrections are manager-only, and they set the absolute count — not a delta — with a required reason (up to 300 characters). On the panel these are the fields “Correct arrived count to (manager; overrides count)” and “Correction reason (required with a correction)”.
| Correction target | Resulting state |
|---|---|
0 |
NOT_ARRIVED — the recorded arrival is undone |
| Between 1 and the party size | PARTIALLY_ARRIVED |
| Exactly the party size | ARRIVED |
| Any of the above on a seated visit | stays SEATED — a correction adjusts the count, never the seat |
A count that already matches the visit is refused with VALIDATION: “The count is already exactly that — nothing to correct.”. Corrections append compensating events with the reason recorded alongside; history is never rewritten.
Seat the party
Seating turns the plan into physical occupancy. It needs all four of:
- a
CONFIRMEDbooking, - at least one recorded arrival,
- live allocations (the booking’s current tables), and
- the expected visit version, as an optimistic-concurrency guard.
The console button “Seat at planned tables” appears once at least one guest has arrived; the panel form “Seat party” takes “Expected visit version”. Success stamps the seating time and creates an active occupancy for every allocated table all-or-nothing: if any planned table is still held, the whole seating rolls back and you get OCCUPANCY_CONFLICT naming the holder — table, holding time, confirmation code and guest name.
Other refusals: VISIT_STALE means someone moved the visit first — reload the version and retry. VISIT_INVALID_TRANSITION means the visit cannot seat (nothing arrived, already seated, or departed). RULE_VIOLATION means the booking is not confirmed or has no live allocations.
Complete service and clear the tables
Complete-and-clear is the only act that ever frees a table. The console button reads “Record departure, release tables” and answers “Departure recorded — tables released for cleaning.”; the panel form is “Complete and clear table”.
One command does two things in the same update: the visit becomes DEPARTED (terminal) and every held table moves to CLEANING with its release stamped — the tables leave the live floor on the next refresh. The booking’s own status is untouched by any of this: a party whose booking was cancelled at the table can still be cleared, because the party was physically there.
A timer never frees a table. Nothing time-based releases occupancy. A party that overruns its booked end keeps holding its table — it stays on “Floor right now”, and any seating attempt at that table fails — until a staff member records the departure. When
OCCUPANCY_CONFLICTnames the holding party, walk over with the confirmation code and name it gives you, thank them, run complete-and-clear on their visit, and seat the next party.
Move a party to another table
The panel’s “Move party to another table” form takes the reservation id, the expected reservation version and the target table ids (comma-separated; an approved combination works too). The move goes through the same allocator as booking, so it can never produce a double-held table — and when a seated party moves, the old table flips to CLEANING for bussing while the new one takes the occupancy. Only a confirmed booking can be moved (RESERVATION_INVALID_TRANSITION); a taken target answers OCCUPANCY_CONFLICT with the current placement attached.
Error codes at the door
| Code | When you see it | What to do |
|---|---|---|
RULE_VIOLATION |
wrong booking status, or an over-cap arrival | read the message; fix the booking or the count |
VISIT_STALE |
another actor moved the visit first | reload the version and retry |
VISIT_INVALID_TRANSITION |
the state forbids the action | seat only after an arrival; never after departure |
VISIT_EVENT_MISMATCH |
a request key recorded a different arrival | use a new request key |
OCCUPANCY_CONFLICT |
the table is still physically held | resolve the named holding party first |
VENUE_LOCK_TIMEOUT |
the venue is busy | retry the same request — it is safe to |
The full catalogue with remedies lives in Error codes & fixes; the waitlist’s own table offers are a separate flow, described in Waitlist.