Skip to content

We built the same pharmacy counter twice on mobile, and the second one is smaller because of what the first taught us

Two attempts at putting the dispensing counter on a phone. The first mirrored the desktop console and was too deep to use standing up; the second kept five screens and pushed everything else behind a drawer.

11:24
DispenseRX-40718 · 3 items · picking
MOMrs M. OkaforDOB 04/03/1961 · Exempt · declared
2 of 3 picked
Amoxicillin 500mg capsules21 capsules · Kelbrook GenericsPicked
Insulin aspart 100 units/ml pens5 × 3ml pens · Aspeline · Maddox LabsFridge
Fridge line · Fridge 2, shelf 1Pick last · cold bag at hand-outPick
Atorvastatin 20mg tablets28 tablets · Norland PharmaPart-supplied
Prescribed28Supplied now14Owing14
3 labels, 1 owing slip · both flags confirmed first
ParkPick fridge, then print
TodayLook upDispenseStockReturns

Who, what, and how long

Industry
Healthcare & Dental Practices
Duration
14 weeks across two builds
Cooperation model
Time and materials
Services
Mobile engineeringInteraction designRebuild
Integrations
Push notificationsDevice secure storageCrash reportingOver-the-air updates
Technologies
React NativeExpoTypeScriptExpo RouterREST API
Team
1 Project lead2 Mobile engineers1 Interaction designer

Client name withheld under NDA. Engagement details are shown to the extent our agreement permits.

The problem

The hard problem

The first build reproduced the desktop information architecture: a drawer, tabs, and management sections nested two and three levels deep. On a phone, held one-handed, next to a customer, the useful screens were four taps away and staff went back to walking to the terminal.

The first build reproduced the desktop information architecture on a phone: a drawer, tabs, and management sections nested two and three levels deep. Held one-handed next to a customer, the screens people actually needed were four taps away. Nobody reported it as a fault, because a slightly awkward app isn't a bug. They simply stopped opening it.

The second build starts from what someone standing up actually does: look something up, take a payment, check stock. Those are tabs. Everything that's administration (categories, companies, generics, suppliers, expense types) went behind a drawer nobody needs during a transaction.

How the pieces fit

  1. 01

    Kept the second build's tab bar to the five things done while standing

    The tab bar holds the five things done standing up, which was decided by watching people work, not by asking what they wanted on the phone.

  2. 02

    Pushed all management screens behind a drawer, out of the tab hierarchy

    Setup lists (categories, companies, generics, suppliers, expense types) live in a drawer, away from the sale.

  3. 03

    Made search its own route with the query in the URL, so a lookup is resumable

    Search is its own route with the query held in it, so an interrupted lookup resumes on back with nothing retyped.

  4. 04

    Split purchase returns and sales returns into two screens, retiring the single screen with a direction toggle

    Splitting them cost one drawer entry and removed a class of mistake that moves both stock and money in the wrong direction.

  5. 05

    Reused the desktop API unchanged, so the rebuild was navigation and nothing else

    The desktop API was reused unchanged, which is what made the rebuild a navigation exercise instead of a second project.

Introduction

The system we were asked to build

After the counter system shipped on desktop, they wanted it on a phone for stock checks on the shop floor. We built it, learned what didn't survive contact with a standing user, and built it again.

After the counter system shipped on desktop, the chain wanted it on a phone for stock checks on the shop floor. The first build was delivered, used briefly, and abandoned: staff went back to walking to the terminal. The second build is the one that shipped, and the interesting part of this engagement is the two days that separated them.

Mobile Engineering

Five tabs, chosen deliberately

The tab bar holds only what someone does standing up; everything else is one drawer away.

The tab bar holds five things, chosen from what someone standing at a counter actually does in a transaction: look up a medicine, take a payment, check stock, handle a return, see the day. Everything else is one drawer away. The first build had put administration in the tab bar, which meant the frequent actions were competing with screens used twice a month.

What shipped
  • Five tabs, chosen from what happens standing up
  • Everything else one drawer away, off the bar
  • Frequent actions no longer share space with monthly ones
