Portfolio / System Ops / mikrofarm

A POS no Play Store
app could fit.

Mikro Farm sells stock feed, animal meds, seeds, pesticides and fertilizer — by the kilo, by the sack, by the container. The owner had tried every off-the-shelf POS and none of them split warehouse from store, none of them re-priced when suppliers moved, and none of them told the customer what was on the shelf before they drove an hour to find out. So we built one that did.

ClientMikro Farm
ScopeCatalog · POS · Warehouse · Supplier
Locations1 store + 1 warehouse
Order size1–2 containers / shipment
Year2026
The owner's pains

Five things that hurt every week.

Before we wrote a single line, the owner walked us through the same Saturday five times. These are the bruises that came up over and over.

Pain 01

Customer drives an hour. The bag of feed isn't on the shelf.

The store is far from where most farmers live. When the thing they came for isn't in stock, the trip is wasted — and so is the trust.

"It hurts me every time. They came all this way for nothing."
Pain 02

Saturday morning is packed. Customers don't know what they want.

Walk-ins arrive into a busy store with no plan — they stand at the shelf trying to read labels while ten other people queue. Staff time is the casualty.

Pain 03

Stock sits in two places. The system counts it as one pile.

Warehouse and storefront are physically separate but every off-the-shelf POS lumps them together. So the screen says 40 sacks, the shelf has 3, and the back has 37 — and nobody knows until a customer asks.

Pain 04

Tracking what's low means walking the warehouse with a clipboard.

Every Friday, someone counts. Manually. By eye. Mistakes show up two weeks later when an order arrives short of what they actually needed.

Pain 05

One shipment is one or two containers. Get the order wrong and you eat it.

This isn't a bag at a time. A single supplier order is a container of feed. Order too little — stockout for a month. Order too much — capital frozen, expiry creeping up on the meds and seeds.

"Plus suppliers move prices every few weeks. Margin gets eaten without me noticing."
● Pains 01 + 02

Customers who drive an hour need to know what's on the shelf.

The first thing we built isn't for staff. It's a public-facing, education-first catalog the customer opens before they get in the car. Each product has live stock per location, dosage notes for meds and seeds, and a "reserve / order" button so the bag is held when they walk in.

The shelf-side problem solves itself: customers who already chose at home don't need to read labels in a queue. The drive-an-hour problem solves itself: if it's red, they don't drive.

"Now they message me asking which fertilizer for cabbage in the dry season. Before, they just showed up confused." — Owner, Mikro Farm
9:41
•••▮▮
Mikro Farm
Toko · live stock
Cart · 0
All Pakan Obat Benih Pupuk
Pakan Ayam Petelur 50kg
CP · Sak
12 sak
Rp 425k
Vitamin B-Complex 1L
Medion · Botol
2 left
Rp 78k
▸ Why this matters
Cabbage in dry season → Urea + KNO3
Add nitrogen for leaf growth, potassium for water-stress tolerance. We stock both — order together for free pickup pack.
Pupuk Urea 50kg
Pusri · Sak
Restock 3d
Rp 280k
● Pain 03

Gudang and Toko are two places. So we made them two columns.

Every item has one master record but two stock rows — one for the warehouse, one for the shop floor. HPP is tracked per location too, so a transfer carries cost as-is and margin reports stay honest.

Sales deduct from Toko first. If Toko runs short, the system falls through to Gudang without confirmation — but logs the pull, so reorder math knows the shelf needs refilling, not just the back.

Gudang backstock
Pakan Ayam 50kg37
Pupuk Urea 50kg82
Vitamin B-Complex 1L14
Pestisida Decis 100ml26
Toko on shelf
Pakan Ayam 50kg3
Pupuk Urea 50kg8
Vitamin B-Complex 1L2
Pestisida Decis 100ml5
● Pain 04

The clipboard rounds become a screen the owner already trusts.

Low-stock alerts run per location, not in aggregate. The "What to buy" tab is the same logic Friday nights used to do by hand — except it never miscounts, and it surfaces items by urgency, not alphabet.

Expiry-tracked categories (meds, seeds, pesticides) get a second pass: anything within 60 days of expiry shows in the same tab so it gets sold or moved before it's worthless.

mikrofarm / what to buy
live
Below min
14
Expiring <60d
06
Hours saved / wk
4–6
ItemLocOn handMinAction
Pakan Ayam Petelur 50kgToko310Pindah
Pupuk Urea 50kgGudang82120Reorder
Vit. B-Complex 1L (exp 09/26)Toko24Sell first
Decis 100mlGudang2650Reorder
● Pain 05 — qty

Container math, not bag math.

