Zorzal

Making a supply-chain tool work where the work actually happens.

Client
Zorzal Cacao · Reserva Zorzal, Dominican Republic
Role
UX/UI design and front-end · wireframes, prototyping, responsive CSS
Team
Lyna Kim, Simi Aluko, Alice Chen, Kristy Chan and me, through Stanford's Engineers for a Sustainable World
Timeline
January – June 2022
Stack
React · TypeScript · Firebase · Material UI · Figma

Outcome. We shipped a mobile-responsive, Spanish-language version of Zorzal's cacao tracker. It went live, and Zorzal still uses it today, with later teams building on top of it.

Why tracking cacao is worth doing well

There are levels to chocolate. Most cacao gets sold by the ton as a commodity. Zorzal's goes to artisan chocolate makers, so they're a little more avant-garde about it. They grow it on Reserva Zorzal, a 1,019-acre bird sanctuary in the Dominican Republic and the country's first private reserve. ("Zorzal" is Spanish for thrush.) Seventy percent of the land is left untouched, and the cacao is what pays for the forest.

Fine-flavor cacao is fussy. How long it ferments, how long it dries in the sun, which farm it came from: every one of those changes how the chocolate looks, tastes and smells. That's the difference between specialty and commodity, so Zorzal needs to know all of it, for every bag.

Their first system was paper slips taped to the boxes. The slips were scribbled in a hurry, hard to read, and fell off on the way from one station to the next. Shipments moved through production untracked, the records came out wrong, and the transparency Zorzal wanted to offer its customers just wasn't possible.

Two earlier Stanford teams had already built the fix: a React and Firebase web app that gives every box a barcode and logs it through each checkpoint (fermentation, drying, warehouse, containers). By the time our team picked it up, the hard backend problems were solved. The app worked.

It just didn't work where the work actually happened.

(The hero art on this page is mine, drawn for this case study.)

Five friends and a bird sanctuary

I joined the team a week and a half late, in the middle of January, which is how I learned the most important thing about this group: they'd already picked the group chat, and it already had a 🤩 in the name.

There were five of us. Lyna was our captain and the one who kept the whole thing on rails. Alice led the code, Kristy ran client engagement (and, per our own final report, was a "wireframe wizard & code genie"), and Simi and I ran design. We were friends before we were a team, and it showed. We had a standing mascot situation: my rabbit, Rupert, came to meetings and hopped around the table eating our snacks, and my friend Kayla's puppy, Zazu, made guest appearances. One night Lyna got stuck in an elevator on her way to our meeting and had to be rescued by the fire department. Her message to the chat: "Everyone should go home." (We did not go home.)

That mattered more than it sounds, because the next six months would test our patience. Showing up every week to a room with friends (and a rabbit) is what kept us laughing through it.

Rupert on the meeting table — photo to come
The five of us around a conference table at night
Four of us in masks, with the fifth on a laptop over Zoom
A night meeting in February, and the usual line-up: four in the room, one on Zoom.

Inheriting someone else's system

Before we decided anything, we spent our first weeks learning the codebase and grilling the two engineers who'd built it, Austin and Mark. That call reshaped how we saw the app. The decisions we'd inherited weren't arbitrary:

Checkpoints are places, not steps. Fermentation, drying, warehouse and containers are each a different physical location on the reserve. The app's structure mirrors the geography.

The data model mirrors the supply chain. Boxes get IDs, boxes get grouped into lots, and lots go into containers. Every scan is a record attached to an ID. To add a new production step, you add one object to the database, with no code changes. The previous team once got a diagram of the supply chain and had a running app the next day.

Search mostly proves the app works. Floor workers record. They almost never look anything up. Search was there so Chuck, Zorzal's founder, could see the big picture.

The app is the first thing to go. This was the big one. Shipments come in bursts: nothing for two weeks, then a flood of boxes. When workers are slammed and the app gives them trouble, they don't troubleshoot. They put the phone down and move cacao. Recording loses to the real work, every time.

That last point became the rule for everything after it: the tool has to cost the worker almost nothing, or it doesn't get used at all.

