Lock a floor, room or table
/api/locksHolds part of the room back from booking; a private function on the mezzanine, a table kept for the owner's guests; without shutting the venue.
This is not a closure. A book_blocked_periods row with no provider (0011) takes the WHOLE venue off sale; this takes one floor, room or table. Migration 0047 keeps them in separate tables deliberately: a lock necessarily has no provider, so had it been a fourth nullable column on book_blocked_periods, the four public routes that spell "fetch the venue closures" as provider_id is null would have started shutting the venue over one held two-top.
Enforced, not decorative. Locks reach the allocator as occupancy, so all four public reservation paths honour them: the availability grid, the checkout POST, the table picker and guest self-service reschedule. A date left with nothing bookable by locks alone reports reason: "locked" on the availability endpoint and is never offered a waitlist, no cancellation frees a table the venue deliberately held back.
Staff, not admin, matching every sibling in this hierarchy. Deleting is the admin half.
Authorization
sessionCookie 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
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Response Body
application/json
application/json
application/json
application/json
curl -X POST "https://example.com/api/locks" \ -H "Content-Type: application/json" \ -d '{ "date": "string", "scope": "level", "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08" }'{ "ok": true, "lock": { "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08" }}Area locks touching a date GET
Every lock overlapping one UTC calendar day, whatever tier it names. A lock running 22:00 into tomorrow's 02:00 is returned for **both** days; a host looking at either one needs to see it. The overlap test is the same half-open comparison the allocator applies to instants and the public booking routes apply in SQL, so this screen and the booking page can never disagree about whether a lock covers a day.
Remove an area lock (admin) DELETE
Puts the floor, room or table back on sale. Admin where creating one is staff, matching `book_tables`/`book_areas`/`book_levels`/link groups; it reads backwards until you notice which direction is dangerous: adding a lock is protective and reversible, removing one is what lets a booking land on top of the function it was holding. There is no PATCH. 0047 grants no UPDATE and writes no update policy: a lock is two instants and a subject with nothing derived from it, so "move it an hour" is a delete and an insert either way.