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.