Skip to main content
Asif.
← All Articles
KotlinSwiftNext.jsMicroservicesBangladeshPersonal Project

Building TakaTrack (Gunti): 4 Platforms, 11 Microservices, and Everything I Learned Shipping a Personal Finance Ecosystem for Bangladesh

Mar 202516 min readAsif Ahsan

TakaTrack started as a simple expense tracker and became something I didn't expect: a full personal finance ecosystem with native Android and iOS apps, a Next.js PWA, an admin dashboard, 11 backend microservices, Firebase Phone OTP, OpenAI-powered insights, and a Zakat calculator. Here's what building it actually looked like.

TakaTrack started with a single question: why does every personal finance app ignore how money actually moves in Bangladesh? bKash, Nagad, Rocket — these are the payment rails for over 60 million Bangladeshis. Every transaction generates an SMS. There are no bank APIs, no card webhooks, no open banking standards. Just SMS messages.

I started building what I thought would be a simple SMS-parsing expense tracker. Twelve months later, TakaTrack (branded as Gunti — Bengali for 'count') is a four-platform ecosystem with 11 backend microservices, native Android and iOS apps, a Next.js PWA, an admin dashboard, and more features than I originally planned. Here's the honest account of building it.

The Full Architecture

TakaTrack has four client surfaces, each built natively for its platform:

  • Android: Kotlin + Jetpack Compose — primary platform, SMS reading with WorkManager background polling, Material 3 UI
  • iOS: Swift + SwiftUI — manual entry with smart prediction, Shortcuts integration
  • Web (desktop): Next.js 15 PWA — full dashboard with Recharts analytics, family group management, installable via service worker (Serwist)
  • Admin Dashboard: Next.js 15 — internal tools, user management, subscription tracking, feature flags

Behind them, 11 Node.js microservices each own a specific business domain with their own PostgreSQL database:

text
Service            Port   Responsibility
─────────────────────────────────────────────────────
api-gateway        3000   JWT verification, rate limiting, routing
auth-service       3001   Firebase Phone OTP → JWT tokens
user-service       3002   Profiles, subscriptions, family groups
expense-service    3003   CRUD, categories, receipt uploads (S3)
budget-service     3004   Monthly budgets, threshold alerts
loan-service       3005   EMI schedules, Zakat calculator
notification-svc   3006   FCM push, bill reminders
sms-service        3007   Parses bKash / Nagad / Rocket / bank SMS
analytics-service  3008   Reports, trends, OpenAI insights
payment-service    3009   bKash tokenized, Nagad, SSLCommerz
admin-service      3010   Feature flags, promo codes, user ops

Security First: The BFF Pattern

One of the most important architecture decisions was implementing the Backend for Frontend (BFF) pattern for the web app. The Next.js server acts as a secure intermediary — it handles authentication with the auth-service and issues JWT tokens stored in httpOnly cookies. The browser never sees the JWT. Client-side JavaScript has no way to read or steal it.

typescript
// Next.js API route — acts as BFF
// /app/api/auth/login/route.ts
export async function POST(req: Request) {
    const { phone, otpCode } = await req.json();

    // Verify OTP with Firebase on the server
    const { token } = await authService.verifyOtp({ phone, otpCode });

    // JWT lives only in a httpOnly cookie — never in JS
    const response = NextResponse.json({ success: true });
    response.cookies.set("auth_token", token, {
        httpOnly: true,
        secure: process.env.NODE_ENV === "production",
        sameSite: "strict",
        maxAge: 60 * 60 * 24 * 7, // 7 days
        path: "/",
    });
    return response;
}

This BFF pattern is the right way to handle auth in Next.js apps that talk to microservices. Storing JWTs in localStorage or even sessionStorage exposes them to XSS attacks. httpOnly cookies are immune — they're sent by the browser automatically but can never be read by JavaScript.

Phone-Only Authentication — A Deliberate Bangladesh Choice

TakaTrack has no email login, no Google sign-in, no password. Purely phone number + OTP via Firebase Phone Auth. This is intentional. Bangladesh has some of the highest mobile penetration rates in South Asia. Almost every adult has a phone number. Email usage is far less universal, especially among non-tech-savvy users. Phone OTP removes the friction of remembering passwords and is instantly familiar to anyone who uses bKash.

Firebase Phone Auth handles OTP delivery and verification. On successful verification, Firebase returns a credential. The auth-service exchanges this for a platform JWT, which the BFF stores in the httpOnly cookie. Subsequent API calls are authenticated via that cookie — the mobile apps use Authorization headers with their own shorter-lived tokens.

The SMS Intelligence Service

The sms-service is a dedicated microservice that parses incoming transaction messages from four providers: bKash, Nagad, Rocket, and Bangladeshi banks (Islami Bank, Dutch-Bangla, BRAC Bank, etc.). Each provider has multiple message templates — send money, receive money, merchant payment, cash out, salary credit, airtime top-up, and more.

typescript
// sms-service: transaction extraction from raw SMS body
interface ParsedTransaction {
    platform: "bkash" | "nagad" | "rocket" | "bank";
    type: "send" | "receive" | "payment" | "cashout" | "cashin";
    amount: number;
    balance?: number;
    recipient?: string;
    trxId?: string;
    timestamp: Date;
    confidence: number; // 0–1, how certain we are about the parse
}

