RestaurantsIn development2026

InvtoryX

Back-of-house for restaurant groups that have more than one house.

Ingredients tracked across every site, recipe-level food costing, suppliers and purchase orders, with stock deducted as orders land. Built for multi-location groups, where the hard part is that a person's authority changes depending on which restaurant they are standing in.

Multi-location
roles resolved per site
Recipe-level
food cost, not category-level
Phase 3
of a phased migration

The problem

Food cost is known monthly, and by then it is history

A group counts stock at month end, compares it to purchases, and learns what margin was four weeks ago. By the time a bad supplier price or an over-portioned dish shows up in the number, it has been running for a month across every site.

How it was built

In order, and why.

  1. 01

    Model the recipe

    Menu products decompose into raw materials through a bill of materials, so selling a dish is an event that consumes specific quantities of specific ingredients. Cost follows from that rather than being estimated.

  2. 02

    Make location real

    Not a locationId column. A guard resolves the effective role a user holds at the site being accessed, cached in Redis and covered by integration tests, because multi-unit permissions are where this category usually breaks.

  3. 03

    Close the loop

    Suppliers, purchase orders and receiving, so stock moves in as well as out and the ledger reflects what is actually on the shelf rather than what was theoretically ordered.

  4. 04

    Migrate in phases

    Built as a phased migration rather than a single cutover, each phase shipping something usable. Currently at phase three, with the suppliers slice next.

The part that was actually hard

Multi-location is a permissions problem wearing an inventory costume

Most inventory software adds multi-site by putting a location column on every table. That falls over the first time somebody manages two restaurants with different authority at each, or a head-office user needs read access everywhere and write access nowhere. InvtoryX resolves an effective role per user per location on each request, caches it in Redis so it does not cost a query every time, and covers it with integration tests. That one decision is most of what makes the system hold together as a group adds sites.

What it does

The features that carry it.

01

Per-location roles

A regional manager at one site and a viewer at another, resolved per request by a guard rather than assumed from a single global role.

02

Recipe costing (BOM)

Menu items decomposed into raw materials, so food cost is computed from the actual recipe rather than estimated by category.

03

Automatic stock deduction

An order lands, the recipe resolves, and the ingredients come off stock. Inventory reflects trading rather than the last time somebody counted.

04

Suppliers & purchase orders

Ordering, receiving and the reconciliation between what was ordered, what arrived and what was invoiced.

05

Multi-site reporting

The same question answered per location and across the group, which is where single-site tools stop being useful.

06

Integration-tested permissions

Every role covered by tests asserting what it cannot do. Permission bugs in a multi-tenant system are silent until they are serious.

Outcome

What actually changed.

01

Authority that matches reality

A user can hold a different effective role at each location, resolved per request and cached, which is the case single-role systems cannot express at all.

02

Cost from the recipe, not an estimate

Menu items decompose into raw materials, so food cost is derived from what a dish actually consumes rather than averaged by category.

03

Each phase usable on its own

Built as a phased migration rather than one cutover, so value lands at the end of each phase instead of only at the end of the programme.

In hindsight

What we would do differently.

We would write the authorisation tests before the authorisation code rather than alongside it. Every permission bug we found in that layer was found by a test written after the fact, which is an uncomfortable thing to notice: it means the bugs still in there are precisely the ones nobody has thought to write a test for yet.

Built with

The stack underneath.

Backend
NestJS, Prisma, PostgreSQL, BullMQ
Frontend
Next.js, React, TypeScript
Mobile
Expo, React Native
Authorisation
Per-location role guard, Redis-cached, integration-tested

Where it stands today

In active development at phase three of a phased migration, with the suppliers slice next. It is the newest of these builds and the least complete, which is stated plainly here because a case study that only shows finished work is not much of an account of how a firm delivers.

Practice areas this evidences

Tell us what you’re trying to build.

If something here looks like the problem you have, say so and we’ll tell you how close it actually is.

Reply time

One business day, from an engineer

Based in

Orlando, Florida · serving the United States

What happens next

  • A reply within one business day, from an engineer
  • A thirty-minute call, with no qualifying call before it
  • A written scope and a fixed number, if it fits