Skip to content

Work / Aakalan / Architecture

Aakalan architecture

A phone app that holds the ledger on the device and syncs it to Firebase. There is no server of our own. The one metered cost named in the repo is the SMS that sends a sign-in code.

last verified 2026-10-30

Known cost a month
₹0 of its own
The ₹31 a month on this account is AskCal's scans, paid from ₹383.78 of prepaid credit by choice. RevenueCat, EAS and store fees are not read.
What makes cost grow
Sign-in SMS
Phone auth bills real codes, but no SMS line is on the October bill. The per-SMS price is not recorded.
Accounts today
9
Firestore count on 2026-10-25, owner and test accounts included.

How it fits together

Pick something a user does to see its path and what it costs.

On the phoneOutside services (Firebase project aakalan-app)Aakalan appAakalan appExpo, iOS and Android; also runs on web$0Local ledger and photo queueLocal ledger and photo queueZustand store, AsyncStorage, pending receipts on disk$0Firebase AuthFirebase AuthPhone sign-in by SMS code · India only₹0: no line on the October billFirestoreFirestoreGroups, expenses, settlements, live listeners₹0: no line on the October billFirebase StorageFirebase StorageReceipt photos, JPEG, 1600 px, under 5 MB₹0: no line on the October billRevenueCatRevenueCatIs this user on Pro?Not readEASEASBuilds and over-the-air updatesNot readApp Store · Google PlayApp Store · Google PlayInstalls and Pro paymentsNot readGemini API (for AskCal)Gemini API (for AskCal)This account's credit pays for AskCal's scans₹30.84 in Oct; ₹67.64 in Sep
One SMS, price not read
India numbers only; test numbers cost nothing
  1. The user enters a phone number.
  2. Firebase checks the app, then sends a code by SMS. Other countries are blocked.
  3. The user enters the code and is signed in.
  4. The app starts its Firestore listeners. Nothing is shown until the groups listener has reported.

Cost

Every number says where it came from.

ServicePays forTodayGrows withBasis
Aakalan appExpo, iOS and Android; also runs on web$0NothingStatedCLAUDE.md
Local ledger and photo queueZustand store, AsyncStorage, pending receipts on disk$0NothingIn codesrc/data/store.ts; src/services/receipt-queue.ts
Firebase AuthPhone sign-in by SMS code · India only₹0: no line on the October billEach real SMS code. Test numbers send none.MeasuredCloud Billing report, Oct 1-30, read 2026-10-30
FirestoreGroups, expenses, settlements, live listeners₹0: no line on the October billReads and writes, plus live listeners per signed-in userMeasuredCloud Billing report, Oct 1-30, read 2026-10-30
Firebase StorageReceipt photos, JPEG, 1600 px, under 5 MB₹0: no line on the October billReceipt photos, a Pro featureMeasuredCloud Billing report, Oct 1-30, read 2026-10-30
RevenueCatIs this user on Pro?Not readSubscription revenueNot known
EASBuilds and over-the-air updatesNot readBuilds, app updatesNot known
App Store · Google PlayInstalls and Pro paymentsNot readDeveloper fees and a cut of Pro salesNot known
Gemini API (for AskCal)This account's credit pays for AskCal's scans₹30.84 in Oct; ₹67.64 in SepAskCal photo scansMeasuredCloud Billing and AI Studio, 2026-10-30; owner's choice, see askcal ops/gemini-credits.md

What breaks when something fails

If this failsThe user seesTheir dataBasis
Local ledger and photo queueNot applicable: this is the app's own memory. Every write lands here first, so screens have no loading state.A queued photo is kept until it uploads. Nothing is dropped after failed tries.In codesrc/services/receipt-queue.ts drain()
Firebase AuthA new sign-in fails. Someone already signed in should keep working.Safe, on the phoneAssumedNo test or runbook covers this
FirestoreOffline writes queue and send later. A refused write or unreadable list shows a banner.Local copy stays. A refused write can be overwritten by the next snapshot.In codesrc/services/sync.ts push(); wiki/concepts/sync-gates.md
Firebase StorageThe expense is saved. The photo waits in the queue.Photo stays on the phone until it landsIn codesrc/services/receipt-queue.ts; storage.rules
RevenueCatShown as not Pro, and the paywall can show no price. Adding, splitting, settling and export stay free.SafeStatedwiki/concepts/revenuecat-rules.md; wiki/concepts/pro-never-gates-the-core-loop.md

Where the data goes

Expenses, groups, settlements, profilePhone, and Firestore
Phone numberFirebase Auth
Receipt photosPhone, then Firebase Storage. Readable by the expense's members only.
Solo expensesFirestore, readable by the owner alone (rules)
ContactsRead on the phone when the user allows it. No upload is recorded.
Invite and reminder textsBuilt on the phone, sent by the user's own app

What we do not know yet

  • Gemini API on this account is AskCal's, by the owner's choice: it stops when the ₹383.78 balance runs out, and AskCal then moves to its own. Aakalan itself calls no Gemini.
  • RevenueCat, EAS and store fees are not read.
  • Price of one sign-in SMS and how many were sent: phone auth needs a billing account, but no usage or price is written down.
  • Firestore and Storage free-tier headroom: not recorded. The app has no backend functions, so there are no request logs.
  • The counts (9 users, 7 groups, 12 expenses, 9 settlements) include owner and test accounts, so real use is smaller.
  • Apple and Google developer fees and store cut: not recorded in this repo.
  • ops/setup.md says the Auth console still shows a stale 10 SMS a day quota. The real limit is not recorded.
  • firestore.rules and storage.rules must deploy together (storage reads Firestore membership); nothing records that they did.