Restaurants · Internal system
Ostera
A chain of 64 restaurants: figures from five systems in one layer, where a question about yesterday’s profit is asked in plain words and answered with the data behind it.
- Role
- Analytics, backend, integrations, AI assistant
- Timeline
- 10 weeks
- Stack
- NestJS · ClickHouse · OpenAI API
What changed
- 2 hours → 18 minutes
- on the daily operational review. The figures are assembled before anyone opens them — what is left for the manager is the decision.
- 4–7 days → a day
- average time between a deviation and somebody seeing it: under 24 hours now.
- −17%
- write-offs across the pilot group restaurants over the first three months.
- +3.8 pp
- on the average operating margin of the ten pilot sites.
Nothing was replaced: the tills, the stock system and the delivery services stayed where they were, and no manager was made to fill in a new form. That sets the limit too — whatever the sources do not hold, the platform cannot show.
Before
A regional manager’s morning began with the till system, the stock program, the aggregators’ back offices and the spreadsheets from the sites: he pulled his restaurants’ figures together by hand, one source at a time. Head office got a stack of reports, each one somebody else’s identical morning. A problem with food cost or write-offs showed up there days after it started.
- 64 restaurants across three cities, and no two of them alike. Comparing a pair of sites began with whether the figure had been calculated the same way at both — and often ended on that question.
- More than 40 daily reports and spreadsheets landed at head office. Not 40 answers: 40 slices that still had to be added into one.
- Around 2 hours of every morning went on a regional manager assembling figures — before he had got as far as deciding anything from them.
- Between 4 and 7 days passed between a drift in food cost or write-offs and anyone noticing it. By then a week of the site’s trading had already gone the same way.
What we built
One metric layer: 47 figures calculated from a shared definition across all 64 restaurants, rather than reassembled inside every report.
Five sources in one model: tills, stock, delivery aggregators, spreadsheets from the sites and time and attendance, tied together by one catalogue of restaurants and items.
The assistant answers a question put in plain words and shows the rows the answer stands on; the morning summary goes out with nobody asking for it.
Outcome
The tills, the stock system and the delivery services were left alone — they became sources, and the reading of the figures moved into a layer above them. The operations director asks in plain words and gets the answer with the data it was built from; a deviation reaches a person the same day, and the morning summary arrives before anyone thinks to look. What to do about a restaurant is still a person’s call: the platform brings the number and the hypothesis that far, not the action.
The client
A restaurant chain: 64 sites across three cities, each with its own kitchen, its own store room and manager. Above them is head office, which answers for the economics of the whole chain and, until this project, saw it only through reports sent up from below.
A site has dine-in takings and orders through the aggregators, purchases and write-offs, shifts and staff hours — all of it in different systems. A regional manager runs several restaurants at once, so those figures were added up as many times as he had sites.
The brief
- What the client asked for
- One dashboard with restaurant sales: takings for all 64 sites on a single screen, so that nobody had to go and find them across forty-odd spreadsheets.
- What the brief turned into
- Interviews with the site managers showed another dashboard would change nothing. There was enough data; what was missing was interpretation. The figures agreed but never said why. So we built an assistant for the operations director instead: asked in plain words — which restaurants have had food cost rising for three weeks — it gathers the figures, finds the anomalies, forms a hypothesis and shows the data behind it.
Why the obvious route was closed
The hard part was never the language model. The data sat in five places, each with rules of its own, and before the assistant had anything to answer with, all of it had to be brought into one model with an agreed way of calculating every figure.
- The till system
- Receipts, dine-in takings and average spend live in the POS at each site. That covers what happened in the room, but write-offs and staff hours are not there — so any figure that divides takings by something else is already coming from more than one source.
- The stock system
- Purchases, stock on hand and write-offs: the half of food cost the till never sees. For a figure to hold, a stock movement and a dish sold have to meet on the same catalogue line, and they did not always meet.
- The delivery aggregators
- Part of the takings arrives past the dining room: the order is placed with an aggregator and cooked by the same kitchen. While delivery is counted apart from the room, comparing two restaurants depends on how much of each one’s trade came from outside.
- The spreadsheets
- Some figures existed only in files put together at the sites. A source like that has no schema and no guarantee that tomorrow’s file arrives in the same shape: it has to be parsed every day, not once at connection.
- Time and attendance
- Staff hours sit in a system of their own and refresh to their own rhythm. A figure that needs two sources refreshing at different rates has to carry a rule for when the second one has not arrived — otherwise it quietly calculates on half the data.
- The same thing under different names
- Restaurant and product names differed from system to system: one site and one item went by something else in the till, in the stock program and at the aggregator. Until those were matched, a consolidated figure was a coincidence rather than a result.
How the work ran
- 01
Data audit and the metrics
Weeks 1–2What sits where, and what can honestly be calculated from it: which fields each system gives up, where they disagree, and which figures head office actually needs. The output was not a warehouse but a list of 47 metrics, each with its sources and its period written down.
- 02
Integrations and one store
Weeks 3–5Five sources connected and brought into a single model: tills and stock, the delivery aggregators, the spreadsheets, time and attendance. The catalogue was built here too — one restaurant and one item carry one identifier, whatever the source on the other side calls them.
- 03
Anomaly detection and alerts
Week 6A layer above the calculated metrics that compares a site’s figure with its own history and sends the deviation on to someone the same day. Until this stage the platform could show a number but could not say that anything was wrong with it.
- 04
The assistant and questions in words
Week 7A question in plain words became one more way into the same metrics. The model reads the wording and picks the figures, the breakdown and the period; the arithmetic still happens in the store, and the data behind the answer travels with it.
- 05
The daily summary
Week 8The same thing with no question asked: an executive summary is assembled automatically and arrives in the morning, before anyone has got round to asking. Which sites need attention today is answered before the question is put.
- 06
Pilot and the rest of the chain
Weeks 9–10Ten restaurants first: the platform’s figures were checked against what the sites calculated themselves, and every difference was worked through before the summary went to the whole chain. All 64 sites came on after the pilot.
Technical decisions
The stack is chosen for the volume and for a question asked in words: NestJS carries the service and the five integrations, ClickHouse calculates the metrics across the chain, and the OpenAI API turns a question in plain words into a request against those metrics.
The analytical layer before the assistant
The AI went on last, on top of normalised data. The other way round, the model would have been answering from five sources that disagreed, and its mistakes could not have been told apart from the data’s. First 47 definitions and one model; only then a question in words.
One identifier per site and per item
A mapping table: a restaurant and a product each carry one internal identifier, with the names from the till, the stock system and the aggregators sitting beside it. It also answers where a line in a consolidated report came from — without it, comparing two restaurants stays an argument about names.
A metric is a definition, not a query
Each of the 47 figures is described once: sources, period, breakdown. The summary, the alert and the assistant’s answer all read the same definition, so three places cannot return three different numbers to one question.
The model picks the figures, the store does the arithmetic
The OpenAI API turns a question into a set of metrics, sites and dates; ClickHouse adds them up. The model never sums anything and holds no numbers of its own — which is why an answer can be reproduced, and why the very rows it came from can be shown beside it.
A deviation is found before the question
Anomalies are calculated in the metric layer and arrive on their own: the figure, the site, the period and what it was compared against. The director’s question and the morning summary are two doors into the same calculation — so noticing a drift no longer waits for somebody to think of looking.
What stayed outside the scope
Some of the work was deliberately left out of the platform: either the source belongs to somebody else, or the decision belongs to a person.
The data sources. The POS, the stock system and the delivery services stayed with the client, along with their rules and their own refresh rhythm: we read them and write nothing back.
Work done by hand at the sites. The spreadsheets put together on site stayed as they were: the platform reads them every day, it does not retire them. No new form was brought into the chain — and with it, no way of doing without the old ones.
Testing the hypothesis. The assistant says where a figure has diverged and what might explain it; whether that explanation matches what is happening in the kitchen is settled on site — the platform does not look there.
The effect across the whole chain. Both the 17% on write-offs and the 3.8 pp on margin come from the ten pilot restaurants. The rest of the sites came on later, and we do not yet have a comparable period for them.
The platform now runs across all 64 restaurants: the morning summary is assembled every day, and a deviation reaches the person it concerns within a day rather than within a week.
More projects
Insurance
Klarim
Reads the scanned pack behind an insurance claim: finds the fields in certificates, photos and statements and moves them into the claims system.
40 → 6 minutes
to process a single claim
Python · FastAPI · Anthropic API
Logistics
Reista
A client portal for a haulier: consignment status, route and paperwork for every delivery, with no call to the dispatch desk. The portal was the smaller half of the job — before it, no system held a status at all: it lived in drivers’ messages and in a dispatcher’s memory.
−70%
calls to the dispatch desk
Next.js · TypeScript · PostgreSQL
Contact
Send a description of the task
A reply with the scope, the timeline and a budget estimate comes within 24 hours.
The first call is 30 minutes, with no commitment on your side.