Hospitality engine

Text a "waiting now" guest that their table is ready

post/api/waitlist/{id}/table-ready

The source: 'staff' mirror of POST .../offer: the same member-scoped tenant check, refusal shape and send-then-mark ordering, but texts via SMS rather than mailing, since a source: 'staff' entry carries a phone and commonly no email at all. Refuses a source: 'online' entry (409): it has no guaranteed phone number, and "your table is ready" makes no sense for a future date nobody has actually booked yet.

Send first, mark second, deliberately: marking first would make notified a lie whenever the SMS provider is down. Logged into book_notification_log against waitlistEntryId with type table_ready.

Authorization

sessionCookie
sb-qxrvgfkjyvbngipqvslu-auth-token<token>

The dashboard's Supabase Auth session cookie, set at sign-in. Large sessions are split across numbered chunks (…auth-token.0, .1), so treat this as a cookie family rather than one name.

Every request re-validates it against the Auth server (getUser()), never by decoding the cookie locally: a JWT nothing has checked is not a credential. Tenancy is then read from the verified app_metadata.company_id claim and enforced by row-level security; it is never read from request input, on any route, ever.

role (admin / staff) is deliberately not in RLS. It gates specific actions in route code, the operations marked admin below, so hiding a button in the UI is cosmetic only, and a route's own check is the enforcement.

In: cookie

Path Parameters

id*string

Waitlist entry id.

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

curl -X POST "https://example.com/api/waitlist/string/table-ready"
{  "ok": true}

Offer a waitlisted guest a table POST

The staff-triggered half of the waitlist, in one button. Emails (and texts, if the guest left an E.164 number and the org has SMS on) a link back into the booking flow prefilled with the date and party size, then sets the entry to `notified` with `notifiedAt`. **Send first, mark second**, deliberately. Marking first would be the tidier transaction, but `notified` would then be a lie whenever the mail provider is down: the list would show the guest as offered, nobody would offer them again, and the table would go empty. Failing the other way produces at worst a duplicate "a table has come free" for a table that is in fact still free. Every attempt is recorded in `book_notification_log` against `waitlistEntryId` with type `waitlist_offer`; the third subject 0044 added to that table. There is **no dedupe index** on this subject, so re-offering is legal and expected: the 7pm cancellation the guest did not answer is followed by an 8:30 one an hour later. **v1 is staff-triggered and there is no auto-broadcast.** "First to reply Y wins" needs inbound SMS, which does not exist anywhere in this codebase.

Close out a waitlist entry PATCH

Sets `status` to `converted`, `expired` or `cancelled`. **`notified` is deliberately NOT settable here**, and it is the only interesting rule on this route. That status is a claim about a message that left the building; setting it from a plain PATCH would let the list show an offer that was never sent, with the guest waiting at home for an email nobody dispatched. Only POST ./offer writes it, after the send. The three end states are terminal; a `converted` entry cannot be dragged back to `open` and offered again to a guest who is already booked. No minRole: clearing a waitlist is ordinary floor work.