Your neighbour's order is not your order
In a food hall, every kitchen is a separate business sharing one system. That means every request has to answer "whose is this" — and a guard that watches the front door does not see something handed through the window.
A food hall is not one restaurant with several counters. It is several businesses, often with different owners, different accountants and different opinions about each other, sharing a building and a piece of software.
So the most important thing our system does is answer one question, on every single request: whose is this? Not "are you logged in" — that is easy. Whose.
How we answer it, once
Orders have numbers. So do recipes, products and invoices. When a request mentions one, we look up which kitchen that record belongs to and check the person asking is allowed there. We do it in one place that every request passes through, rather than in each handler, for a reason we learned the hard way: a rule written into nine endpoints is a rule the tenth forgets.
That check went in after somebody proved the point by attacking it — an account with access to one kitchen in one hall reading another hall's records by changing a number in the address bar. It has held since.
The door it was not watching
This week we found a request that mentions an order number, but not in the address. It sends it in the body of the message instead — the part a form submits rather than the part in the URL.
Our guard reads addresses. It had no idea the body existed. So the request walked past it, and the code behind it fetched the order by number with no question about whose kitchen it belonged to.
The route in question books a courier. A kitchen manager could, in principle, have booked a real rider against a neighbouring kitchen's order — to an address of their choosing, on the platform's account, writing the courier's details onto somebody else's record.
Nothing happened, and that is not the same as nothing mattered
No venue was exposed. The courier integration has no credentials configured and no screen that calls it, so the request refuses at an earlier gate. It is built and waiting, which is the state a lot of good software sits in.
We fixed it in that one route rather than widening the shared guard, because the other eight places that take a record number in a body all check for themselves — changing the shared rule to fix the one that forgot is a big change for a small problem.
If you are choosing a system for a hall, this is the thing to press on. Ask how separation between vendors is enforced, and specifically ask whether it is enforced in one place or in every screen. Then ask what happens when the same identifier arrives a different way. The honest answer to the second question is usually a pause.