✱ Motion graphicA single bag of beans with a barcode riding along the supply chain (farm → fermentation → drying → warehouse, where bags merge into a lot → container), drawn in as you scroll.
Swimlane diagram of the checkpoints: fermentation, drying, containers and warehouse
The supply chain the app was built around, one swimlane per checkpoint.
A map of every action at each checkpoint, each marked quick scan, form, create or aggregate
From the previous team's operations manual: every action at every checkpoint, in order. Most are a single quick scan.

The problem, held up to reality

The app had been designed for a desktop browser, and Zorzal's employees used it almost entirely on their phones: one-handed, mid-task, in the heat, during those harvest bursts. On a phone, it fell apart. The checkpoint sidebar didn't collapse, so it ate half the screen. Rows of tabs ran off the edge, form fields got cut off, and the buttons were tiny. On top of that, the whole thing was in English, for a team that works in Spanish.

So the brief was narrow and pretty unglamorous: make the tracker genuinely usable on the phones and in the language of the people it was built for. The interesting part is how close we came to doing something much flashier instead.

✱ Motion graphicThe old desktop app squeezing narrower and narrower until it breaks at phone width.
The old Record page squeezed to 400 pixels wide, with its tabs and form cut off
The old Record page at 400px wide: the tabs run off the edge and the form goes with them.
The old Record page on an iPhone, overflowing
The same page scrolled sideways, with the heading cut off
The fermentation form on a phone, its fields clipped at the right edge
The same app on an actual phone.

Phase one: deciding what to build

Plant a garden

Here's the part nobody warns you about with client work: sometimes the client goes quiet.

We emailed Chuck. We emailed him again. For most of winter quarter we couldn't get him on a call, so we had no feedback on anything we were making. Our winter slides said it plainly: "Haven't talked to Chuck at all this quarter." I made a missing-person poster for him and put it in our presentation, misery-loves-company style. Simi, wisely, asked me to tone it down, so the poster went and I "changed my tone." When Lyna finally sent what she called a "passive aggressive email" in week nine, he replied in five minutes. Then he cancelled the meeting he'd proposed. ("Chuck tricked us, I fear," I told the group.) Lyna's email chain and Simi's texts were our only lines to Zorzal, and they did a lot of heroic chasing.

✱ Motion / imageThe missing-person poster, recreated with no face: a silhouette with a question mark, "HAVE YOU SEEN THIS MAN?", "Last seen: Week 1", "Reward: one reply email". Maybe a phone ringing on loop beside it, never picked up.

The plan vs. what happened

The planWhat happened
Winter · wk 1–3Plan · React onboarding, brainstorm, wireframesActual · Kickoff (Jan 7). A call with Austin and Mark, who built the app (Jan 20)
wk 5Plan · Wireframes to Chuck for feedbackActual · Emails to Chuck. No call
wk 6–8Plan · Start the mobile transition. Risk registerActual · Wireframe review and risk register. Kristy's first Spanish commit (Feb 16). The TA critique (Feb 24)
wk 9–10Plan · “Well-defined criticisms from Zorzal”Actual · Our winter slides: “Haven't talked to Chuck at all this quarter” (Mar 2)
Spring · wk 12Plan · BuildActual · The first call with Chuck (Apr 8). We decide to modify (Apr 12)
wk 16–18Plan · Prototype to the clientActual · Export to Google Sheets ships (May 18)
wk 20Plan · A thoroughly tested productActual · Final design review, then the final report (Jun 5)
Client feedback was planned for week 5. It came in week 12.

Honestly, at first the silence was kind of fun. No strict guidelines, no rubric, just the creative reins and room to go any direction. It was like being told to plant a garden: no specifics, just plant a garden. So you do. You pick the plants, arrange them, style them, make it look good. Then weeks later, while everything's flowering, someone walks by and says: oh wait, these are the wrong plants, I should've told you. That's rain on a parade. And after the first round of pushback, every round after it is harder to start. Our excitement tapered off and eventually leveled out into frustration.

(I presented one of these from COVID isolation, having woken up on my laptop keyboard seconds before.)

Five brains, five wireframes

