18

Spesifikasi Teknis Buku Besar

Updated: Sep 2026Oleh: SystemSistem ERP & Teknologi Inti

๐Ÿ› ๏ธ SPESIFIKASI TEKNIS SISTEM & ARSITEKTUR

Modul Buku Besar & General Ledger Engine (Double-Entry Financial System)#

ERP BUMDes Mandiri Sejahtera Stack: Next.js 15 (App Router) + Supabase PostgreSQL + TypeScript (Strict) + Tailwind CSS + SafeMoney Engine


๐Ÿ›๏ธ 1. Arsitektur Komponen & Alur Data#

Sistem Buku Besar (General Ledger) merupakan inti pembukuan berpasangan (double-entry bookkeeping) yang mengonsolidasikan seluruh transaksi dari 20 unit usaha BUMDes secara real-time sesuai dengan Standar Akuntansi Keuangan Entitas Privat (SAK EP).

Memuat diagram alur...

โš™๏ธ 2. Core Engine Specifications#

2.1. Double-Entry Posting & Normal Balance Engine

Setiap akun perkiraan memiliki karakteristik saldo normal (normal_balance: 'debit' atau 'credit'). Sistem menghitung posisi saldo berjalan (running balance) secara sekuensial berdasarkan urutan kronologis entry_date ASC:

Running Balance_i = Running Balance_{i-1} + Delta_i

Di mana:

  • Akun Saldo Normal Debit (Aset, Beban, HPP): Delta_i = Debit_i - Credit_i
  • Akun Saldo Normal Kredit (Kewajiban, Ekuitas, Pendapatan): Delta_i = Credit_i - Debit_i

2.2. Kepatuhan SAK EP: Isolasi Saldo Awal Akun Nominal vs Akun Riil

Sesuai Standar Akuntansi Keuangan Entitas Privat (SAK EP) dan prinsip tutup buku tahunan:

  1. Akun Nominal (Pendapatan & Beban / Akun Kepala 4, 5, 6, 7, 8, 9):
  • Saldo akun nominal ditutup ke Ikhtisar Laba Rugi / Saldo Laba pada setiap akhir tahun buku.
  • Saldo awal (beginning balance) akun nominal di Buku Besar dibatasi hanya sejak 1 Januari tahun fiskal berjalan (Year-to-Date / YTD): entry_date >= ${selectedYear}-01-01 dan entry_date < startDate.
  • Transaksi pendapatan dan beban dari tahun-tahun sebelumnya tidak diperkenankan bocor ke saldo awal tahun berjalan.
  1. Akun Riil / Neraca (Aset, Kewajiban, Ekuitas / Akun Kepala 1, 2, 3):
  • Saldo akun riil bersifat kumulatif sepanjang masa (all-time cumulative), dihitung dari awal mula pencatatan transaksi BUMDes (entry_date < startDate).

2.3. Data Pump Streaming Pagination (Anti-Truncation Engine)

Secara default, Supabase/PostgREST menerapkan batas query sebesar 1.000 baris per request. Pada buku besar dengan volume transaksi historis tinggi, query biasa tanpa paginasi akan memotong kalkulasi saldo awal.

Modul ini mengimplementasikan pola Data Pump Pagination pada query Saldo Awal dan Mutasi Periode dengan pengurutan deterministik .order('id', { ascending: true }):

typescript
// Cuplikan Data Pump Pagination pada getGeneralLedger()
let begFrom = 0
const begStep = 1000
let begHasMore = true

while (begHasMore) {
 const { data: chunk } = await begQuery.range(begFrom, begFrom + begStep - 1)
 if (!chunk || chunk.length === 0) {
 begHasMore = false
 } else {
 chunk.forEach((line: any) => {
 const debit = safeMoney(line.debit)
 const credit = safeMoney(line.credit)
 if (isNormalDebit) {
 beginningBalance = safeAdd(beginningBalance, safeSubtract(debit, credit))
 } else {
 beginningBalance = safeAdd(beginningBalance, safeSubtract(credit, debit))
 }
 })
 if (chunk.length < begStep) begHasMore = false
 else begFrom += begStep
 }
}

Karakteristik Kunci:

  1. Memory-Efficient: Kalkulasi saldo berjalan dilakukan per chunk, tanpa memuat seluruh baris historis ke dalam memori Node.js sekaligus.
  2. Infinite History: Mampu mengagregasi ratusan ribu mutasi saldo awal tanpa batas kuota PostgREST.
  3. Harmonisasi Status Jurnal: Memperhitungkan status sah ['approved', 'posted'], memastikan jurnal storno dan transaksi modul otomatis tercatat sempurna.
  4. Pengurutan Deterministik: Saldo berjalan dipastikan stabil menggunakan pemeringkat tie-breaker idA.localeCompare(idB).

2.4. SafeMoney Arithmetic Standard (Anti-IEEE 754 Floating Drift)

Operasi floating point bawaan JavaScript (0.1 + 0.2 = 0.30000000000000004) dapat menyebabkan akumulasi selisih sen (cents drift) pada buku besar dan laporan keuangan.

Seluruh perhitungan finansial distandardisasi menggunakan pustaka lib/accounting.ts:

FungsiRumus Aritmatika PresisiTujuan
safeMoney(val)Math.round(Number(val) * 100) / 100Sanitasi input dan pembulatan ke 2 desimal
safeAdd(a, b)(Math.round(a * 100) + Math.round(b * 100)) / 100Penjumlahan berbasis integer cent
safeSubtract(a, b)(Math.round(a * 100) - Math.round(b * 100)) / 100Pengurangan berbasis integer cent
safeSum(array)array.reduce(...) / 100Agregasi total debit/kredit tanpa residu floating point

