Arsitektur Teknis Bursa Sekunder & Escrow
Arsitektur Teknis Sistem Bursa Sekunder & Escrow Kliring
Dokumen ini mendokumentasikan desain teknis perangkat lunak, relasi data, proteksi keamanan tingkat basis data (Row Level Security), serta alur eksekusi logika bisnis (Server Actions) untuk subsistem Bursa Sekunder Saham Desa dan Escrow Kliring BUMDes.
1. Diagram Alur Transaksi & Integrasi Layanan#
Memuat diagram alur...
2. Skema Basis Data & Integritas Relasional#
Subsistem Bursa Sekunder beroperasi di atas dua entitas tabel utama yang terhubung dengan tabel crowdfunding pasar perdana:
2.1. Tabel village_crowdfunding_secondary_listings
Menyimpan penawaran jual saham yang dibuka oleh investor:
| Kolom | Tipe Data | Constraint | Keterangan |
|---|---|---|---|
id | UUID | PRIMARY KEY, DEFAULT gen_random_uuid() | Identifikator unik penawaran |
investment_id | UUID | REFERENCES village_crowdfunding_investments(id) ON DELETE CASCADE | Rujukan investasi induk penjual |
seller_id | UUID | REFERENCES auth.users(id) ON DELETE RESTRICT | ID pengguna penjual |
campaign_id | UUID | REFERENCES village_crowdfunding_campaigns(id) ON DELETE CASCADE | Rujukan proyek desa yang diperdagangkan |
shares_offered | INT | NOT NULL, CHECK (shares_offered > 0) | Jumlah lembar saham yang ditawarkan |
price_per_share | DECIMAL(15,2) | NOT NULL, CHECK (price_per_share > 0) | Harga per lembar saham |
status | TEXT | DEFAULT 'active', CHECK IN ('active', 'sold', 'canceled') | Status penawaran bursa |
created_at | TIMESTAMPTZ | DEFAULT now() | Waktu listing dibuat |
updated_at | TIMESTAMPTZ | DEFAULT now() | Waktu perubahan data |
2.2. Tabel village_crowdfunding_secondary_transactions
Menyimpan mutasi pembelian, bukti transfer escrow, serta hasil audit kliring:
| Kolom | Tipe Data | Constraint | Keterangan |
|---|---|---|---|
id | UUID | PRIMARY KEY, DEFAULT gen_random_uuid() | Identifikator unik transaksi |
listing_id | UUID | REFERENCES village_crowdfunding_secondary_listings(id) ON DELETE CASCADE | Rujukan ke penawaran bursa |
buyer_id | UUID | REFERENCES auth.users(id) ON DELETE RESTRICT | ID pengguna pembeli |
shares_bought | INT | NOT NULL, CHECK (shares_bought > 0) | Jumlah lembar saham yang dibeli |
price_per_share | DECIMAL(15,2) | NOT NULL, CHECK (price_per_share > 0) | Harga per lembar yang disepakati |
total_amount | DECIMAL(15,2) | NOT NULL, CHECK (total_amount > 0) | Total dana bruto yang disetor pembeli |
admin_fee | DECIMAL(15,2) | NOT NULL, DEFAULT 0 | Fee platform BUMDes (3% dari total) |
seller_net_amount | DECIMAL(15,2) | NOT NULL, DEFAULT 0 | Hak bersih penjual (97% dari total) |
payment_proof_url | TEXT | NULLABLE | Tautan berkas bukti transfer di Supabase Storage |
status | TEXT | DEFAULT 'pending', CHECK IN ('pending', 'verified', 'rejected') | Status verifikasi kliring |
verified_by | UUID | REFERENCES auth.users(id) | ID admin yang memverifikasi |
verified_at | TIMESTAMPTZ | NULLABLE | Waktu verifikasi dieksekusi |
created_at | TIMESTAMPTZ | DEFAULT now() | Waktu transaksi diajukan |
3. Keamanan Tingkat Basis Data (Row Level Security - RLS)#
Semua tabel bursa dilindungi oleh RLS aktif:
sql-- Kebijakan Akses Listing CREATE POLICY "Public can view active listings" ON public.village_crowdfunding_secondary_listings FOR SELECT USING (status = 'active'); CREATE POLICY "Users can create listings" ON public.village_crowdfunding_secondary_listings FOR INSERT WITH CHECK (auth.uid() = seller_id); CREATE POLICY "Admin can view all listings" ON public.village_crowdfunding_secondary_listings FOR ALL USING (auth.uid() IN (SELECT id FROM profiles WHERE role IN ('super_admin', 'admin_unit', 'admin_media'))); -- Kebijakan Akses Transaksi CREATE POLICY "Users can view own purchases" ON public.village_crowdfunding_secondary_transactions FOR SELECT USING (auth.uid() = buyer_id); CREATE POLICY "Admin can manage all secondary transactions" ON public.village_crowdfunding_secondary_transactions FOR ALL USING (auth.uid() IN (SELECT id FROM profiles WHERE role IN ('super_admin', 'admin_unit', 'admin_media')));
4. Struktur Server Actions (lib/actions/secondary-market.ts)#
| Fungsi Server Action | Role Otorisasi | Deskripsi Operasi |
|---|---|---|
getActiveSecondaryListings() | Publik | Mengambil seluruh penawaran aktif dengan relasi data proyek dan foto aset. |
getSecondaryListingDetail(id) | Publik | Mengambil detail spesifik satu listing untuk halaman checkout pembelian. |
buySecondaryListing(data) | Autentikasi Warga | Memvalidasi kuota lot yang tersedia, menghitung fee 3%, dan menyimpan data pembelian. |
createSecondaryListing(data) | Autentikasi Penjual | Memverifikasi kepemilikan lembar saham dan mengunci kuota agar tidak terjual ganda. |
cancelSecondaryListing(id) | Pemilik Listing / Admin | Membatalkan penawaran dan mengembalikan kuota saham ke status aktif di portofolio. |
verifySecondaryTransaction(id) | super_admin, admin_unit | Mengeksekusi pemindahan saham, pencatatan jurnal SAK EP, dan audit log secara atomic. |
rejectSecondaryTransaction(id, reason) | super_admin, admin_unit | Menolak transaksi dan mengembalikan kuota saham ke penjual. |
getSecondaryMarketStats() | Admin | Mengagregasi 4 KPI: Volume Transaksi, Nilai Perdagangan, Escrow Pending, dan Pendapatan Fee. |
getAllSecondaryTransactions() | Admin | Mengambil riwayat seluruh mutasi kliring pasar sekunder. |
getAllSecondaryListingsAdmin() | Admin | Pengawasan pasar menyeluruh terhadap listing aktif, terjual, maupun dibatalkan. |
5. Standarisasi Integrasi Jurnal SAK EP#
Penyelesaian kliring di verifySecondaryTransaction terintegrasi secara otomatis dengan Buku Besar menggunakan akun resmi:
1-102.05: Bank BUMDes - Rekening Escrow Saham Desa (dengan fallback bertingkat ke1-102lalu1-101).4-305: Pendapatan Jasa Platform Bursa & Escrow (dengan fallback ke4-105).
Integrasi ini menjamin pembukuan akuntansi yang taat asas (compliant), tidak tumpang tindih dengan omzet unit perdagangan/ritel, serta selalu seimbang (balanced debit-kredit).