← All Projects

Budget Buddy

Our own money manager for iOS and Android. It keeps a double-entry ledger on the phone, checks it against bank statements day by day, and recomputes balances instead of adjusting them.

Home screen: net worth of 24,038.40 USD, assets, debts and 30-day income and expenses
Spending by category as a donut chart: Renting, Utilities, Groceries and Flights
  • 7

    SQLite triggers guarding cached balances

  • 111

    illustrated categories out of the box

  • 6

    bank statement formats, plus any CSV

  • 600+

    automated tests

Client
KorLab, our own product
Stores
App Store and Google Play
Platforms
iOS and Android from one Flutter codebase
Our part
Everything, design included
Timeline
Since November 2024, in stores since September 2025

The brief.

Context

Budget Buddy is our own personal finance app, designed and built by KorLab end to end. People track accounts, spending, budgets and subscriptions, import bank statements and back their data up to their own Google Drive. The ledger lives in a SQLite database on the device, and the interface is translated into seven languages.

Challenge

Finance apps usually keep balances as running totals and nudge them on every write. It is fast, and it is how balances drift: one missed update or a crash mid-write, and the number on screen stops matching the transactions behind it. People also expect the app to agree with their bank, which means reading each bank's own statement format.

Approach

We made the ledger the only source of truth. SQLite triggers mark cached balances stale in the same transaction as the write, and balances are recomputed from the ledger rather than adjusted. Bank statements are parsed per bank and compared with the app day by day. A paired browser opens the same ledger on a computer, and an optional AI agent answers questions about it.

A year of money, read at a glance.

Home opens on net worth and the last 30 days of income and spending. Statistics breaks any period down into an overview, spending by category, net worth and cashflow. The transaction list groups entries by day and shows each account's balance after every entry.

Statistics overview for a year: net 24,102.66 USD, income, expenses and a 52.1% savings rate
Overview
Cashflow tab with 46,290 USD income, 22,187.34 USD expenses and a monthly cashflow trend
Cashflow
October transactions grouped by day, with account balances next to each entry
Transactions

Every expense in a few taps.

An expense is a move from one account to another: from the card it was paid with to the category it was spent on. Categories are illustrated tiles grouped into sub-accounts, so Groceries sits one tap inside Food. Every entry is double-entry underneath.

  • 111 illustrated categories come with a new install.
  • Splits send one payment to several categories.
Expense category picker with illustrated tiles for Housing, Food, Transport, Car and more
Categories
Food sub-accounts: Groceries, Cafe, Coffee, Sushi, Desserts and others
Food
Add expense form: 64.20 USD from Bank A to Groceries
Expense

Balances that cannot drift.

The ledger is three tables: transactions, their entries and opening balances. No total on screen is kept up to date by hand. Cached balances are marked stale by the database itself, and running balances are never stored at all.

  • Equivalence tests hold the fast paths to the same answer as a full recomputation.
  1. A write

    Adding, editing or importing a transaction changes ledger rows inside one SQLite transaction.

  2. Triggers

    Seven triggers mark the affected balances stale in that same transaction, so a crash leaves both changes or neither.

  3. Revision counter

    Every write bumps one data_revision counter. Statistics and summaries remember the revision they were computed at.

  4. Recompute

    Stale balances and outdated summaries are rebuilt from the ledger, never adjusted in place.

  5. On screen

    Running balances in a list are folded in memory from the account total, so there is nothing to keep in sync.

The bank statement checks the app.

Import a statement and the app matches each bank row to its own entries. Rows the bank has and the app does not become review cards. Then each day's closing balance is compared with the bank's, so a gap shows up on the day it appeared.

  • Six bank formats are read natively, Revolut and monobank among them, plus any CSV.
  • When only the time of an entry differs, one tap aligns it with the bank.
Reconciliation by day for October: app and bank balances match with a 0.00 difference
Reconciled
Review card for a 6.75 USD Starbucks payment that only the bank has, with the daily balance gap
Review
Fix discrepancies: entries whose amounts match the bank but whose times differ
Time fixes

The same ledger on a bigger screen.

On the same Wi-Fi, the phone serves a web console to a browser. The browser asks for a four-character passcode, the phone asks its owner to confirm, and the computer then works with the ledger on the phone. The data does not leave the local network.

  • The console is a Vue 3 app with ECharts, served by a small shelf server inside the Flutter app.
Home
Transactions

Ask the ledger a question.

The agent answers questions about the user's own data: top categories, this month against last, budgets worth setting. It reads the ledger through read-only tools and can draw charts. When it suggests a transaction it opens a filled form, and nothing is saved until the user presses Save.

  • Users bring their own OpenAI or Gemini key, and data is sent only after they allow it.
Agent start screen with suggested questions: top spending categories, this month against last, budgets to set
Questions
Agent answer listing the top five categories of the last 90 days, with a donut chart of 6,278.65 USD in spending
Answer

Black canvas, one accent.

The main theme is black with graphite cards and a single purple accent. Green and red are kept for income and expense, so colour always means money moving. Type is set in Geist.

  • Background
  • Card
  • Accent
  • Income
  • Expense
  • Text
October budgets with progress bars; Taxi is over its limit by 30%
Budgets
Subscriptions: five active, 129.55 USD a month in total
Subscriptions

What we built.

Our part

  • Product and interface design
  • Flutter app for iOS and Android
  • Double-entry ledger on SQLite
  • Bank statement import and reconciliation
  • Remote console in Vue 3, served from the phone
  • AI agent on OpenAI and Gemini
  • Backup to Google Drive
  • Releases to the App Store and Google Play

Stack

App
  • Flutter
  • Dart
  • Provider
  • fl_chart
  • ARB localization, 7 languages
Data
  • SQLite (sqflite)
  • SQL triggers
  • Flutter Secure Storage
  • Google Drive API
Remote console
  • shelf
  • Vue 3
  • Pinia
  • ECharts
  • Vite
AI
  • OpenAI API
  • Gemini API
Operations
  • RevenueCat
  • Firebase Crashlytics
  • Firebase Remote Config
  • GitHub Actions
  • Fastlane

Building a finance product?
Let's make the numbers add up.

Ledgers, bank imports, data that stays on the device. Tell us what yours has to get right.