
A daily total tells you how much caffeine you logged. A timeline also shows when you logged it. I built Unbuzz to make that time dimension easier to explore with an adjustable estimate.
I designed and built the iOS and Android app, the calculation engine, and companion experiences for Apple Watch and iOS widgets. The product is an example of my own engineering work, not a clinical validation or a client-results claim.
Make the calculation understandable
Unbuzz applies a simplified decay calculation to each logged drink and sums the estimates. The inputs include the logged amount, time since the drink, and a configurable half-life.
This is the basic calculation, shown separately from the app’s input validation and settings:
double remainingCaffeine(double initial, double hours, double halfLife) {
return initial * pow(0.5, hours / halfLife);
}
The half-life is a model input, not a measurement of an individual’s metabolism. A threshold crossing is a result of those settings, not a guarantee that a person will sleep well or that an amount is safe.
I made the assumptions adjustable and put explanations alongside the curve. The interface needs to distinguish a software estimate from something the phone has measured.
Keep the daily log on the device
I used Drift, a SQLite library for Dart, to store drinks, presets, and settings locally. Core logging and calculations work without an account or network connection.
Local storage also gives the calculation code a consistent place to read from. A logged drink can update the dashboard immediately instead of waiting for a server response. I do not claim a particular response time without a measurement on a specified device and release build.
Optional synchronization is a separate layer. That distinction matters: a user choosing to sync records should not change whether the basic tracker works offline.
Share calculations, not just screen layouts
Flutter provides the shared phone interface. Riverpod connects the stored drinks and settings to the calculations that feed the chart and timing summaries.
A useful boundary is to keep calculation logic independent of widgets. It can then be tested with known inputs: several drinks at different times, a changed half-life, or an edited log entry. The graph and its summaries should agree because they use the same underlying values.
The framework does not establish calculation correctness by itself. The inputs, edge cases, and displayed units still need explicit tests.

Native integrations need their own boundaries
I used platform bridges for native features, including health-data integrations and the Apple Watch companion. The phone and Watch exchange drink logs and caffeine state. iOS widgets read a shared snapshot of the current state.
These are different surfaces with different update rules. A widget is not a continuously running copy of the app. Its displayed state needs to make sense when the operating system controls the next refresh.
For the user, the purpose is simple: log a drink from the wrist or check the estimate without navigating through the whole phone app.
Explain patterns without inventing outcomes
The insights screens summarize logged intake, timing, and routine patterns. They should describe the data and assumptions behind a result.
A percentage about sleep quality needs a defined metric, a data source, and enough context to interpret it. These notes do not claim a measured improvement in sleep, a validated causal relationship, or a universal benefit from changing caffeine intake.
That editorial limit is also a product-design constraint: the strength of the wording should match what the calculation can actually support.
Accounts, permissions, and purchases
The optional sync layer uses Supabase. Row Level Security can scope database access to the authenticated user, but policy design, tests, and privileged credentials remain part of the application’s responsibility. A platform’s security features do not establish the privacy or compliance of a finished app. Supabase explains the policy model and its exceptions.
RevenueCat handles purchase and entitlement integration. Which features are included in each plan can change, so the published app is the place to check current purchase options.
What this build demonstrates
Unbuzz connects a local data model, testable calculations, a Flutter interface, and native companion screens. The useful engineering lesson is to keep those parts consistent while making the estimate’s limits visible.
Explore the production screenshots, or discuss a mobile product of your own.