const BKASH_PATTERNS: SmsPattern[] = [
    {
        type: "send",
        regex: /You have sent Tk ([d,]+.d{2}) to (d{11}).*?balance is Tk ([d,]+.d{2}).*?TrxID (w+)/s,
        groups: { amount: 1, recipient: 2, balance: 3, trxId: 4 },
    },
    {
        type: "receive",
        regex: /Tk ([d,]+.d{2}) has been credited.*?by (d{11}).*?TrxID (w+)/s,
        groups: { amount: 1, sender: 2, trxId: 3 },
    },
    {
        type: "payment",
        regex: /You have paid Tk ([d,]+.d{2}) to (.+?) successfully.*?TrxID (w+)/s,
        groups: { amount: 1, merchant: 2, trxId: 3 },
    },
    // 9 more bKash patterns, 8 Nagad patterns, 6 Rocket patterns, 12 bank patterns...
];

The service returns a parsed transaction or a low-confidence flag that triggers a manual review prompt in the app. The parsing accuracy across bKash and Nagad messages is currently at 94%.

OpenAI-Powered Spending Insights

The analytics-service does standard reporting (monthly summaries, category breakdowns, trend charts via Recharts on the web). But the most interesting feature is AI-powered insights using the OpenAI API. Once a month, the service aggregates a user's anonymized spending patterns and sends them to GPT-4 with a carefully crafted prompt:

typescript
async function generateInsights(userId: string): Promise<string> {
    const summary = await buildSpendingSummary(userId); // aggregated, no PII

    const prompt = `
You are a personal finance advisor for a Bangladeshi user.
Analyze this spending summary and provide 3 specific, actionable insights
in simple language. Focus on patterns, not lectures.

Spending summary (last 30 days):
- Total spent: ৳${summary.total}
- Top categories: ${summary.topCategories.join(", ")}
- vs. last month: ${summary.changeVsLastMonth}%
- Budget adherence: ${summary.budgetAdherence}%
- Unusual transactions: ${summary.unusualItems.join(", ")}

Write in a friendly, non-judgmental tone. Use Bengali currency (৳).
`;

    const response = await openai.chat.completions.create({
        model: "gpt-4o-mini", // cost-effective for monthly summaries
        messages: [{ role: "user", content: prompt }],
        max_tokens: 300,
    });

    return response.choices[0].message.content ?? "";
}

The Zakat Calculator — A Feature I Didn't Plan

The loan-service includes an EMI calculator as expected. What I didn't plan for was the Zakat calculator. Bangladesh is 90% Muslim, and Zakat — an annual religious obligation to donate 2.5% of qualifying wealth above a minimum threshold (Nisab) — is something many users asked about early in beta.

The Nisab threshold is calculated in silver (85g) or gold (612.35g), which means it fluctuates with commodity prices. The Zakat calculator in TakaTrack uses current gold/silver prices fetched from a commodity API, calculates the Nisab in BDT, compares it to the user's declared assets, and outputs their Zakat obligation. It's a simple calculation but one that users interact with once a year and have to look up manually otherwise. Small feature, disproportionate value.

Payment Integrations — bKash Tokenized is Hard

TakaTrack has a subscription tier (premium features: AI insights, family groups, advanced analytics). The payment-service handles three providers: bKash tokenized payment, Nagad, and SSLCommerz (card payments). bKash tokenized was by far the most complex to integrate.

bKash's tokenized payment flow lets users authorize TakaTrack once and then be charged automatically for recurring subscriptions without approving each transaction. The merchant agreement process is bureaucratic — it requires a trade license, TIN certificate, and bank account documentation. The technical integration itself involves a multi-step OAuth-like flow where TakaTrack exchanges a grant token for an ID and access token, which are then used to execute charges.

Family Groups and Real-Time Sync

The user-service manages family groups — a feature where multiple family members share a financial view. Shared expenses are pooled, and the system calculates net settlement amounts (who owes whom). The real-time challenge: when three family members transact throughout the day, the shared dashboard needs to stay current. I used Redis pub/sub to broadcast transaction events, with Server-Sent Events delivering updates to the Next.js web app and WebSockets to the mobile apps.

What Took Longer Than Expected

  • bKash merchant registration: 6 weeks of back-and-forth with documentation before getting sandbox access
  • SMS parser edge cases: SMS formats change without notice — I've had to update patterns three times already
  • Bilingual UI: next-intl is excellent but ensuring every string, every error message, every toast notification exists in both Bangla and English is meticulous work
  • Firebase Phone Auth on Android emulator: OTP interception for testing required a custom test phone numbers setup that isn't well documented
  • Microservice debugging: when something breaks across service boundaries, distributed tracing becomes essential — I added OpenTelemetry later than I should have

Current Status

TakaTrack is in closed beta with 40 users in Dhaka. The Android app is feature-complete. The iOS app covers core expense tracking; advanced features are in progress. The web dashboard is fully functional. Target: Play Store launch with 500 beta users by Q2 2025.

If you're building in the Bangladeshi fintech space, or curious about any part of this architecture, I'd genuinely enjoy talking about it. The intersection of local payment infrastructure and mobile-first software design in emerging markets is a fascinating problem space.

A
Asif Ahsan
Senior Software Engineer · Dhaka, Bangladesh

Full-stack engineer with 8+ years building scalable products across web, mobile, and cloud. Currently building Gunti, Nexus RTC, and Nagorik.