11:24
StockBridge Street · counted Thu 17 Sep, 08:05
All1,284Low12Expiring7
18 lines · low or expiring Expiry within 60 days
Salbutamol 100mcg inhalerBrenzair · 200 doses3min 10
Insulin glargine 100 units/ml pensGlarestra · 5 × 3mlExp Oct 262min 4
Omeprazole 20mg capsulesKelbrook · 28Exp Nov 2619min 8
Levothyroxine 50mcg tabletsNorland · 284min 12
Sertraline 50mg tabletsMaddox · 285min 10
Lansoprazole 30mg capsulesKelbrook · 28Exp Oct 2614min 6
Amlodipine 5mg tabletsNorland · 286min 15
Calder Wholesale · arrived 10:46, 2 lines short
TodayLook upDispenseStockReturns
On screen

Stock filtered to low and expiring, with a fridge line marked, and along the bottom the five-tab bar that is the whole of the second build's navigation.

11:24
StockBridge Street · counted Thu 17 Sep, 08:05
All1,284Low12Expiring7
18 lines · low or expiring Expiry within 60 days
Salbutamol 100mcg inhalerBrenzair · 200 doses3min 10
Insulin glargine 100 units/ml pensGlarestra · 5 × 3mlExp Oct 262min 4
Omeprazole 20mg capsulesKelbrook · 28Exp Nov 2619min 8
Levothyroxine 50mcg tabletsNorland · 284min 12
Sertraline 50mg tabletsMaddox · 285min 10
Lansoprazole 30mg capsulesKelbrook · 28Exp Oct 2614min 6
Amlodipine 5mg tabletsNorland · 286min 15
Calder Wholesale · arrived 10:46, 2 lines short
TodayLook upDispenseStockReturns
11:24
StandwellHollins & Varley · Hannah K., dispenser
Set-up · most used firstopens, 30 days
Suppliers6 wholesalers · order days, account nos.11
Generics1,146 generics · strength and form7
Companies212 manufacturers4
Categories38 categories · shelf groups2
Expense types14 types · rent, couriers, sundries1
Records
Purchase returnsStock back to a wholesaler
Deliveries2 expected today
Reports & settingsTakings, VAT periods, devices
Full editing on every screen here. None of them is in the tab bar.
On screen

The drawer over the stock screen: suppliers, generics, companies, categories and expense types as real screens, ordered by how often each was opened.

Administration behind a drawer

Categories, companies, generics and suppliers are real screens. They just aren't in the way of a transaction.

Categories, companies, generics, suppliers and expense types are complete screens with full editing. They're simply out of the path of a transaction. Demoting them cost nothing, because the person configuring suppliers is sitting down with time, and the person selling isn't. The drawer is organized by how often things are actually opened, not alphabetically.

What shipped
  • Administration screens complete, just out of the transaction path
  • Configuration is a sitting-down job; selling isn't
  • Drawer ordered by real frequency, not alphabetically

Search is a route

The query lives in the route, so an interrupted lookup picks up where it left off.

The search query lives in the route through Expo Router, so an interrupted lookup (a customer question, a phone call, a switch to take a payment) is resumed by going back, with nothing retyped from the beginning. State in a route also means a search can be shared between staff on two devices, which turned out to matter more than expected.

What shipped
  • Query held in the route, so back resumes the search
  • Interruptions cost nothing; nothing is retyped
  • A lookup can be handed between two devices
11:24
metfor
/search?q=metfor Other phone
Resumed where you left itLeft at 11:19 to take a payment · back brought it here
5 matchesIn stock first
Metformin 500mg tabletsKelbrook · 28 · shelf C164on shelf
Metformin 850mg tabletsNorland · 56 · shelf C122on shelf
Metformin 500mg modified-release tabletsMaddox · 28 · shelf C29on shelf
Metformin 1g tabletsKelbrook · 28 · shelf C2None on shelf
Metformin 500mg/5ml oral solutionTarnside · 150ml · shelf Liquids 33on shelf
Recent lookups
sertral amlod 5 salbut
TodayLook upDispenseStockReturns
On screen

A half-typed medicine lookup with the query carried in the route beneath the field, resumed after a payment interrupted it, and ready to hand to another phone.

11:24
ReturnsBridge Street · Thu 17 Sep
Sales returns Purchase2
Customer shopItem back onto the shelf, money back to the customer. Nothing else on this screen.
S-20931Sold Tue 15 Sep, 16:42Receipt found
1Digital ear thermometerUnopened · seal intact£24.99
Stock+1 back on shelfRefund£24.99 · 4417
Refund £24.99 to card 4417
Sales returns earlier
Blood pressure monitor, upper armS-20917 · 09:58−£39.99
Travel sickness bands, 2 packS-20902 · 09:21−£7.49
Reading glasses +2.0S-20888 · Wed 16:10−£9.99
TodayLook upDispenseStockReturns
On screen