2.5. Prioritas Narasi Keterangan Baris Jurnal

Rincian mutasi buku besar mengutamakan keterangan spesifik baris transaksi (journal_line_items.description), contoh: "Beli 5 Rim Kertas A4 Sidu", sebelum melakukan fallback ke deskripsi umum voucher header (journal_entries.description), contoh: "Operasional Kantor Unit Toko".


2.6. Server-Side Prefetching (SSR) & Proteksi Audit

  1. Zero Flash Loading Flicker: Halaman /dashboard/keuangan/buku-besar melakukan prefetching data mutasi dan saldo awal di server (page.tsx), sehingga tampilan tabel langsung instan ter-render saat request pertama.
  2. Badge Visual Audit: Nomor referensi transaksi dilengkapi penanda AUTO (subsistem POS, Pinjaman USP, Billing Air) atau POSTED.
  3. Read-Only Navigation: Tautan nomor bukti voucher otomatis diarahkan ke filter pencarian jurnal guna memproteksi integritas transaksi double-entry antar subsistem dari perubahan manual yang tidak sah.

๐Ÿ”’ 3. Keamanan & Multi-Unit RBAC#

3.1. Role Guard & Master CoA Filtering

Endpoint Server Actions dilindungi secara deklaratif dengan isolasi akun aktif dan unit bisnis:

typescript
export async function getAccountsList(unitId?: string | null): Promise<AccountOption[]> {
 await requireRoleGuard()
 const supabase = createAdminClient()
 let query = supabase
 .from('coa')
 .select('id, code, name, unit_id, is_active')
 .eq('is_active', true)

 if (unitId && unitId !== 'all') {
 query = query.or(`unit_id.is.null,unit_id.eq.${unitId}`)
 }

 return (await query.order('code', { ascending: true })).data || []
}

3.2. Resolusi Hierarki Unit Bisnis

Akses data transaksi dibatasi berdasarkan hierarki unit:

  • Pengguna Konsolidasi (super_admin, direktur, bendahara, sekretaris, pengawas, auditor, admin_keuangan): Dapat melihat seluruh unit (unitId = 'all') atau memfilter per unit tertentu.
  • Pengguna Unit Terbatas (manajer_unit, kepala_unit, admin_unit, kasir, admin_gudang, kolektor_usp, staf_unit): Terisolasi mutlak ke unit kerja mereka (assigned_unit_id). Opsi konsolidasi seluruh unit dinonaktifkan.

๐Ÿ“Š 4. Spesifikasi Ekspor (PDF, Excel & CSV)#

Format ekspor buku besar diselaraskan 100% antara tampilan layar, PDF, CSV, dan Excel:

  1. Header Metadata:
  • Judul Dokumen: BUKU BESAR
  • Periode: Periode: [Nama Bulan] [Tahun] (contoh: Periode: September 2026)
  • Identitas Akun: Akun: [Kode Akun] - [Nama Akun] (contoh: Akun: 1-101 - Kas Operasional)
  1. Urutan Kolom Baku:
  • Kolom: Tanggal, No. Ref, Keterangan, Debit, Kredit, Saldo
  1. Baris Saldo Awal:
  • Format: ['-', '-', 'Saldo Awal Periode', 0, 0, beginningBalance]
  1. Baris Total Akhir:
  • Format: ['TOTAL DEBIT / KREDIT', '', '', totalDebit, totalCredit, endingBalance]
  1. Sanitasi Nama File:
  • Menggunakan sanitasi regex /[^a-zA-Z0-9_-]/g untuk menghindari karakter ilegal pada sistem operasi: Buku-Besar-[Nama_Akun]-[Periode].xlsx / .pdf

๐Ÿงช 5. Matriks Pengujian Otomatis#

Verifikasi modul buku besar dijamin oleh 14 unit test pada __tests__/actions/general_ledger_remediation.test.ts:

ID TesFokus PengujianKriteria Lolos
GL-F01Role Guard getAccountsListMenolak akses tanpa otorisasi (throws Forbidden)
GL-F01RBAC Authorized getAccountsListMengembalikan daftar akun saat otorisasi valid
GL-F02Data Pump PaginationMengambil mutasi bertahap (chunk 1.000) dan menghitung saldo awal tepat
GL-F03Excel Export Metadata & Urutan KolomHeader periode, akun, dan kolom [Tanggal, No. Ref, Keterangan, Debit, Kredit, Saldo]
GL-F05Floating Point PrecisionMenghitung akumulasi desimal presisi tinggi tanpa drift IEEE 754
GL-F06SAK EP Nominal Account YTDSaldo awal akun pendapatan/beban dibatasi mulai 1 Jan tahun berjalan
GL-F06SAK EP Real Account All-TimeSaldo awal akun neraca (aset/kewajiban/ekuitas) berjalan kumulatif
GL-F08Isolasi RBAC Unit Non-HoldingMengunci role operasional (kasir, admin_gudang, manajer_unit) ke unitnya
GL-F08Fleksibilitas RBAC HoldingMengizinkan role holding (super_admin, direktur, bendahara) konsolidasi
GL-F09Filter Master CoA AktifMenyaring akun dengan is_active: true
GL-F09Isolasi CoA Spesifik UnitMenyaring akun global + akun milik unit usaha aktif
GL-F10Prioritas Narasi Baris JurnalMengutamakan line.description di atas journal_entries.description
GL-F11Audit Trail Flags & ProteksiMendeteksi reference_type, status, dan is_automated: true untuk subsistem
GL-F11Standardisasi PDF ExportMemastikan tabel PDF menggunakan kolom [Tanggal, No. Ref, Keterangan, Debit, Kredit, Saldo]

Apakah panduan ini membantu Anda?