While we waited, we each sketched our own version of a mobile Zorzal, and the sketches showed how differently we each read the same problem. Alice built around a master menu with long-press shortcuts. Kristy went for big labelled buttons and a circular palette for flicking between checkpoints. Lyna was obsessed with orientation: always knowing where you are, and jumping between levels fast. Simi leaned on visual cues and a menu tucked into a long-press.

Mine was the minimalist one: a floating back button (borrowed from Android, which the workers already knew), a home button in the corner, oversized buttons that fill the screen so a thumb can't miss, a muted grey-and-blue palette, and as little on screen as I could get away with. Utility over information density. I was, frankly, excited to make this thing beautiful. Hold that thought.

We merged the best of them into one direction, a full redesign, and built it as an interactive Figma prototype.

✱ Motion graphicThe wireframes dealt out like a hand of cards (the same pile as the home page), each with a one-line label of its big idea.
Kai's wireframe flow in Figma: splash, home, record, search and error screens
Mine: as little on screen as I could get away with.
Simi's hand-drawn wireframes
Simi
Alice's fermentation flow on grid paper
Alice
Kristy's wireframe of the home, record and create screens
Kristy
An early high-fidelity Record screen with palette swatches
An early high-fidelity pass at the Record screen.

Testing it, finding by finding

We wanted to test with Zorzal's employees, but we couldn't reach them. So we tested the prototype on whoever we had: classmates, roommates and a TA from a human-centered design course. We gave everyone the same three tasks from the app's real core loop: create a box in fermentation, create a lot in the warehouse, fill out the FCCI quality form.

People got through them and warmed up quickly. The failures taught us the most:

Everyone expected Search to search everything. Asked to create a box, several testers went straight to Search and typed "fermentation." One said: "I would assume that you can search for fermentation." People's habit of using search to navigate is stronger than any layout.

"Add to Lot" vs. "Create Lot" was a coin flip. Two near-identical labels, side by side, doing different things. That was a naming problem pretending to be a layout problem.

Pages needed to announce themselves. Testers landed on screens and paused: "kind of confused on what I was supposed to do — not too many words, but maybe a heading." My minimalism had tipped over into ambiguity.

The forms button was invisible. On the FCCI task, people went to Settings first. Forms belonged inside each checkpoint, not in a separate bucket.

People wanted more life. Nearly everyone, unprompted, asked for more color, pictures, maybe animation. (Hold that thought too.)

Three tasks, and where people got lost

Create a box in fermentationDetourWent to Search first: “I would assume that you can search for fermentation.”
Create a lot in the warehouseMix-upQuick, but “Add to Lot” and “Create Lot” were a coin flip.
Fill out the FCCI formDetourWent to Settings first. The forms were in a separate bucket.
Every failure was about labels and wayfinding, not the flow itself.
The prototype's Aggregate screen, with "Add to Lot" and "Create Lot" circled — screenshot to come

The critique that killed our favorite design

Then we put the redesign in front of Taylor Lallas, a TA for Stanford's CS 147, and she took it apart. Correctly.

First, we'd designed the wrong kind of thing. Our prototype behaved like a native mobile app, with bottom bars and app-style navigation, when the brief was a web app that works on any device. We'd drifted into designing what was fun instead of what was asked.

Second, and this was the deep one, we hadn't earned the right to change this much. The workers already knew the existing layout. We had almost no window into how they actually used it. Every layout change was a bet placed with someone else's money, and if the app annoys a worker mid-harvest, it's the first thing to go. Her rule: keep the existing layout wherever you can, and only change something when you can say exactly why it's better.

She also gave us the sharpest rule of the whole project: Record is where the money is. Logging boxes at each checkpoint is the entire job of this tool, so count the taps to get there. Our beautiful redesign took four screens to get from Home to Create Box, the most common action in the whole system. "You want as few clicks as possible."

Our beautiful redesign took four screens to reach the most common action in the app. That's not a style problem. That's the whole problem.
✱ Motion graphicA tap counter. A thumb taps through the redesign, screen after screen, and the counter ticks to four. Then the slimmed-down version gets there in fewer.

Steps to Create Box

The redesign4 screens
Home→Record→Fermentation→Create Box
What shipped2 screens
Record (where it opens)→Fermentación → Create Box

