All Work

PlotWise

An internal inventory platform for agricultural R&D field operations, built on an immutable transaction ledger. Live across 10+ sites in two countries.

Design + Build · Solo
Sites
10+
Countries
2
Languages
EN · ES
Builder
1
02(Context)

PlotWise is built on one rule: never edit a balance. Stock, value, expiry, and usage all derive from an immutable transaction log, so every number traces back to who moved what, and when. It replaces the disconnected spreadsheets that field operations ran on, used daily by operators working on their feet, not at a desk.

03(Design)

The whole interface is built on the ledger, not on editable fields. You never type a new quantity; you record a movement (receive, use, check out, or adjust) and the balance is derived. The history stays intact and auditable, and a mistake is corrected with another transaction rather than a silent overwrite.

The primary field actions live in a persistent bottom bar sized for a thumb: home, scan, receive, checkout, usage. For someone entering twenty records between rows of plants, the common path stays one tap away instead of buried in a menu.

Scanning is tuned for the field, not the warehouse. The scanner looks up a container's own label before falling back to a product barcode, because in trial operations the thing in your hand is a specific container, and that is what the user actually needs to find.

04(Engineering)

A Postgres ledger sits at the core: immutable transaction rows, balances derived through views like an on-hand rollup rather than stored, and a schema of items, categories, locations, lots, checkouts, and import tracking around them. Row-level security enforces per-site and per-region access at the database, through a can-access-site check, so the rules hold no matter which client is talking to it. Server components read through request-scoped Supabase clients while the interactive forms write transactions directly, and the same access model is mirrored in middleware.

Input
Receive · scan · checkout
Validate, then write a movement
Read model
Views + aggregates
On-hand, value, thresholds derived
stack   Next.js · TypeScript · Supabase · PostgreSQL · Tailwind · shadcn/ui · next-intl
05(Why end-to-end)
Because I owned both the inventory interaction model and the database write model, I could build every flow on one immutable ledger, so receive, usage, checkout, and scan all write the same kind of signed transaction instead of each becoming a separate path that mutates stock directly and drifts out of sync.
The case for one person, end to end
06(Outcome)

Shipped and in daily use across the operation. It replaced the spreadsheet sprawl and surfaced inventory that had never been tracked in one place before. The working surface runs the full loop: role-aware onboarding and site selection, inventory listing, receiving, usage and checkout, a barcode scanner, activity history with export, notifications, and analytics, all installable as a PWA.

07(What I'd do differently)

The append-only guarantee was earned, not designed in: early migrations still allowed updating and deleting transactions, and it took a later one to drop those policies and truly lock the ledger. Starting again, I'd commit to immutability from the first migration. There is also real cleanup waiting: the scanner and a number of catch blocks lean on any in an otherwise strict codebase, a couple of forms read the current site two different ways, and the PWA manifest and README still carry stale copy from an earlier iteration. The ledger-first model itself, deriving every balance instead of storing it, is the decision I'd keep without question.

Next project
PathPilot
Full-stack · UX / Next.js · Supabase · OpenAI
Back to selected work