Building BakiLedger: An Offline-First Personal Ledger with Kotlin and Jetpack Compose
A software project does not always begin with a technical problem.
Sometimes, it starts with a very ordinary situation.
For me, it started with a disagreement over a grocery shop's baki.
The shopkeeper told me that I had a certain amount outstanding. I remembered the amount differently. The shopkeeper had a handwritten ledger, while I was relying mostly on memory and previous transactions.
The problem was not necessarily the accuracy of either side.
The bigger problem was visibility.
The person maintaining the ledger had a record. The customer did not have an equally convenient way to maintain their own record.
That small observation became the starting point for BakiLedger.
What Is BakiLedger?
BakiLedger is an Android application designed for tracking personal dues, payments, and balances.
The product is intentionally focused on one simple use case:
Keep a clear record of how much you owe, what you have already paid, and what your current balance is across different shops.
Users can add multiple shops as separate records. Each shop can have an opening balance, followed by individual due and payment transactions.
The core balance calculation is:
Current Balance
= Opening Balance
+ Total Due
- Total Payments
Each transaction can also contain:
- Amount
- Transaction type
- Optional note
- Exact date and time
The goal was not to build another full accounting system.
It was to build a small, focused tool for an everyday problem: helping customers maintain their own record of baki instead of depending entirely on memory, notebooks, or someone else's ledger.
Why Offline-First?
One of the earliest decisions I made was that BakiLedger should work without an account, backend, or internet connection.
For this particular product, the core operation does not require a server.
A user should be able to open the application, check a balance, record a payment, or add a due even when there is no network connection.
That led to an offline-first, local-only architecture.
The application does not depend on a remote database for its primary functionality.
This also gives the product a clear privacy model: the user's ledger data remains on the device unless the user explicitly chooses to export or back it up.
Why JSON Instead of Room or SQLite?
This was one of the more deliberate technical decisions in the project.
For a larger Android application, a database abstraction such as Room can be an excellent choice.
For BakiLedger, however, I wanted to keep the storage layer small and straightforward.
The application uses an app-private JSON file for its local data.
The main data structures are essentially:
Shop
├── id
├── name
├── phone
├── address
└── createdAt
Transaction
├── id
├── shopId
├── amount
├── type
├── note
└── timestamp
Transaction types include:
DUE
PAYMENT
OPENING_BALANCE
The application can reconstruct the current balance from these records rather than maintaining a separate balance value that could become inconsistent with the transaction history.
This approach also made full backup and restoration simpler.
The decision was not that JSON is universally better than a database. It was a deliberate choice for the scope and requirements of this particular application.
Building the UI with Jetpack Compose
The Android UI was built using:
- Kotlin
- Jetpack Compose
- Material 3
- Material Icons
- Android's modern document APIs
The interface follows a relatively simple navigation model.
Home
The home screen provides:
- Total due
- Total number of shops
- Shop search
- Shop list
- Add Shop action
- Settings access
Shop Details
Each shop has its own details screen containing:
- Current balance
- Add Due
- Add Payment
- View Summary
- Transaction history
Transactions are displayed with their date and time, making the history useful as an actual record rather than just a running number.
Daily Summary
The summary view provides:
- Added Due
- Payments
- Net Change
- Current Due
This keeps the application useful not only for checking a total balance, but also for understanding recent activity.
Backup and Restore
Local storage introduces an important responsibility:
Users need a way to move or recover their data.
BakiLedger therefore includes JSON backup and restore functionality.
The exported backup contains the application's structured data rather than simply exporting a visual report.
The restore process supports two approaches:
- Replace existing data
- Merge backup data with existing data
This was particularly important because a local-only application should not make the user feel locked into a single device.
There is also CSV export for users who want their transaction data in a more universally accessible format.
For individual records, BakiLedger also supports shop-wise statement export in PDF format.
Keeping the Interaction Model Simple
A major part of the product design was deciding what not to include.
BakiLedger is not intended to replace full accounting software.
There is no complex chart of accounts, inventory management system, payroll module, or business analytics dashboard.
The interaction model is intentionally narrow:
Add a shop
↓
Set an opening balance
↓
Record dues
↓
Record payments
↓
Check the current balance
That simplicity is part of the product rather than a limitation I wanted to hide.
For a personal ledger, the user should not have to understand an accounting system before recording a payment.
Data Ownership and Privacy
Another product requirement was keeping the user's records under their control.
BakiLedger does not require:
- An account
- A cloud backend
- An internet connection for normal use
The application stores its working data locally.
Backup and export are user-controlled operations.
The project also has a dedicated privacy policy explaining how the application handles local data and user-initiated exports.
This approach fits the nature of the application: a personal record should remain useful without requiring a permanent online service behind it.
Product Website and Distribution
The project eventually expanded beyond the Android application itself.
I built a dedicated product website for BakiLedger with:
- Product information
- Feature documentation
- Screenshots
- How-it-works documentation
- Download section
- Privacy policy
- About page
- Changelog
- Contact page
- SEO metadata
- Sitemap
- Robots configuration
- Responsive layouts
The website is available at:
The Android application is also publicly distributed through APKPure:
https://apkpure.com/p/com.afeemuhammodwafy.baki
The Android application and its website were treated as one product rather than two unrelated deliverables.
What I Learned from the Project
BakiLedger was useful to me because it covered much more than UI development.
The project involved several different layers:
Problem Discovery
↓
Product Definition
↓
UX Design
↓
Android Development
↓
Local Data Architecture
↓
Backup & Restore
↓
Data Export
↓
PDF Generation
↓
Product Website
↓
Deployment & Distribution
One of the most important lessons was that scope is a technical decision.
It would have been easy to add accounts, cloud synchronization, a backend, notifications, analytics, and more.
Instead, I kept asking:
Does this solve the problem BakiLedger was created to solve?
If the answer was no, it did not automatically belong in the product.
That helped keep the application lightweight and focused.
The Bigger Idea Behind BakiLedger
The interesting part of this project is not simply that it records numbers.
It is the perspective from which the problem was approached.
Digital ledger software often focuses on the person or business maintaining customer accounts.
BakiLedger started from the other side of that relationship:
What if the customer wants to maintain their own record?
That small shift in perspective was enough to turn an everyday problem into a complete product.
And that is probably my favorite part of building software:
A simple real-world observation can eventually become a technical system with its own architecture, interface, documentation, and distribution strategy.
Final Thoughts
BakiLedger is a relatively small application, but it gave me the opportunity to work across the entire product lifecycle.
From identifying the problem to designing the interaction model, implementing the Android application, choosing a local data architecture, building backup and export workflows, creating the product website, and preparing the project for distribution.
The project reinforced something I keep finding in software development:
Good products do not necessarily need more features. They need the right features for the problem they are solving.
BakiLedger started with a simple question:
How can someone keep track of their own baki without depending on a notebook, memory, or someone else's ledger?
The answer became BakiLedger.
About the Creator
BakiLedger was created by Afee Muhammod Wafy, an independent developer focused on building practical software products and turning everyday problems into simple digital solutions.
Creator: Afee Muhammod Wafy
BakiLedger
Offline Baki & Shop Ledger
A focused, offline-first Android application for keeping personal dues, payments, and balances organized across different shops.
Product Website: https://bakiledger.amwafy.xyz
Download on APKPure: https://apkpure.com/p/com.afeemuhammodwafy.baki
Top comments (0)