Context
I worked on web and mobile features of Trinio OS, an omnichannel commerce and fulfillment platform. The mobile app (React Native + Expo) is the working tool of the people doing the picking: they scan item barcodes, confirm quantities, handle items that are not in stock, and move orders through the fulfillment lifecycle.
Problem
- The operator cannot lose work. If the app dies, the connection drops or the person is called away mid-pick, the picking session must be recoverable.
- Reality produces exceptions: item out of stock, wrong item scanned, an order the store cannot fulfil. Those cases need a designed path, not an error toast.
- The same product serves different tenant types, so functionality must be scoped: a checkout tenant should not see pick-and-pack menus at all.
- Operators work fast on small screens. Interface density and tap-to-feedback latency are functional requirements, not polish.
My responsibility
Feature-level work across the web dashboard and the mobile app: picking and checking flows, barcode reading, exception handling, resuming interrupted operations, offline behaviour with local persistence, push notifications, plus continuous UI, UX, performance and business-rule improvements. I worked on top of existing platform architecture and patterns.
Representative work
- Resume what was interrupted: reuse orders from the previous picking session instead of starting over.
- Accept picking batches without fulfillments in the app, so the flow matches how operations actually dispatch work.
- Barcode and reference codes: expose EAN/SKU in the reference code and show the picking barcode, so scanning and manual lookup agree.
- Exception handling: a dedicated confirmation modal for items out of stock, with a reason, instead of a dead end.
- In-app notification when a new order arrives for picking: visibility without leaving the screen.
- Performance on the picking list: reduce the work done on the tap-to-open path of the picking card.
- Consistency: standardise headers, status messages, pending drawers and summary blocks across internal screens, and reclaim vertical space on mobile.
- Multi-tenant scoping: hide pick-and-pack menus and flows from checkout tenants, and enforce write permission where it was needed.
- Business rules: pending items should consider only the store's own orders; correct late/urgent filters; surface urgency and lateness tags in the app.
How I approached it
The pattern I used consistently: understand the operation first (who does what, on which device, under which constraint), then map it onto existing platform patterns instead of inventing a new one. State that must survive interruption is kept locally and treated as authoritative until the server confirms it, so the operator never loses a step. Exceptions are modelled as explicit states in the UI rather than as failures. For anything repetitive and user-facing, I measure the cost in taps and in perceived latency, not in elegance.
Decisions and trade-offs
- Local-first for in-progress work. Trade-off: the app can hold state the server has not accepted yet, which forces explicit reconciliation rules and makes bugs harder to reproduce. Blocking on the network was not acceptable on a warehouse floor.
- Exceptions as first-class screens. Trade-off: more UI surface and more states to maintain, but fewer dead ends for the operator and less informal improvisation.
- Scoping by tenant at the UI boundary. Trade-off: the front end has to know about tenant types; the benefit is that unsupported flows cannot be reached by accident.
- Standardising components across screens. Trade-off: touching several screens at once, in exchange for a product that stops feeling like several separate apps.
Result
Operational rather than numerical: the packing flow stopped losing the operator's work on interruption, exception cases gained a defined path, and the app became consistent enough to teach.
What I learned
- On mobile, reliability is a feature: what happens on failure matters as much as the happy path.
- In multi-tenant products, "who can see this" is a design decision made early, not a permission patched later.
- Operational feedback beats assumptions: screen space and one extra tap are real costs.