Documentation
The operations hub and what it checks
How each readiness card is counted and dated, which workflow calculation boundaries the code actually keeps, and why green does not mean usable.
Last reviewed against the product on .
The workspace navigation calls this page the Operations hub. It does two jobs: it reports whether your workspace holds enough evidence to calculate anything, and it routes you to the four workflows that do the calculating. It performs no calculation of its own.
Readiness is a count, not a check
Each readiness card runs one count against one table, scoped to your organization, and turns green the moment that count rises above zero. The headline badge asks for three of those counts at once: at least one menu item, at least one recipe ingredient and at least one purchase row.
| Card | Counts | Dated by |
|---|---|---|
| Purchase evidence | Purchase records | The latest purchase date |
| Menu structure | Menu items, with ingredients beside them | The newest menu item created |
| Import history | Import runs | The newest run created |
| Planning models | Saved scenarios | The newest scenario created |
Measured from app/app/tools/page.tsx.
Readiness also says nothing about whether the three bodies of evidence match each other. A menu item, an ingredient and a purchase row can all exist while every costing line stays unresolved, because matching happens on names and units rather than on counts.
The four workflows, and whether their stated boundaries hold
Each workflow card prints a calculation boundary. Three of them are equations, and all three are accurate descriptions of the code that runs.
| Workflow | Stated boundary | Verdict |
|---|---|---|
| Recipe and menu costing | Quantity divided by usable yield, times the latest matching unit price | Accurate |
| Supplier price and spend analysis | Comparable price change times matching observed spend | Accurate |
| Cost and volume forecasting | Observed daily spend times horizon, cost factor and volume factor | Accurate |
| Competitor and guest intelligence | Sources stay separate until a comparable basis is documented | A policy, and not kept everywhere |
Measured from app/app/tools/page.tsx, checked against src/lib/planning/calculations.ts and src/lib/analytics/engine.ts.
The fourth card states a rule rather than a calculation, and the rule is broken one page away. The review workspace does keep ratings separate by named source. The Reports page does not: it averages every imported rating into a single figure regardless of source. That is set out in what the Reports page totals.
The forecasting window is worth one extra sentence, because it behaves like the dashboard rather than like a calendar. The baseline window is counted backwards from your most recent purchase, not from today, so a workspace that stopped importing in spring still projects from a full window.
Matching is exact, so most of the work is naming
An ingredient is priced from the most recent purchase whose reduced item name and reduced unit both equal the recipe's. Nothing is converted along the way.
- Canonical units
- 8
- each, kg, g, lb, oz, l, ml and case
- Unit conversion
- None
- a recipe in grams cannot use a price quoted in kilograms
- Usable yield accepted
- 0 to 100%
- zero is refused, and so is anything above one hundred
- Reasons a line stays unresolved
- 5
- invalid quantity, invalid yield, no purchase, unit mismatch, no unit price
Measured from src/lib/planning/calculations.ts.
A unit the aliases do not recognise is not rejected. It is reduced to its letters and digits and compared as it stands, so a recipe in bunches will match a purchase in bunches and nothing else. Where a purchase carried no unit price, the line falls back to total divided by quantity. Where neither is available, the line is reported as unresolved rather than estimated, and costed totals stay separated by currency exactly as they do everywhere else.
What the hub will not tell you
For the recipe side in detail, see menus and recipes. For what the importer will and will not accept, see the import contract.