Enable a floor plan
- Go to Stores → Floor plans.
- Open a store and turn on Show floor plan.
- Add a floor. Drag tables and structure from the palette onto the canvas, draw walls corner by corner and zones as rectangles, or paste the floor JSON with Edit JSON. Select items to move, resize, or rotate them. Every action also works from the keyboard, and Undo (Ctrl/Cmd+Z) reverts any change.
- Select Save. Every floor with changes is validated and saved.
level (0 for the ground floor, negative for basements) used to sort them.
Units and coordinates
Sizes use abstract units, where 1 unit is roughly 1 meter. The origin is the top-left corner of the floor.x grows to the right and y grows downward. Every item is a box placed at x, y with a width and depth, plus an optional rotation in degrees around its center.
Floor JSON
The same schema is used by the editor, the API, and the floor plan views. It lives in@repo/validations (vStoreFloors.floor()), so every surface validates it the same way.
Every element and table has
id, x, y, width, depth, and rotation (at least 0 and below 360). Items must fit inside the floor, and ids can’t repeat on the floor.
- Elements add
kind(wall,counter,kiosk,door,column, orzone) and an optionallabel. - Polyline walls are walls that also have
points(2 to 200 corners along the wall’s centerline, in floor units) and an optionalthickness(0.1 to 2, default 0.2). Their box is the bounding box of the drawn wall and theirrotationis 0. Only walls can havepointsorthickness, and every corner must be inside the floor. Walls withoutpointsare still plain boxes, so older floors stay valid. - Tables add
label(unique per floor, case-insensitive),seats(1 to 50), andshape(square,round, orrect). Table ids are unique across all floors of the store, because the POS and reservations refer to them.
Example
How it’s stored
A floor is saved as two kinds of data, on purpose:- Structure as JSON. Walls, counters, kiosks, doors, columns, and zones are stored as one
jsonbdocument per floor (store_floors.layout). Nothing else refers to them, they’re always read and edited together, and saving them as a single document keeps each edit atomic. - Tables as rows. Each table is a row in
store_tables. Tables have their own life: the POS marks them occupied, groups them, and links them to orders, and reservations will point to them. Rows give each table a stable identity, foreign keys, row-level security, and per-row realtime updates when its status changes, without rewriting the whole floor.
Related concepts
Stores
Locations that own floor plans
Orders
Orders opened for seated groups