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.
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
- One place to record shared bills and direct debts for a small group, used mostly on iPhone Safari.
- Nobody wants another account or password, so one shared group PIN.
- It must cost nothing to run, and the data must not be readable by strangers even though the site is public.
- Satu tempat untuk mencatat tagihan bersama dan utang langsung untuk grup kecil, kebanyakan dipakai di Safari iPhone.
- Tidak ada yang mau bikin akun atau password lagi, jadi cukup satu PIN grup.
- Harus gratis dijalankan, dan data tidak boleh bisa dibaca orang asing walaupun situsnya publik.
02 What I builtYang saya bangun
- Split bills equally or with custom amounts, record direct debts, and mark debts as paid.
- Debt simplification: a greedy algorithm matches the biggest creditor with the biggest debtor, so the group settles with the fewest transfers.
- Receipt scanning: take a photo and an AI model reads it into items, which you assign to people. Tax and service are shared in proportion, and rounding uses the largest-remainder method so every rupiah adds up exactly.
- History and accountability: editable transactions, receipt photos, and an activity log of who changed what.
- Bagi tagihan rata atau dengan nominal custom, catat utang langsung, dan tandai utang lunas.
- Penyederhanaan utang: algoritma greedy mencocokkan penagih terbesar dengan pengutang terbesar, jadi grup lunas dengan transfer paling sedikit.
- Scan struk: foto struk lalu model AI membacanya jadi daftar item yang dibagikan ke tiap orang. Pajak dan service dibagi proporsional, dan pembulatan memakai metode sisa terbesar sehingga setiap rupiah pas.
- Riwayat dan akuntabilitas: transaksi bisa diedit, foto nota, dan log aktivitas siapa mengubah apa.
03 ArchitectureArsitektur
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
- Every table has row-level security switched on and all direct access revoked, so the public key cannot read or write a single row.
- All reads and writes go through security-definer Postgres functions that verify the group PIN (stored as a bcrypt hash with pgcrypto) before doing anything.
- Writes also check that the acting member exists and is active, and every change lands in the activity log.
- The PIN is never committed to the repository; it is set once in the SQL editor.
- Setiap tabel mengaktifkan row-level security dan semua akses langsung dicabut, jadi kunci publik tidak bisa membaca atau menulis satu baris pun.
- Semua baca dan tulis lewat fungsi Postgres security-definer yang memverifikasi PIN grup (disimpan sebagai hash bcrypt dengan pgcrypto) sebelum melakukan apa pun.
- Penulisan juga mengecek anggota yang melakukan aksi ada dan aktif, dan setiap perubahan masuk log aktivitas.
- PIN tidak pernah masuk repositori; diatur sekali di SQL editor.
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
- "No login" can still be secure if the database itself is the gatekeeper.
- Money maths needs exact rounding rules, or the total is off by a few rupiah and someone always notices.
- Small tools for real friends get honest feedback fast.
- "Tanpa login" tetap bisa aman kalau database-nya sendiri yang jadi penjaga.
- Hitungan uang butuh aturan pembulatan yang pasti, kalau tidak totalnya meleset beberapa rupiah dan selalu ada yang sadar.
- Alat kecil untuk teman sungguhan cepat dapat masukan yang jujur.
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
