Athlenote · 2024
A voice-first training journal athletes actually fill in
Built and shipped a subscription sports journaling app to both stores, using voice capture to remove the friction that kills training logs.
- Role
- Sole developer
- Team
- Solo, working with the founder
- Timeline
- 2024

Outcomes
- App stores shipped to
- 2
The problem
Training journals fail for a boring reason: nobody wants to type paragraphs after a hard session. The value of the log is in the detail, and the moment you ask a tired athlete to type, the detail disappears. The product needed a capture method that costs the user almost nothing at the moment they're least willing to spend effort.
Constraints
- Solo build on a founder's budget — every hour had to go into the product, not the plumbing
- Subscriptions had to work identically on iOS and Android, including restore
- Voice recording had to be reliable enough to trust with the only copy of a session
- App Store review for a subscription app is unforgiving about restore and pricing clarity
Approach
FlutterFlow was the right call here, and that's a judgement about context rather than about the tool: a solo developer on a budget gets a real product in front of real athletes far faster, and the app's demands sat inside what the platform does well. Voice capture became the primary input rather than an alternative one. Subscriptions went through RevenueCat instead of being hand-rolled against two different store APIs, which is where most of the risk in a subscription app actually lives.
What I rejected, and why
Hand-rolling store subscriptions
Two store APIs, two sets of receipt validation, two restore flows and two sets of edge cases — for a solo build that is most of the budget spent on something RevenueCat already does correctly.
Custom Flutter from the start
It would have been the better codebase and the worse decision. The product needed to reach athletes and find out whether voice-first capture worked at all before earning a hand-built foundation.
Architecture
The hard part
Entitlement state that is correct in every case. A subscription app has more states than it first appears: subscribed, expired, in grace period, billing-retry, refunded, restored on a new device, and bought on one platform but opened on the other. Each one has to resolve to the right answer about what the user can see, and getting it wrong in either direction is bad — locking out a paying athlete, or giving away the product. Building it so that entitlement is derived from one source of truth rather than checked ad hoc in each screen was the difference between it working and it mostly working.
What I'd do differently
Choosing the less impressive tool was the right engineering decision, and I'd defend it in an interview. The interesting question was never 'is FlutterFlow good enough' — it was 'what is the cheapest way to find out whether athletes will actually log sessions by voice'. Optimising the codebase before answering that would have been optimising the wrong thing.
Stack
- FlutterFlow
- Firebase
- RevenueCat
- Payments
- iOS
- Android