C:\ARDI\PROJECTS\UTANG_GRUP> type case-study.txt

Utang Grup: a shared-expense app built in a weekend

Utang Grup: aplikasi patungan yang dibuat dalam satu akhir pekan

A phone-first web app my group of six friends uses to split bills and settle debts. No accounts and no app store, but the database still refuses anyone without the group PIN.

Web app untuk HP yang dipakai grup berenam teman saya untuk bagi tagihan dan melunasi utang. Tanpa akun dan tanpa app store, tapi database tetap menolak siapa pun yang tidak punya PIN grup.

66friends use itteman memakainya
2 days2 harito build the first versionuntuk membangun versi pertama
Rp 0Rp 0monthly hosting costbiaya hosting per bulan
33automated test suitesrangkaian tes otomatis

My role: everything, from the database schema to the iPhone layout. Stack: plain HTML, CSS and JavaScript, Supabase Postgres with row-level security, a Vercel function for receipt scanning (Gemini), PGlite and the Node test runner.

Peran saya: semuanya, dari skema database sampai tampilan iPhone. Stack: HTML, CSS, dan JavaScript murni, Supabase Postgres dengan row-level security, fungsi Vercel untuk scan struk (Gemini), PGlite, dan Node test runner.

01 The briefKebutuhannya

02 What I builtYang saya bangun

utang-saldo.jpg
Balance screen suggesting the fewest transfers, made-up names

Balances and the fewest transfers — demo data

Saldo dan transfer paling sedikit — data demo

utang-riwayat.jpg
Transaction history with made-up bills

History — demo data

Riwayat — data demo

03 ArchitectureArsitektur

utang_grup — architecture
iPhone Safari6 friendsStatic web appHTML · JS · VercelPIN-checked RPCsecurity-definer functionsPostgres + RLSall tables locked/api/scanreceipt → itemsPGlite testsin-memory PostgresHTTPSanon keyread / writephotonode --test

The public key is in the page on purpose. It can only call functions that check the PIN first.

Kunci publik memang ada di halaman. Kunci itu hanya bisa memanggil fungsi yang mengecek PIN lebih dulu.

04 Security without accountsKeamanan tanpa akun

05 Testing a database you cannot run locallyMenguji database yang tidak bisa dijalankan lokal

I did not want to test against the real group's data. The tests load the actual schema.sql into PGlite, an in-memory Postgres, and call the same functions the app calls. A small local server emulates Supabase's RPC endpoint the same way, so the whole app runs on a laptop with a throwaway database.

Saya tidak mau menguji dengan data grup yang asli. Tesnya memuat schema.sql yang sebenarnya ke PGlite, Postgres di memori, lalu memanggil fungsi yang sama dengan yang dipanggil aplikasi. Server lokal kecil meniru endpoint RPC Supabase dengan cara yang sama, jadi seluruh aplikasi bisa jalan di laptop dengan database sementara.

06 What I learnedPelajaran

Want a small, secure tool built quickly for your team?

Butuh alat kecil yang aman dan cepat jadi untuk timmu?

WhatsApp Email Download CVUnduh CV More projectsProyek lain