Risk register · 21 risks · about $4,040 a year

Upsetting the status quo: shipments back up for a week$750/yr
Training time: four hours each, for ten people$500/yr
Slowing workers down$375/yr
Misrepresented data leads to bad decisions$250/yr
The value lands in the wrong place$250/yr
It breaks in the future$250/yr
It costs more than the value it adds$250/yr
No one can maintain it after we leave$200/yr

Risks to how the workers already work. Score = probability × impact.

The risk register we inherited and extended. The three biggest risks were about disrupting how workers already work, not about the technology.

Rebuild, buy, or modify

The critique forced the real question. We had three paths, and we ran them as an actual evaluation instead of a vibe:

Rebuild from scratch, with our redesign. Best-looking and the riskiest. It was untested with real users, it was the wrong kind of app, and it took longer to reach the main actions. It would also run well past our two quarters.

Move to a no-code platform. We gave Retool a serious look. It had a built-in barcode scanner and some Firebase support. But every checkpoint would have been its own separate app, stitched together, it's built for internal tools (which kills any future customer-facing version), it's drag-and-drop in name and JavaScript-heavy in practice, and it would have cost a monthly fee. We also wrote down one question that stuck: does this do justice to the work previous teams already put in?

Retool, weighed

For (2)

+A barcode scanner built in

+Some Firebase support

Against

ArchitectureOne app per checkpoint and sub-checkpoint, with data passed through URLs and separate desktop and mobile versions

DataUnclear data handling and sync, and Zorzal depends on Retool staying up

FitBuilt for internal tools, so no customer-facing future. JavaScript-heavy, so Chuck couldn't configure it

CostA monthly fee, and it throws away the previous teams' work

Modify the existing codebase. The least glamorous option. It keeps the layout workers already know, keeps the clean architecture, keeps the customer-facing future open, fits the timeline, and does no harm to a workflow we couldn't test directly.

What the year cost · $67.10 of $1,000

Barcode labels$13.90
Firebase, just in case$50.00
Figma, VS Code, a React course$0.00
Tax$3.20
The year before us: scanner, label printer, tablet$737
Commercial agtechsix figures a year
Modifying was also the cheap option. Our whole year cost $67.

Modify won on paper. Then, at the start of spring, we finally got Chuck on a call and showed him both prototypes. He reacted just like our testers: he found the redesign clearer and more user-friendly than the existing app. He also said he'd take an app if we could deliver it by the end of the quarter. We couldn't promise that, so he went with the modified version. The person who had to live with the decision ended up where we had.

(I presented one of these from COVID isolation, having woken up on my laptop keyboard seconds before.)

✱ Motion graphicThe team's traffic-light decision matrix, with Kristy's scribbled objections drawing themselves on top, stroke by stroke.
A traffic-light matrix comparing changing the codebase, a drag-and-drop tool and a new app
The same matrix with Kristy's scribbled objections
The matrix, and Kristy's take on it.

The five stages of shelving a redesign

I'd love to say I took it gracefully. I went through all of it:

  • Anger, mostly at the communication. We'd spent a quarter planting the garden.
  • Denial. It does fit the bill.
  • Bargaining. What if we just tweak this, keep that, ship half of it?
  • Acceptance. Okay. They want this instead.

The silver lining: what Chuck wanted was a much more stripped-down version of what we already had, which turned out to be the simplest thing for us to deliver. I came in wanting to make it beautiful, and the work kept asking me to make it invisible.

Phase two: the build, decision by decision

“We overcomplicated the whole converting-to-mobile process!”

We got full access to the code and the database at the start of spring and turned "do no harm" into screens. This is the part I'd want another designer or engineer to read: the small decisions, and why each one went the way it did.

For a while, implementation went sideways. We'd assumed the whole app was broken on phones and were trying to fix everything at once. Our interim fix was even to tell the browser to render the site at 75% zoom, which worked, but it's not a mobile product. It's a desktop product held at arm's length.

