A custom inventory management system that replaced a brittle multi-spreadsheet workflow with a purpose-built web app — including real-time stock tracking, automated tax reports, and a procurement flow the team actually uses.
Svendborgsund Bryghus had grown from a two-person passion project to a team of eight. Inventory still lived in four loosely related spreadsheets — one per category, manually synced every Friday, by hand.
Tax reporting was a half-day exercise. Procurement was a phone call followed by hand-entering receipts. The owner wanted a system before the next SKAT audit.
I spent the first week not writing code. I followed the head brewer through a full brew cycle, watched the Friday reconciliation from start to finish, and sat in on the monthly procurement call.
The pattern was clear: the pain wasn't the spreadsheets themselves — it was that three people were maintaining three different versions of the truth, and reconciliation was the only checkpoint.
Rather than migrating the spreadsheet model into a database, I modelled stock as a stream of events — every batch produced, every ingredient consumed, every delivery received — and derived current state from that log. This gave us an audit trail for SKAT for free.
Each stock movement — intake, consumption, waste, adjustment — is an immutable event. Current inventory is a materialised view over that log. This pattern gave us audit-readiness on day one and made the SKAT export a two-line query.
-- materialised current stock per ingredient
SELECT
ingredient_id,
sum(qty) FILTER (WHERE kind = 'intake') AS received,
sum(qty) FILTER (WHERE kind = 'consumed') AS used,
sum(qty) FILTER (WHERE kind = 'intake')
- sum(qty) FILTER (WHERE kind = 'consumed')
- coalesce(sum(qty) FILTER (WHERE kind = 'waste'), 0)
AS on_hand
FROM stock_events
GROUP BY ingredient_id;
-- SKAT afgiftsrapport — ethanol produced last quarter
SELECT
date_trunc('month', produced_at) AS month,
sum(volume_litres * abv / 100) AS pure_ethanol_litres
FROM batch_events
WHERE produced_at >= now() - interval '3 months'
GROUP BY 1
ORDER BY 1;The brewhouse floor has water, CO₂, and people in a hurry. The interface needed to be operable with one hand on a 10-inch tablet, with large touch targets and no tiny form fields.
I used a step-based intake flow — scan barcode, confirm quantity, done — so a delivery receipt takes 40 seconds instead of ten minutes of back-office entry.
The dashboard adapts to three roles: the brewer sees live batch status; the owner sees stock value and margin; the accountant sees the SKAT-ready export queue.
We ran the new system alongside the spreadsheets for two weeks. Every Friday reconciliation was done twice — old way and new way — and results compared. The last delta was a single barrel of malt that was logged in both systems on the same day. Fixed in ten seconds.
I thought I'd need to explain it to the team. They figured it out in an afternoon. The SKAT audit was the first one in five years with zero follow-up questions.
Four hours of weekly reporting collapsed to zero — the SKAT export runs with one click. Inventory accuracy jumped from a best-guess to a measured 99.9%, and the first tax audit under the new system came back clean.
The team picked it up in an afternoon. The brewhouse tablet is the first thing the head brewer checks in the morning.
No open slots right now — but reach out and I'll add you to the waitlist.