Pola Frontend
Struktur folder per fitur
Section titled “Struktur folder per fitur”Tiap domain bisnis punya folder sendiri di src/features/<domain>/
(±64 folder — lihat daftar lengkap di src/features). Konvensi penamaan
berkas yang konsisten di hampir semua folder:
supabase-<domain>.ts— fungsi akses data ke Supabase untuk domain itu (query, RPC call, mapping baris ke bentuk yang dipakai UI).<domain>-hooks.ts— React hook (biasanya berbasis React Query) yang membungkus fungsi di atas untuk dipakai komponen halaman.
Halaman di src/pages/<route>/page.tsx meng-import hook dari
src/features/<domain>/, bukan memanggil Supabase langsung — menjaga
logika data tetap di satu tempat per domain.
Pemilihan backend & feature flag kanonik
Section titled “Pemilihan backend & feature flag kanonik”isSupabaseBackend/selectBackend()(src/lib/backend-provider.ts) menentukan backend aktif di level build — lihat Gambaran Arsitektur.VITE_SUPABASE_CANONICAL_*_READS(satu flag per domain, mis.VITE_SUPABASE_CANONICAL_CONFIG_READS) mengaktifkan pembacaan dari tabel kanonik alih-alihlegacy_documents, hanya setelah tabel kanonik untuk domain itu dipastikan siap (jumlah baris sama) — lihat Migrasi & Rollout dan Skema Data & Tabel Kanonik.
Pola ini membuat setiap domain bisa pindah ke tabel kanonik secara independen, tanpa menunggu domain lain selesai, dan bisa dibatalkan sendiri lewat env var tanpa deploy ulang kode aplikasi.
Routing: lazy-loaded pages
Section titled “Routing: lazy-loaded pages”Hampir semua komponen halaman di src/App.tsx di-lazy-load dengan
React.lazy() per rute, supaya bundle awal tetap kecil meski jumlah
halaman sangat banyak. Rute publik (portal, katalog publik, display,
kiosk) sengaja dirender di luar provider aplikasi utama (lihat
Gambaran Arsitektur) supaya tidak memuat context
yang tidak relevan untuk pengunjung tanpa login.
Menampilkan error ke pengguna dengan aman
Section titled “Menampilkan error ke pengguna dengan aman”Error mentah dari Supabase/Postgres (kode PGRST*, nama relasi, detail
RLS) tidak langsung ditampilkan ke pengguna. Helper
getUserFacingError() (src/lib/user-facing-error.ts) menyaring pesan
error sebelum ditampilkan lewat toast:
- Pesan validasi bisnis yang memang ditulis untuk pengguna (mis. “Stok bahan tidak mencukupi”) diteruskan apa adanya.
- Pesan yang mengandung istilah teknis (PGRST, postgres, supabase, convex, “relation … does not exist”, dll.) diganti pesan generik: “Layanan sedang tidak dapat dihubungi. Coba lagi beberapa saat.”
- Pesan terkait hak akses (permission denied, RLS, forbidden) diganti: “Anda tidak memiliki akses untuk melakukan tindakan ini.”
- Pesan terkait sesi (JWT/token/session tidak valid) diganti: “Sesi login tidak lagi valid. Silakan masuk kembali.”
Pola ini mencegah detail implementasi database bocor ke pengguna akhir lewat pesan error, sekaligus tetap menampilkan pesan validasi bisnis yang memang berguna bagi pengguna.
Sumber: src/lib/backend-provider.ts, src/lib/user-facing-error.ts,
src/lib/user-facing-error.test.ts, src/features/hr/supabase-hr.ts,
src/App.tsx.