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:
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 opsSecurity 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.
// 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.
// 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:
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.