For a single-bag retailer, "order more when low" is fine. For Mikro Farm, the question is how many sacks fill a 20ft container without overshooting six months of demand. So reorder isn't a button — it's a calculator the owner can override.

The system rolls the last 12 weeks of sales, multiplies by supplier lead time, and snaps the result up to the supplier's MOQ and the next container fill line. The owner sees the math, not just the answer, and can dial it before sending.

▸ Reorder calculator · Pakan Ayam 50kg
avg_weekly_sales × lead_time_weeks × safety
32 sak/wk × 6 wk × 1.25 = 240 sak
snap to MOQ (50 sak) → 250 sak
snap to container (300 sak) → 300 sak ✓
Suggest
300 sak
Container fill
100%
Cover
~9 wk
● Pain 05 — price

Suppliers move prices. Margin moves silently. Not anymore.

Every receiving event recomputes weighted-average HPP per location. If the new HPP crosses the markup band the owner sets, the retail price auto-updates and gets logged — both on the POS and on the customer-facing catalog.

The owner sees a single feed of every move: what changed, why, and by how much. No more "wait, why did margin drop this month."

▸ Price moves · last 7 days
Pakan Ayam 50kg Rp 410k Rp 425k ▲ +3.7%
Pupuk Urea 50kg Rp 295k Rp 280k ▼ −5.1%
Decis 100ml Rp 64k Rp 68k ▲ +6.3%
Benih Cabai 10g Rp 28k Rp 26k ▼ −7.1%
How we built it

Five weeks. Built on top of an existing POS shell.

We didn't start from zero. The POS skeleton came from our own Floural template — sales, expenses, attendance, payments. The custom work was inventory: splitting it, costing it, and surfacing it.

01

Week 1 — Walk the warehouse

Inventory model on paper before a single line of code. Mapped every category, every unit (kg / sak / liter / pcs), every supplier MOQ, every expiry-tracked SKU.

02

Week 2 — Two-location data model

Built inventory_items + inventory_stock junction (one master, per-location qty & HPP). Wired weighted-average cost on every receive. Transfer flow ("Pindah ke Toko") shipped same week.

03

Week 3 — POS rewire

Sales now hit Toko first, fall through to Gudang, snapshot HPP onto the order line. Low-stock alerts and "What to buy" tab driven off live joins.

04

Week 4 — Public catalog + reorder math

Customer-facing PWA reading the same stock table the POS writes to. Reorder calculator with container-fill snap. Price ticker reading off receiving events.

05

Week 5 — Run alongside the old way

For one full week, every count was done both on the system and on the clipboard. Reconciled at the end. Discrepancies → bugs → fixed → handover.

What's working now

Six things the owner doesn't do by hand anymore.

No fabricated month-over-month numbers — the system is fresh. These are the workflows that have moved off paper and out of the owner's head.

2

Stock locations, separated

Gudang and Toko have their own qty and HPP. Sales fall through cleanly. Transfers carry cost.

0

Manual price updates

Every receive recomputes HPP and re-prices retail per the owner's markup band. Catalog reflects it instantly.

1

Place to see what to buy

One tab, sorted by urgency, including expiry-soon items. Replaces the Friday clipboard round.

100%

Live stock visible to customers

Public catalog reads the same table the POS writes to. No staging, no caching delay.

1–2

Container math, automated

Reorder suggestions snap to MOQ and container fill. Owner sees the math, can dial it, then sends.

0

SaaS subscriptions

Replaces every Play Store POS attempt that didn't fit. Owned outright. Hosts on a small VPS.

The stack

Picked for offline-first, Indonesian retail.

▸ POS app

React Native + Expo

Runs on the staff Android tablet at the counter. Offline-first via a queued sync store — counter keeps taking sales when wi-fi blinks, replays when it returns. OTA updates so we ship JS-only fixes without a reinstall.

React Native · Expo 55 · Zustand · TypeScript
▸ Backend

PHP + MySQL on a small VPS

One file per domain, ?action= routing, raw PDO. JWT auth. Audit log on every mutation so we can trace any stock change back to a person and a moment.

PHP · MySQL · PDO · JWT · audit log
▸ Customer catalog

PWA reading live stock

Public-facing browser app. Reads the same inventory_stock table the POS writes to — no separate sync. Education-first: each product carries a "why this" note for cross-sell context.

PWA · live stock per location · WhatsApp share link
▸ Inventory model

Master + per-location stock

One inventory_items row per SKU. Two inventory_stock rows (Gudang, Toko) keyed by (item_id, location). Every receive event triggers weighted-average HPP and an optional retail re-price.

junction table · weighted-avg HPP · expiry tracking
Next → Floural

Off-the-shelf POS
not fitting your store?

Free scope-out call. We'll tell you the cheapest thing that actually fits.