Then Alice and Kristy audited the app page by page and wrote up what they found. Their memo opens, in all caps: "WE OVERCOMPLICATED THE WHOLE CONVERTING-TO-MOBILE PROCESS!" Most pages were fine. The breakage was concentrated in a few places: the checkpoint components (Create Box and drying especially), sub-checkpoints that didn't load, and text fields with fixed pixel widths that ignored the screen they were on. Some forms even showed the same fields in a different order on mobile and desktop, which meant someone, somewhere, had built two different versions.

That memo turned a vague goal ("make it responsive") into a checklist.

The memo, as a checklist

Collapse the checkpoint sidebar
Stack every form field in one column
Swap fixed pixel widths for percentages
One field order, on mobile and desktop
The "WE OVERCOMPLICATED…" memo, mess and all — screenshot to come
✱ Motion graphicA long tangled to-do list that untangles itself into four checkboxes.

The sliding belt

The worst offender on mobile was the checkpoint navigation: a wide bar of buttons that either ran off the screen or squashed itself unreadable. We could hide the checkpoints behind a hamburger menu, but that buries the app's main structure two taps deep. A drawer has the same problem. So we turned the bar into a horizontal sliding belt across the top: every checkpoint stays on screen and in thumb's reach, and the overflow slides instead of breaking. It kept the mental model workers already had (checkpoints in a row, in supply-chain order) and let it survive a four-inch screen. We used the same pattern for the actions inside each checkpoint.

✱ Motion graphicA phone, in the style of the Fortuna mockups, with the belt sliding through Fermentación, Secado, Almacén and Contenedores under a flicking thumb.
The stacked checkpoint belt on a phone
The same build on a desktop, with larger tabs
The belt on a phone, and the same build on a desktop.

Stack everything, and size it to the screen

The forms were laid out sideways (Farm · Quantity · Submit across one row), which is fine at 1280px and chaos at 375px. Alice rebuilt them as a single column, every label above its field. On the Aggregate page, "Complete Lot" moved below the list of scanned boxes, matching the order of the task (scan, scan, scan, complete) and ending the misclicks.

The old Record page with pen marks: the sidebar crossed out and collapsed, the fields stacked, Submit moved underneath
Our proposal, drawn over the old Record page: collapse the sidebar, stack the fields, put Submit underneath.

I worked on the responsive CSS with Kristy and Alice. Alice and Kristy owned the breakpoints that replaced the 75% zoom, and we swapped fixed pixel widths for relative ones so every field fits the screen it's on. Unsexy work, and the difference between genuinely mobile and a desktop site zoomed out.

✱ Motion graphicA form whose fields slide from a single row into a column as the screen narrows.

Spanish first

Kristy's first code change of the whole project put the navigation into Spanish. She celebrated with ice cream. From there the translation went through the app in passes: checkpoints and buttons, then notifications, then forms. None of us were fluent (Simi's plan B: "we can just Google translate our way through life"), so we checked against Spanish-speaking friends.

One honest boundary: a full translation reaches into the database itself, because every action, checkpoint and form name is stored as data, not code. We translated the interface and documented the database side for the next team, rather than pretending it was done.

Spanish field labels on a phone: Nombre del que Trabaja, Hora de Salida
"Nombre del que Trabaja," "Hora de Salida."

Real phones, not simulators

