Most budgeting apps answer one question: what did I spend? The question I actually ask myself is different: how much can I spend today without regretting it on the 28th?
So I built Budget Lover, an Android app (Flutter + Firebase + Gemini) that answers that second question with one number, a daily "safe to spend" amount, and an AI advisor you can ask follow-up questions. I'm a Computer Science student and this is a solo project. It is not released yet, so everything below is from building and testing it on an emulator with demo data.
The one number: safe to spend
The core idea is simple. Take what is in the account and subtract everything that is already spoken for until the next payday:
// simplified from my engine
safe = balance
- upcomingBills
- subscriptions
- plannedPayments
- savingsContribution
- safetyBuffer;
dailyAllowance = safe > 0 ? safe / daysUntilPayday : 0;
What is left is money you can spend freely, and dividing it by the days until the next income gives a daily allowance. The real version also handles things like a monthly budget cap, trips, debt payments and subscriptions detected from your history, but the shape is the same.
I put all of this in a pure Dart "engine" layer with no Flutter or Firebase imports. That turned out to be the best decision of the project, because it can be unit tested in milliseconds, and the app has a lot of edge cases (month ends, paydays that move, a bill that lands tomorrow).
The AI explains, the code calculates
I wanted an advisor that can answer "Can I afford a €80 purchase?", but language models are unreliable at arithmetic and happy to invent numbers that sound right. So the AI never does the math.
When the user asks a question, the app first works out the relevant facts locally: the current safe-to-spend, what it would become after the purchase, the new daily allowance, upcoming bills. Only then does it send those facts to Gemini with the question, and ask it to explain the result in plain language.
The advisor's answer in the screenshot above ("new safe to spend €290, verdict: tight") is built on numbers my engine produced. The model's job is tone and explanation, not accounting. A side effect: the facts are just totals and category names, so the model never needs to see individual transactions.
The same engine powers a "what if?" simulator. It runs the calculation twice, once with your real data and once with a change (spend €150, cancel a subscription, earn less), and shows the difference. Nothing is saved.
No API key in the app
A mistake I made early on was shipping an AI key inside the app. Anything inside an APK can be extracted. I moved to Firebase AI Logic, which sits between the app and Gemini, so the app contains no key at all. Combined with App Check, requests only work from the real app.
It has a cost too: free-tier limits are low, so the advisor has a daily message counter (you can see "10 left" in the screenshot) and I use a lighter, cheaper model for small jobs like reading receipts.
Smaller features that taught me the most
- Receipt scanning: a photo goes to a lightweight Gemini model, which returns the amount, merchant and category. The parsing of its answer is regular code with validation, so a bad answer cannot corrupt data.
- Subscriptions: regular payments are collected in one place with their yearly cost. The app works out the kind (streaming, music, cloud...) from the name, on the phone, so it can spot overlaps like three streaming services and tell the AI the kinds without the names.
- Trips: a budget per trip, per-day and per-person costs, and live currency conversion.
- Monthly wrap-up: story-style cards you can export to PDF.
- XP and badges: small rewards for good habits.
- 15 languages, including right-to-left Arabic. I wrote my own small translation layer and layout tests that fail when a translation is too long for its box.
What I'd tell my past self
- Keep the logic out of the widgets. The engine layer paid for itself within a week.
- Don't let the model do what a function can do. Use it for language, not for numbers.
- Test the boring parts. The project has more than 50 test files, and most bugs I found were date edge cases, not UI.
- Demo data matters. I built a demo account so I could take screenshots and test without touching real data.
Stack
Flutter and Dart, Provider for state, Firebase Authentication and Firestore, Firebase AI Logic with Gemini, and Flutter's PDF and printing packages.
I'm looking for freelance work building apps and websites like this one. If you'd like to see more of my work, or you have an app idea, you can find me through my portfolio.
Portfolio: https://ostyl51.github.io


Top comments (2)
Keeping the math in Dart and letting the model explain it is the right split. One case worth a test: money in doubles. 0.1 + 0.2 drifts, and an allowance split by days can show 33.333. Do you store amounts as integer cents and round only for display?
"Use it for language, not for numbers" is the line I wish more AI app tutorials started with. Computing the facts locally and only asking the model to explain them also gives you something you can unit test, which a prompt never does.
One thing I would add from a similar setup: the model can still restate a number wrongly in its explanation, even when you hand it the correct one. A cheap guard is to check that every figure in the reply appears in the facts you sent, and fall back to a plain template when it does not.
Moving the key out of the APK early was the right call too. I made the same mistake once and fixed it with a server-side proxy.
How do you handle the daily message limit in the UI when the user hits it in the middle of a conversation?