Admin panels a packer can use on day two
A furniture store in Jaipur hired two packers last quarter. Both had used smartphones for years but had never touched anything resembling a CMS. The owner told us, flatly, that if the admin needed a training manual, it was the wrong admin.
We had built their storefront on Shopify, which handles the customer-facing side fine. The problem was the back office — returns, partial refunds, inventory adjustments, courier handoff. Shopify's admin is powerful but dense, and the packers were spending forty minutes on a return that should take five. So we built a thin panel on top of the Shopify API, scoped to exactly what packers do, and nothing else.
The first decision was what to leave out. Shopify's admin exposes maybe sixty actions per order. A packer on day two needs four: print label, mark packed, mark handed to courier, mark returned. We hardcoded those four into a list view with one-line rows and large touch targets. No filters, no saved views, no bulk actions. If the owner needs bulk operations, he logs into Shopify directly — he already knows it.
The second decision was naming. The Shopify API calls a return a "return" but the courier calls it a "reverse pickup" and the packers call it "wapasi" — the Hindi word. We used "wapasi" in the panel. This sounds trivial. It is not. On day one, the packers asked us where the returns button was. On day two, they found it.
We made a similar choice with order statuses. Shopify has "fulfillment_status: unfulfilled" and "financial_status: paid." The packers do not care about fulfillment status as a concept. They care about whether the box is packed. So the panel shows two columns: "Packed?" and "Courier picked up?" Both are checkboxes. The underlying API calls update the fulfillment and create a fulfillment event, but the packers never see those words.
A tradeoff: the panel duplicates state that Shopify already tracks. If a packer checks "Packed?" in our panel and someone else marks the order fulfilled in Shopify's admin, they can disagree. We handle this by polling Shopify every thirty seconds and reconciling. This is not elegant. It is one extra API call per packer per half-minute, and it prevents the packers from seeing stale data. We could have built a real-time webhook sync, but for two packers on one connection, polling is simpler and the cost is negligible.
The panel runs on a single EC2 instance with a Postgres table that stores nothing except the mapping between our checkbox state and Shopify's fulfillment IDs. No caching layer, no queue. If the instance dies, we lose nothing — Shopify is the source of truth, and the table can be rebuilt from the API in under a minute. We told the client this, and he asked what happens if the instance dies during a return. The answer: the packer calls the owner, who processes the return in Shopify. This fallback exists regardless.
One thing we did not do: analytics. The owner asked for a dashboard showing daily packed counts per packer. We pushed back. The Shopify API can give him the same number in two clicks, and a dashboard in the packer panel would mean the packers see it too, which changes their incentives in ways nobody asked for. He agreed.
The panel took eleven days to build. The packers were using it unassisted on their second morning. The owner's measure of success was that he stopped hearing questions about it.
We have since built a similar panel for a grocery merchant in Lucknow, scoped to stock reconciliation. Different vocabulary, same principle: figure out the four actions, use their words, leave out everything else, and let the underlying platform hold the complexity you are not ready to own.