Save one floor's decor elements
/api/floor-planReplaces the decor (walls, doors, stairs, bar, stools, plants, text labels; migration 0092) for one canvas wholesale: levelId null means the venue's single implicit floor. Element geometry is in the same grid units as table geometry. Strict on write; the read side re-parses leniently and drops junk, so a malformed element here is a 400 naming the problem rather than a silent shrink.
The backdrop image (0094) is positioned and faded through the background* fields here, but its URL deliberately is NOT settable: background_url is written only by POST /api/floor-plan/background, from a file that route just placed in this app's own bucket, so no request can aim a venue's canvas at an arbitrary external image.
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
application/json
curl -X PATCH "https://example.com/api/floor-plan" \ -H "Content-Type: application/json" \ -d '{ "elements": [ { "id": "string", "kind": "wall" } ] }'{ "ok": true}Remove a furniture-set combo DELETE
Deletes the combo (its book_furniture_set_combo_members rows cascade). The piece's own real member rows are untouched: this only withdraws staff's permission for the allocator to combine that particular subset, and each member goes back to being bookable only on its own unless another configured combo still covers it.
Upload the backdrop image for one floor POST
The venue's own plan (an architect's drawing, an evacuation diagram, a photo of the host-stand sheet) stored in the public `floor-plans` bucket at `{companyId}/{levelId|none}` and painted under the canvas so drawn tables can be aligned to it (migration 0094). `multipart/form-data` with `file` and an optional `levelId`. Re-uploading replaces the object at the same path and cache-busts the URL, keeping whatever box the venue already aligned; a first upload seeds a 40x30-unit box, which the editor then drags to fit.