Sales returns on a screen of their own, with purchase returns one segment away: an unopened thermometer going back on the shelf and its refund going back to the card, with no direction toggle to misread.

Returns split by direction

Purchase returns and sales returns are separate screens, with no toggle to misread.

Purchase returns and sales returns are separate screens, not one screen with a direction toggle, because a toggle is a thing to misread and the two are irreversible in opposite directions. Splitting them costs one drawer entry and removes the mistake entirely. That's the right trade for an action that moves both stock and money.

What shipped
  • Two screens in place of one with a direction toggle
  • No control to misread on an irreversible action
  • Costs one drawer entry, removes the mistake class
11:24
DeliveryCalder Wholesale · arrived 10:46
CW-55821322 lines 2 short
Arrived short · decide before stock updates
Ramipril 5mg capsulesKelbrook · 282 / 64 short
Substitute 4 packsRamipril 5mg capsules · Norland · 28 · 4 available
Record an owing instead4 packs owed by Calder Wholesale
Salbutamol 100mcg inhaler7 of 10 · 3 shortSubstituteOwing
Received in full+18 more
Omeprazole 20mg capsulesKelbrook · 2812
Amlodipine 5mg tabletsNorland · 2815
Update stock · 1 decision left
TodayLook upDispenseStockReturns

Same API, new navigation

On screen

A wholesaler delivery arriving short, offering a substitution or an owing record at the top of the screen before the stock update, written to the same records the desktop console uses.

The rebuild changed the route tree and nothing underneath it, which is why it took weeks, not months.

The rebuild changed the route tree and nothing beneath it: the same REST API, the same records, the same business rules. That's why it took weeks instead of months, and why it could be rolled out without retraining anyone on anything except where things now live. The operations themselves behaved exactly as before.

What shipped
  • Route tree replaced; API, records and rules untouched
  • Weeks, not months, with no backend risk
  • Rollout needed no retraining beyond where things live
Process

Phase by phase

  1. Phase 1: The First Build

    The Desktop, Shrunk

    Built the app as the console's structure on a smaller screen: drawer, tabs, and nested management sections. It was complete and it was correct, and staff didn't use it.

    • Drawer & Tabs
    • Management Sections
    • Dispense Screen
  2. Phase 2: Watching It Fail

    Four Taps Is Too Many

    Spent two days on the shop floor. The finding was blunt: the three things done while standing were all several levels down, and walking to the terminal was faster than navigating to them.

    • Floor Observation
    • Tap-Depth Audit
    • Rebuild Brief
  3. Phase 3: The Second Build

    Five Screens And A Drawer

    Rebuilt navigation around standing work (home, dispense, stock, reports, settings), with every management surface behind a drawer. The API didn't change; only the route tree did.

    • Tab Bar
    • Drawer
    • Route Tree
  4. Phase 4: Search As A Route

    Resumable Lookups

    Made the medicine search its own route carrying the query, so an interrupted lookup can be returned to instead of retyped, which on a busy counter happens constantly.

    • Search Route
    • Query In URL
    • Recent Lookups
11:24
TodayHollins & Varley · Bridge Street · Thu 17 Sep
Look up a medicineResume “metfor”
Dispensed46prescriptions so far
Takings£1,284.60counter and card
Owings open5to patients
Fridge waiting3bagged, to collect
Waiting at the counterSee all
M. OkaforFridge line · part-suppliedRX-407183 items · 11:18
D. WhitlowReady to hand outRX-407161 item · 11:09
S. FerreiraOwing collected todayRX-407132 items · 10:52
L. BranniganReady to hand outRX-407094 items · 10:37
TodayLook upDispenseStockReturns
On screen

Today, the first of the five tabs: the day's dispensing, takings, open owings and fridge items waiting, the prescriptions at the counter, and the interrupted lookup one tap from resuming.

What it carries now

4

Taps to dispense, first build

1

Taps to dispense, second

5

Tabs

0

API changes for the rebuild

Taps to dispense in each build are counts from the same task performed on both. Tabs is the size of the second build's tab bar. API changes for the rebuild is zero: the same endpoints, records and business rules served both, which is why the second build took weeks instead of months.

Client name withheld under NDA. Figures are approximate, drawn from the engagement’s own reporting.

