Notes from FitMesh's first year in production
What held up, what I rewrote, what I'd change. A retrospective of an indie app with real users.
FitMesh has been live for just over a year. Here's what I learned.
What held up
The Postgres schema. I spent one extra hour thinking it through, rather than shipping the first schema that worked, and it paid me back a hundred times over. The analytics queries and the export jobs still run today without any restructuring.
The client/server separation. The wearable talks only to the phone. The phone talks only to the backend. The backend talks only to the database. No shortcuts, no extra APIs. Every time I added a feature, I knew exactly where it belonged.
Flutter on Wear OS. This was the riskiest call and it surprised me: hot reload working on the watch, acceptable performance, distribution through the Play Store without friction.
What I rewrote
The sync layer. The first version polled every 60s. It made sense at launch (easier debugging), but it didn't scale: the phone kept waking up constantly. I rewrote it with WorkManager triggered by Data Layer events. Result: −70% battery drain on the phone.
The app's home screen. The first version showed every metric on a single dashboard. Cluttered. It's now a stack of cards, each carrying one primary metric. More legible, more mobile-friendly.
A year of maintenance: what takes the time
There's a truth no tutorial covers: shipping the app is 30% of the work; maintaining it is 70%.
Wear OS ships major updates annually. Each time I have to reopen the codebase, check for deprecated APIs, and test on a physical device. It's not catastrophic, but it demands attention and can't be deferred: if the watch experience breaks, users leave a one-star review and disappear.
The Play Store review cycle for each release introduces latency I always underestimate at launch: an urgent fix doesn't reach production in ten minutes. Planning ahead becomes mandatory.
User feedback without a support team is its own job. I read every review, every email report. Most of it is genuinely useful. Some of it requires long investigation — reproducing a bug on a device configuration I don't own is the kind of rabbit hole that eats an afternoon.
Then there are dependencies. Every Gradle, Kotlin, or Wear OS plugin update can break CI in non-obvious ways. Keeping the pipeline green means small, regular maintenance sessions even when you're not adding anything new.
None of this is insurmountable. It's simply the real work that never shows up in side-project demos.
What I'd change today
- I would adopt
androidx.health.connect.clientas an extra layer from day one - I would ship the trend charts in v1: users have been asking for them since week one
- I would invest earlier in onboarding: 40% of users drop off during the permissions setup
- I wouldn't use Supabase Storage for avatars, overkill. A simple URL + S3 would be cheaper
Numbers, for context
No secret data, no vanity metrics. FitMesh has real users but small numbers. That's not the point. The point is that it's an experiment that works, it's live, it's maintained, and it teaches me something new every week.
One indie app in production is worth ten indie apps in the drawer.