Skip to content
ARAfsar RakhaSoftware Engineer
JKT --:--:--HomeAboutProjectsContactGet in touch
© 2026 Afsar Rakha· built in Jakarta, not Gotham
UsesGitHubLinkedInEmailResume
← All projects
01engineering2026

Klari.id

Live demo ↗

Inside the app

Klari is a finance and wealth tracker built for the Indonesian market — designed to become a top-of-mind way for Indonesians to manage money and grow their net worth. It unifies day-to-day budgeting with a polymorphic portfolio engine that tracks five investment instruments (saham, reksadana, emas, obligasi, deposito) in a single schema, and an AI-powered Split Bill that turns a photo of a receipt into an itemized, fairly-split expense. Built and shipped solo, end-to-end, and running in production at klari.id.

The problem

Indonesians who invest end up with saham in one app, reksadana in another, emas somewhere else, and a group dinner that still means typing a receipt by hand. Klari puts day-to-day money and a five-instrument portfolio in one place, and turns a photo of a bill into a split.

5

instrument types, one schema

347

unit and integration tests

2

languages, ID and EN

1

engineer, design to production

Architecture

CLIENTAPIDATA AND SERVICESHTTPSper-user lockphotoReact 19 + ViteTailwind 4, i18n ID/ENExpressVercel serverlessBetterAuthemail + GoogleSupabase PostgresDrizzle ORM,advisory locksOpenRouterreceipt OCRMidtransKlari Plus billingUpstash Redissessions

Client

  • React 19 + Vite · Tailwind 4, i18n ID/EN

API

  • Express · Vercel serverless
  • BetterAuth · email + Google

Data and services

  • Supabase Postgres · Drizzle ORM, advisory locks
  • OpenRouter · receipt OCR
  • Midtrans · Klari Plus billing
  • Upstash Redis · sessions

Flows

  • React 19 + Vite → Express · HTTPS
  • React 19 + Vite → BetterAuth
  • Express → Supabase Postgres · per-user lock
  • BetterAuth → Upstash Redis
  • Express → OpenRouter · photo
  • Express → Midtrans

The hard parts

01

One schema for five instruments

Saham, reksadana, emas, obligasi and deposito each value differently: units times price, NAV, grams times spot, face value with coupons, principal with interest. Instead of five tables and five code paths, holdings are polymorphic rows over a single schema and one valuation module owns the math, so a new instrument is a new case, not a new subsystem.

02

Lost updates under concurrent writes

A user can have the web app and a second tab or device writing at once. Every write path takes a Postgres advisory lock keyed on the user, which serialises their writes without locking anyone else out. It eliminated the lost-update class of bug outright rather than patching individual races.

03

Receipt photo to a fair split

The split-bill flow is a pipeline: photo in, OCR through OpenRouter, items parsed into lines, then per-item or even split with reimbursement tracking and a shareable breakdown card. Each stage fails independently and hands back something editable, so a bad scan costs a correction, not a restart.

Key contributions

  • Built solo end-to-end — React 19 + Vite + Tailwind 4 frontend on an Express / Vercel serverless backend, covered by 347 unit + integration tests
  • Designed a polymorphic portfolio engine tracking 5 instrument types (saham, reksadana, emas, obligasi, deposito) in a single schema with centralized valuation math
  • Built an AI Split Bill: receipt photo → OCR parsing → per-item or even split → reimbursement tracking, with a shareable breakdown card
  • Engineered per-user data isolation with a Postgres advisory lock that serializes every write path, eliminating lost updates under concurrent writes
  • Implemented auth with BetterAuth (email + Google OAuth), Upstash Redis sessions, and Supabase Postgres via Drizzle ORM — all per-user scoped
  • Shipped a Klari Plus subscription tier with Midtrans billing and a fully bilingual (ID/EN) i18n system
roleSolo Founder & Full-Stack Engineer
year2026
typeengineering

Stack

ReactViteTailwind CSSBetterAuthDrizzle ORMSupabaseOpenRouter AIPayment Gateway

Links

Live demo↗

next →

CBT Pustaka Mulia