What the architecture settled

  • Porting a desktop information architecture to a phone reproduces the structure and loses the product.

    A desktop information architecture ported to a phone preserves the structure and loses the product, because the structure was a response to a different posture.

  • Navigation depth is a usability budget. Spend it on what people do standing up.

    Depth is a budget: four taps to the common action spends it all on screens used twice a month, and staff simply stop paying.

  • Two days on the floor produced a clearer brief than any amount of discussion about mobile patterns.

    Two days of watching produced a brief that months of discussing mobile patterns hadn't, because what people do standing up isn't what they say they need.

  • When the API is right, a rebuild is a navigation exercise. That's an argument for keeping the two separable.

    The rebuild cost weeks because the API was right and separable. That's the argument for keeping that boundary even when one client is the only client.

How the work was run

  • We showed them the first build failing instead of describing it. Two days of shop-floor observation, counted in taps, made the rebuild an easy decision, and made it a navigation project instead of an argument about whether the app was good.

    Time and materials across two builds, which is what allowed the second one to happen at all; a fixed-price engagement would have delivered the first build and stopped. The API was untouched throughout, so the second build was a navigation exercise and cost weeks, not a second project.

One item, dispensed on both builds

Four taps became one. The calls to the back end didn't change at all.

The same task on both builds, from the home screen to dispensing one item. The first build reaches it through the desktop console's structure, the second from the tab bar. Watch the tap counter, then the API calls that follow. Switch tabs, or use the arrow keys once one is focused.

Dispensing one item · the same task on both builds

Timings, routes and endpoint names are illustrative
Taps from home to dispensing4 / 4
  1. 1Tap “Open the menu”on Home
  2. 2Tap “Management”on Drawer
  3. 3Tap “Sales & dispensing”on Management
  4. 4Tap “New dispense”on Sales & dispensing
  5. Dispense screen open /(drawer)/management/sales/dispense/new

Dispensing sat inside the console's management sections, two and three levels down. Held one-handed next to a customer, walking to the terminal was faster.

Calls to the shop's APIIdentical in both builds
  1. 1GET/api/prescriptions/RX-40718
  2. 2GET/api/stock?ids=…
  3. 3POST/api/dispenses
First build4taps to dispense
Second build1tap to dispense
API changes0for the rebuild

Same endpoints, same records, same business rules. What moved is where dispensing lives in the route tree, which is why the second build took weeks, not months.

Architecture

A new route tree over an API that didn't move

The boundary between navigation and the back end is what made the second build a navigation exercise. The app and its routes were replaced; the API and the records beneath it are what the shop already ran.

  1. 01 · Trigger
    A tap at the counterThe day, a lookup, dispensing, stock and returns are the 5 tabs, chosen by two days of watching the shop floor rather than by asking.Rebuilt
  2. 02 · Navigation
    Expo Router route treeTabs for standing work, a drawer for administration. The search query lives in the route, so back resumes a lookup and a second device can open it.Rebuilt
  3. 03 · Business logic
    The desktop REST API0 API changes for the rebuild. The same endpoints and business rules served both mobile builds, so every operation behaves exactly as before.Unchanged
  4. 04 · State
    The shop's existing recordsStock, sales, returns and supplier records are the ones the counter system already kept. The rebuild touched none of them.Unchanged
  5. 05 · Client
    React Native app on staff phonesExpo and TypeScript. Rollout needed no retraining on any operation, only on where each one now lives.Rebuilt

What a phone at the counter must not break

Dispensing under pressure & back-end safety

Nothing to misread under pressure

Dispensing is 1 tap away instead of 4, an interrupted lookup resumes rather than being retyped, and sales and purchase returns are separate screens, so no direction toggle sits on an action that moves both stock and money.

Fridge and part-supplied lines on their own cards

While a prescription is picked, the fridge line and the part-supplied line are each flagged on a card of their own before the label prints. A short delivery asks for a substitution or an owing record before the stock update.

A rebuild that never reached the back end

0 API changes: the same endpoints, records and business rules served both builds. The rebuild replaced the route tree and nothing beneath it, so the operations behaved exactly as before.

Staff walking back to the terminal instead of opening your app? Scope your build in 3 minutes.

Scope your build
Have a project?

Let's talk

Running a large platform, shaping a first MVP, or getting a product ready for a funding round? Tell us where you are. We'll shape the process around it, and stay with you after launch.