Coffee Inventory

Know exactly what coffee you have, and where

An append-only ledger behind every weight, so a stock figure is auditable rather than merely plausible.

The problem

Most roasteries run inventory in a spreadsheet that says 4,200 kg and a warehouse that has 3,940. Nobody can say when they diverged, because a spreadsheet records the answer and not the arithmetic.

Every gram has a reason

Nothing changes a weight except a ledger entry. Receipts, splits, transfers, roast consumption and recounts are all rows, in order, each carrying the balance it produced.

  • One write path, so no screen can adjust stock without an entry
  • A per-lot sequence number makes concurrent writes safe by construction
  • Nightly reconciliation ALERTS on drift rather than silently correcting it — silent correction hides the bug that caused it

Bags are not a mass unit

A Colombian bag is 69 kg and a Brazilian one is 60. The factor lives on the lot, so 275 bags is 18,975 kg or 16,500 kg depending on which lot it is — and never an average of the two.

  • Weights are exact decimals, not floats: SUM() is the audit
  • Your entered value and unit are stored alongside the canonical kilograms
  • Locations track their own balances within a lot

Reserved is not the same as gone

Allocating coffee to an order records a claim; the weight leaves inventory at fulfilment. That distinction is what stops the same kilogram being promised twice while keeping the physical count honest.

Everything here is in the API

This area is inventory.green.* — the same operations the console calls.