# Building a library system for phones that lack a Bengali font

*16 September 2026*

মদন মোহন গ্রন্থাগার (Madan Mohan Library) is a community library in Bangladesh that has been running since 1948. Over the last year I built its digital management system: a catalogue, a blood-donor register, an events calendar, a member points ledger and a cash book, all on one codebase.

This post is about the parts that were interesting to build, and why they look the way they do.

## What it is

- **Backend:** Laravel 12, MySQL, S3 for files, web push for notifications. One deployment serves six hostnames, including the public site at [madanmohanlibrary.org](https://madanmohanlibrary.org) and the member app at [app.madanmohanlibrary.org](https://app.madanmohanlibrary.org).
- **Web app:** Vue 3 with Inertia.
- **API:** a REST API consumed by two native Android apps.
- **গ্রন্থাগার for Android:** the member app. Kotlin and Jetpack Compose.
- **কোষাগার (Koshagar) for Android:** the committee's treasury app, on the same API.

The Android apps are not on the Play Store. I will add a direct download link here once it is hosted on the library's site.

## Every decision came from one fact

Most members use low-end Android phones on unreliable networks. That single constraint decided almost everything about the mobile apps.

**The APK is 4.6 MB.** Storage on these phones is tight and downloads over mobile data are slow. Every dependency had to justify its size.

**No Google Play Services.** A lot of the target devices either do not have Play Services or have an old, broken version. Depending on it would have locked out the people the app is for. The cost is that push notifications, sync and crash reporting are things I handle myself rather than getting from Firebase.

**Android 7.0 minimum.** The floor was set by looking at what members actually carry, not by what the tooling makes convenient.

**A Bengali font is bundled.** Many of these phones ship without one, or with a font that renders conjuncts wrong. Bundling adds a few hundred kilobytes and removes an entire class of "the app shows boxes" reports.

**Offline first, with queue and replay.** Every action a member takes without a connection is written to a local queue and replayed when the network returns. The awkward part is conflicts: two people updating the same record while both offline. I resolved this per record type rather than with a general rule, because a points-ledger entry and a catalogue edit do not want the same behaviour.

## The treasury app

কোষাগার exists because the library's money handling was a paper notebook. The app turns it into a ledger: every receipt and payment is an entry with who recorded it and when, and the committee can audit the book at any point. This mattered more to the committee than any other feature, and it is the reason the project has a second native client instead of a web view.

## The almanac

The library runs on the Bengali calendar for its events, so the backend computes the পঞ্জিকা for the library's exact coordinates: sunrise, তিথি (lunar day), নক্ষত্র and পার্বণ (festivals). I had never touched lunar-day arithmetic before, and it was the part of the project I enjoyed most. Sunrise depends on where you are, which is why the calculation is tied to the library's location rather than a national table.

## Six hostnames, one codebase

The public site, the member app, the API and a few smaller surfaces all run from the same Laravel deployment, routed by hostname. This was a deliberate trade against having several small services. For a volunteer-run library, one thing to deploy, back up and monitor is worth more than clean separation.

## What I would tell someone building something similar

Start from the phones people actually have, not from the phone in your pocket. Almost every hard technical choice in this project was easy once I had that list.


---

*Source: https://mishuk.me/writing/madan-mohan-library-system*