To see the app break the way phones actually break it, we ran the database locally and tunneled it out with ngrok, so the work in progress opened on a real Android and a real iPhone without deploying anything. (That's also how I learned what "ERR_NGROK_3200" means.) Watching a real thumb miss a real button beats a resized browser window every time.

An Android phone showing an ngrok tunnel-not-found error
ERR_NGROK_3200: the tunnel had closed before the phone got there.

Fix Create Box before adding anything

Create Box is the front door of the whole system: the first action in fermentation, the moment a batch of cacao enters the record. It was also the buggiest. We made that one function boringly reliable before shipping anything new, because of the rule from week one: if the app fails a worker mid-burst, the app gets abandoned, not the cacao.

Meet Chuck where he already is

Chuck is the one who actually analyzes the data, and midway through the build we found out he's very good with spreadsheets. The "proper" answer would have been dashboards and charts inside the app, but that would have taken longer than we had and been maintained by no one. So we wired the database to a Google Sheet and added a Report page with a one-click "Export to Google Sheets." He gets live production data in the tool he already lives in, and future teams can automate whichever of his charts turn out to matter. We built less, on purpose.

Our priorities, before and after one call with Chuck

1A flexible, configurable codebaseDropped. His checkpoints weren't changing
2Mobile responsivenessKept. It was the whole job
3A consumer-facing interfaceHanded to the next team
4Something newOne button: Export to Google Sheets
5Better search—
✱ Motion graphicA busy dashboard mockup (charts, filters, tabs) that collapses into one button: "Export to Google Sheets."
A sketch of a Report page counting units at each checkpoint today
An earlier idea: a Report page counting units at each checkpoint. A spreadsheet export did the job with less.
Phone sketches of a dashboard for Chuck, with an update-database button and a checkpoint timeline
Simi's and my dashboard sketches for Chuck.

What the reserve told us

Remember the testers asking for color and animation? Later in the spring, the team went down to the Dominican Republic to work alongside Zorzal. What came back, through Chuck (the closest thing we had to the workers' voice), pointed the other way: the job was speed, in Spanish, on the phone already in their hand, in the layout they already knew. Our testers were design-fluent students who wanted delight. Our users were people for whom the app competes with actual cacao. When those two audiences disagree, the users win.

So we kept the visual refresh modest. The whole team picked a warm chocolate palette to replace the placeholder greys, with an apricot accent, and we spent the effort we saved on reliability.

Our testers asked for more color and animation. The people actually using it needed fewer taps. Knowing which audience to listen to was the most important design decision of the project.
A photo from the Dominican Republic trip — to come

What shipped

By the end, the tracker worked across screen sizes and in Spanish. Create Box was stable, the FCCI form no longer slid off the edge, the checkpoint and action menus compressed cleanly at every size, the forms were stacked, the chocolate palette was in, and Chuck had his Google Sheets export. On a phone, you now land straight on Record, greeted by "Select a Checkpoint" and the belt: the fewest-taps rule from the critique, made real.

We presented it on the last day of May in Sweet Hall, with QR codes so the room could open it on their own phones.

✱ Demo reelA short motion piece of the Zorzal work: the shipped screens, the palette, the belt, the wireframes. Kai is putting this together.
The final Record screen, in the chocolate palette
The final Record screen on a laptop, with Spanish labels
The shipped Record screen. Stand-in shots, taken off a laptop at the final demo; clean phone screenshots to come.

It went live, and Zorzal still uses it today. Later teams kept building on top of it. What we could control was the handoff: an operations manual covering the code's structure, the local database workflow and the data model, so the next team got a map instead of an archaeology project, like we had. We also left them a direction. Simi and I sketched the first customer-facing view: scan the code on your chocolate and see the farms it came from and how long it spent at each checkpoint. That's the transparency the whole system was always pointed at.

✱ Motion graphicThe "Start → You!" journey drawn as one line, a bean travelling along it.
A sketch of a cacao batch's journey from the farm to the customer
The customer-facing view, sketched: from the farm to "You!"

Zorzal today

Zorzal is thriving. They were featured in a documentary, The Birds and the Beans. They run chocolate excursions where cacao lovers come down to the rainforest for a hands-on walk through the same supply chain our app tracks. They have new buildings, merch, collaborations with chocolatiers, and Chuck is out travelling, telling the story of how a protected bird sanctuary became one of the world's most distinctive fine-flavor origins. A mobile-friendly form tool didn't do that; they did. But it's a good feeling to have built a small working piece of a company you'd want to see win.

What it taught me

Three things I still carry:

Count the taps to the money screen. Every interface has one action that is the entire job. Our redesign was prettier and put that action four screens away. Distance to the core action is the metric that keeps taste honest.

The loudest feedback isn't the truest. Testers asked for color and animation, and real users needed fewer taps in their own language. Learning whose voice outranks whose, and letting the people on the other end outvote my eye, was worth more than any pattern library.

Restraint is a deliverable. The best design decision we made was a rebuild we didn't do. The most useful thing I worked on is something nobody who uses it will ever notice.

On deadline day, I told the group chat the final report "WILL BE FINISHED BY SUNDOWN." I submitted it at 11:57pm. "Not a moment too soon! The sun just set."