Skema Data & Tabel Kanonik
Skema Postgres Catera tumbuh dari proses migrasi data Convex → Supabase yang dilakukan bertahap per domain, bukan “big bang” satu kali. Ini menghasilkan dua lapis tabel yang hidup berdampingan selama masa transisi.
1. Landing zone JSONB — legacy_documents
Section titled “1. Landing zone JSONB — legacy_documents”Saat sebuah domain data belum dimigrasikan ke tabel kanonik, baris data
disimpan generik di public.legacy_documents dengan kolom table_name
(nama koleksi asal) dan document (JSONB berisi field aslinya). Pola ini
memungkinkan aplikasi tetap berjalan terhadap Supabase sejak awal cutover,
sebelum setiap domain satu per satu mendapat tabel kanoniknya sendiri.
2. Tabel kanonik per domain
Section titled “2. Tabel kanonik per domain”Domain yang sudah “naik kelas” mendapat tabel bertipe sendiri di public
(mis. employees, attendance_records), dengan kolom asli JSONB tetap
disimpan di kolom raw_document untuk kompatibilitas mundur selama masa
transisi, didampingi fungsi project_<domain>() yang mem-parse dokumen
JSONB legacy menjadi baris kanonik tersebut. Pola ini terlihat konsisten di
seluruh migrasi domain kanonik, misalnya project_employee() dan
project_attendance_record() di
supabase/migrations/20261011120000_employees_attendance_canonical.sql.
Domain yang sudah punya migrasi kanonik pada repo ini antara lain (lihat nama berkas): pelanggan (write-path projection), master produk/inventori, sales-config/zona/promo, komplain & food-waste, karyawan & absensi, langganan (subscriptions), invoice, konfigurasi CCTV, payroll inti, THR, pinjaman karyawan, dan faktur pajak.
3. Pola baca dual-mode (feature flag)
Section titled “3. Pola baca dual-mode (feature flag)”Kode frontend tidak langsung berasumsi tabel kanonik sudah siap. Helper
seperti readHrTable() (src/features/hr/supabase-hr.ts) membaca tabel
kanonik hanya jika:
- Flag
VITE_SUPABASE_CANONICAL_CONFIG_READS=truediaktifkan, dan - Jumlah baris di tabel legacy dan kanonik untuk domain itu sudah sama
(dicek lewat
countquery, di-cache sementara per domain).
Jika salah satu syarat tidak terpenuhi, kode otomatis jatuh ke pembacaan
legacy_documents. Pola ini membuat rollout per-domain bisa dibatalkan
(toggle flag) tanpa deploy ulang kode, dan mencegah UI menampilkan data
kosong saat tabel kanonik baru separuh terisi.
4. Role & identitas
Section titled “4. Role & identitas”public.profiles (lihat Model Keamanan) adalah
tabel identitas inti yang terhubung 1:1 ke auth.users, menyimpan role
dan status yang dipakai hampir semua fungsi RLS lain di database.
5. Skema landing migrasi (sekali pakai, bukan tabel operasional)
Section titled “5. Skema landing migrasi (sekali pakai, bukan tabel operasional)”Schema terpisah migration (migration.runs, migration.convex_documents,
migration.id_map, migration.storage_map) dipakai untuk mencatat proses
impor data Convex → Supabase itu sendiri (bukan data operasional aplikasi)
dan ditutup aksesnya dari public/anon/authenticated.
Sumber: supabase/migrations/0001_migration_control.sql,
supabase/migrations/0002_identity_and_rls.sql,
supabase/migrations/20261011120000_employees_attendance_canonical.sql,
src/features/hr/supabase-hr.ts.