Inspiration

Dialing in espresso is a repeated experiment: adjust the grind, pull a shot, taste it, and decide what to change next. Recipes often end up scattered across notes, screenshots, or memory—and knowing what to adjust can be intimidating.

I created tastewell to turn that process into a calm, guided workflow. Instead of overwhelming home baristas with charts and technical jargon, tastewell records the important variables, translates taste feedback into one clear recommendation, and helps users build a repeatable recipe for every bag of coffee.

What it does

tastewell is a local-first espresso companion that helps home baristas:

  • Organize coffee beans, roasters, origins, roast levels, blends, and flavor notes.
  • Save their espresso machine and grinder settings.
  • Follow a step-by-step dial-in workflow.
  • Record grind size, dose, yield, temperature, extraction time, and brew ratio.
  • Rate each shot by sourness, bitterness, and body.
  • Receive one practical recommendation for the next attempt.
  • Preserve the final recipe and complete shot history for every bean.
  • Generate personalized AI artwork for coffee bean covers.
  • See the currently active bean through an iOS home-screen widget.

The essential dial-in experience remains available for free. tastewell pro, powered by RevenueCat, unlocks unlimited beans, AI-generated covers, and the active-bean widget.

How I built it

I built tastewell with React Native, Expo SDK 56, React 19, and Expo Router, with a strong focus on a native iOS experience. I used Expo UI and SwiftUI-backed components for platform-native forms, navigation, controls, and interactions.

I designed the app around a local-first architecture. Beans, equipment, dial-in sessions, and individual shots are stored in SQLite and modeled with Drizzle ORM. This keeps the core experience fast, private, and available without an account or internet connection.

I implemented the recommendation system as a deterministic TypeScript rule engine. It combines taste feedback with measurable results such as extraction time and brew ratio. It then suggests changing one variable—grind, yield, dose, or temperature—while considering previous attempts and avoiding repetitive or contradictory adjustment loops.

For AI-generated bean artwork, tastewell sends a structured prompt to Google Gemini through Expo API Routes hosted with EAS. I use Shopify Skia to compose the resulting artwork onto a coffee-bag design.

I integrated RevenueCat for subscription management:

  • RevenueCat entitlements are the source of truth for Pro access.
  • Offerings and pricing are configured remotely instead of being hardcoded.
  • RevenueCat Paywalls provide the purchase experience.
  • Customer-info updates react to purchases, renewals, and expirations.
  • Purchase restoration is available from the app settings.
  • RevenueCat’s Test Store allows me to test the complete flow without real transactions.
  • Anonymous RevenueCat customers let users subscribe without creating another account.

I also localized the interface in English, German, and Spanish and added support for light and dark appearance modes.

Challenges I ran into

The largest product challenge was translating subjective taste into useful guidance. “Sour” or “bitter” does not always have a single mechanical cause, so the system needed to combine taste, ratio, extraction time, equipment limits, and shot history without pretending to be more precise than it is.

I also had to prevent recommendation loops. Repeatedly moving the grind finer and then coarser would quickly destroy trust. The engine therefore tracks previous adjustments, detects reversals, limits repeated recommendations, and only introduces temperature changes after simpler variables have been explored.

Designing the local database was another challenge. A dial-in session contains multiple related attempts, while recipes can reference previous shots and final dialed results. I used client-generated IDs, migrations, soft references, and canonical measurement units to keep the data model reliable and ready for possible future synchronization.

Finally, I wanted monetization to feel like part of the product—not an interruption. RevenueCat helped me keep access rules centralized while supporting dynamic offerings, anonymous purchases, restoration, and subscription-state changes across the app.

Accomplishments that I'm proud of

I am especially proud that tastewell feels like one focused experience rather than a collection of coffee utilities. Bean management, equipment, guided brewing, tasting, recommendations, history, artwork, widgets, and subscriptions all connect to the same workflow.

Other highlights include:

  • A recommendation engine that provides one understandable next step.
  • A complete local-first relational data model.
  • A native, tactile interface with haptics and platform controls.
  • AI artwork that gives every bean a distinctive identity.
  • A RevenueCat integration that cleanly separates free and Pro value.
  • Support for three languages, dark mode, and an iOS widget.

What I learned

I learned that predictable guidance is often more valuable than an overly clever algorithm. Users need to understand why a change is recommended and should remain in control of every recipe.

I also learned that monetization architecture affects the whole application. Subscription state influences navigation, settings, feature access, widgets, and error handling—not only the paywall. Treating RevenueCat entitlements as a shared source of truth made those decisions much easier to manage.

Most importantly, building tastewell reinforced my belief that good coffee tools should reduce friction during brewing. The phone should support the ritual, not take attention away from it.

What's next for tastewell

Next, I plan to:

  • Launch tastewell on the App Store.
  • Explore RevenueCat Virtual Currencies for flexible AI-generation credits.
  • Add deeper recipe comparisons and long-term brewing insights.
  • Expand the recommendation engine with more equipment-aware guidance.
  • Support additional brewing methods such as pour-over and AeroPress.
  • Improve Android support while preserving the native experience.
  • Explore optional encrypted synchronization without compromising the local-first design.

Built With

  • drizzle-orm
  • eas-build
  • eas-hosting
  • expo-api-routes
  • expo-router
  • expo-ui
  • expo-widgets
  • expo.io
  • gemini-api
  • google-gemini
  • i18next
  • ios
  • native
  • react
  • react-native
  • revenuecat
  • revenuecat-paywalls
  • revenuecat-test-store
  • shopify-skia
  • sqlite
  • swiftui
  • tanstack-query
  • typescript
  • zustand
Share this project:

Updates

Submission history