Banyak Kantong Tabungan & Menabung Bersama
Memisahkan uang ke berbagai pos tabungan seperti dana darurat, liburan, atau tabungan bersama pasangan dan keluarga yang bisa dipantau bersama lewat undangan email.
Memisahkan uang ke berbagai pos tabungan seperti dana darurat, liburan, atau tabungan bersama pasangan dan keluarga yang bisa dipantau bersama lewat undangan email.
Tantangan & Kebutuhan Pengguna
Dalam pengelolaan keuangan nyata, seseorang membutuhkan pemisahan ruang antara dana harian pribadi, tabungan investasi jangka panjang, dan tabungan bersama pasangan atau keluarga. Jika skema database mengikat transaksi hanya pada satu `user_id`, maka kolaborasi multi-pengguna pada satu tabungan tertentu menjadi mustahil tanpa mengekspos seluruh transaksi pribadi lainnya.
Melepaskan kepemilikan tunggal dari tabel tabungan dan menggantinya dengan tabel kontrol akses mengubah aplikasi personal menjadi platform kolaborasi multi-tenant.
Solusi & Cara Kerja
Entitas kantong tabungan (`bank`) dirancang independen tanpa kolom pemilik tunggal. Relasi antara pengguna dan kantong tabungan dijembatani oleh tabel `allowedaccess (uuiduser, uuidbank, role)` yang membedakan peran `owner` dan `member`. Pemilik kantong dapat mengirim undangan kolaborasi ke pengguna lain melalui tabel `bankinvitation`. Di sisi klien, hook `useInvitations` melakukan *polling* ringan setiap 15 detik menggunakan SWR sehingga undangan yang masuk langsung tampil dan dapat disetujui atau ditolak tanpa memuat ulang halaman.
Berikut adalah query agregasi tunggal pada `src/app/api/saving/route.ts` yang menggabungkan daftar hak akses kantong tabungan dengan empat *derived table* sekaligus untuk menghitung total arus kas sepanjang waktu dan bulan berjalan:
Detail & Hal yang Diperhatikan
- Validasi Berlapis Pengiriman Undangan: Sebelum menyisipkan baris ke `bankinvitation`, server memverifikasi bahwa pengirim adalah `owner`, email tujuan terdaftar, bukan mengundang diri sendiri, belum menjadi anggota aktif, dan tidak ada undangan *pending* yang menggantung.
- Idempotensi Penerimaan Undangan: Saat undangan diterima, query menggunakan `INSERT INTO allowedaccess ... ON DUPLICATE KEY UPDATE role='member'` untuk mencegah duplikasi baris jika tombol Terima tertekan dua kali.
- Proteksi Penghapusan Diri Sendiri: Endpoint manajemen anggota menolak request jika `memberUuid === user.uuid` serta membatasi aksi hapus/ubah kantong hanya untuk peran `owner`.
Kantong yang aktif dipilih pengguna disimpan ke dalam React Context (BankCtx) dan disinkronkan dengan localStorage serta query parameter URL (?bank=...) agar perpindahan antar halaman tetap mempertahankan konteks kantong yang sedang dibuka.