Admin panels a packer can use on day two
Take a furniture store that hires two packers. Both have used smartphones for years but have never touched anything resembling a CMS. The owner's position, reasonably, is that if the admin needs a training manual, it is the wrong admin.
Say the storefront runs on Shopify, which handles the customer-facing side fine. The problem is the back office — returns, partial refunds, inventory adjustments, courier handoff. Shopify's admin is powerful but dense, and a new packer can spend forty minutes on a return that should take five. The approach we take in this situation is a thin panel on top of the Shopify API, scoped to exactly what packers do, and nothing else.
The first decision is 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 hardcode 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, they log into Shopify directly — they already know it.
The second decision is naming. The Shopify API calls a return a "return," the courier calls it a "reverse pickup," and the packers call it "wapasi" — the Hindi word. Use "wapasi" in the panel. This sounds trivial. It is not. Label the button "returns" and on day one the packers ask where the wapasi button is. Label it "wapasi" and on day two nobody asks anything.
We make 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 the 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 stops the packers from seeing stale data. A real-time webhook sync is the textbook answer, but for two packers on one connection, polling is simpler and the cost is negligible.
The panel runs on a single small instance with a Postgres table that stores nothing except the mapping between the checkbox state and Shopify's fulfillment IDs. No caching layer, no queue. If the instance dies, nothing is lost — Shopify is the source of truth, and the table can be rebuilt from the API in under a minute. The obvious question is what happens if the instance dies in the middle of a return. The answer: the packer calls the owner, who processes the return in Shopify. That fallback exists regardless of whether the panel does.
One thing we push back on: analytics. Owners often ask for a dashboard showing daily packed counts per packer. The Shopify API gives them the same number in two clicks, and a dashboard in the packer panel means the packers see it too, which changes their incentives in ways nobody asked for. Most owners agree once that is pointed out.
A panel this narrow is a couple of weeks of work, not a quarter. The measure of success is not a training session that went well. It is that the packers are using it unassisted on their second morning and the owner stops hearing questions about it.
The same shape works for a grocery merchant whose staff only ever do 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.