Case Study 2024 Live

Wine Tracker

Wine collectors lose track of what they own and why they bought it. Spreadsheets don't capture the story behind the bottle.

Platforms: iOS + Android Role: Solo product + engineer
Stack: React Native Expo TypeScript Firebase Firebase Auth

Why it exists

I travel a lot. 25+ countries. Every time I'm somewhere interesting, I end up in a local wine shop or a restaurant with a list I don't recognize. I buy things, I discover things, I occasionally have a bottle that changes the way I think about wine from a particular region.

Then I forget. Not that I liked it — I'd remember that — but the context. The vintage, the producer, the reason I picked it over the one next to it. Spreadsheets don't capture this. Photos on my phone pile up with no structure. Notes apps fill with half-formed thoughts.

Wine Tracker exists because I wanted a single place that held both the collection and the memory of how each bottle got into it.

What I built

A cross-platform mobile app (iOS and Android) for tracking a personal wine collection. Each bottle gets a record: producer, vintage, varietal, region, where you bought it, price, and tasting notes. You can rate it while you're drinking it, photograph the label, and mark bottles you're cellaring versus bottles you're ready to open.

The core views are: a cellar overview (what you have), a recently tasted feed (what you've opened), and a discovery log (things you tried but didn't buy, worth tracking for rebuying later). The search is intentionally simple — filter by region or varietal, no complex queries.

Firebase handles auth and real-time sync across devices. If I add a bottle on my phone, it's there on my tablet when I'm browsing the cellar at home.

Key decisions

React Native over native. I wanted one codebase that ran on both platforms. Expo made the development loop fast enough that this was the right call — I could test on real iOS and Android devices quickly and iterate on the UI without the overhead of two separate codebases.

Firebase over a custom backend. For a personal app with no monetization, Firebase's free tier is generous and the real-time sync is genuinely useful. The trade-off is vendor lock-in, but the alternative was building and hosting my own backend, which would have added weeks I didn't want to spend.

Tasting notes as free text, not structured ratings. I experimented with structured inputs (fruit/tannin/acidity sliders, etc.) but they felt clinical. The notes that actually help you remember a wine are sentences, not scores. I kept a simple numerical rating and left the rest as a text field.

What I learned about mobile vs web development

The performance model is completely different. On web, you can get away with re-rendering frequently and relying on the browser's batching. On mobile, you feel every unnecessary render — lists get jumpy, transitions stutter, the whole experience degrades.

I spent more time on FlatList optimization than on any other single component. Proper keyExtractors, getItemLayout for known-height rows, windowSize tuning. It wasn't difficult work but it required understanding why mobile lists behave the way they do, which pushed me to actually read the React Native internals documentation properly for the first time.

The other big difference: error handling for offline states. Web apps can usually assume connectivity. A mobile app that's opened in an airport or a wine cellar with poor signal needs to degrade gracefully. Firebase's offline persistence helped here, but it still required thinking about sync conflicts that just don't come up in web development.

Open live app ← All projects

Share this

More case studies