18

Spesifikasi Teknis Buku Besar

Updated: Nov 2026Oleh: SystemSistem ERP & Teknologi Inti

๐Ÿ› ๏ธ SPESIFIKASI TEKNIS SISTEM & ARSITEKTUR

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

BUMDes Bolulango โ€” Kabupaten Bone Bolango, Gorontalo 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 (approved, posted, reversed): Memperhitungkan status sah ['approved', 'posted', 'reversed'], memastikan pasangan jurnal asal (status = 'reversed') dan jurnal pembalik Storno (status = 'approved') keduanya dihitung sehingga saling mengeliminasi menjadi Rp 0,00.
  4. Pengurutan Deterministik: Saldo berjalan dipastikan stabil menggunakan pemeringkat tie-breaker idA.localeCompare(idB).
  5. Resolusi Metadata Akun Tanpa Mutasi: Apabila akun COA belum memiliki mutasi pada periode berjalan (lines.length === 0), getGeneralLedger() tetap mengembalikan objek accountInfo (code, name, account_type, normal_balance) beserta beginningBalance dan endingBalance.

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. Mode Setahun Penuh (month=0), Standarisasi URL & Drill-Down COA

  1. Mode Audit Tahunan Penuh (month=0):
  • Buku Besar mendukung audit kumulatif satu tahun penuh melalui seleksi parameter month=0 ("Semua Bulan / Setahun Penuh").
  • Kalkulasi Saldo Awal: Dihitung tepat per 1 Januari tahun terpilih (entry_date < ${selectedYear}-01-01). Untuk akun nominal (pendapatan/beban), saldo awal per 1 Januari otomatis bernilai Rp 0,00 sesuai prinsip tutup buku tahunan SAK EP.
  • Cakupan Mutasi: Mengambil seluruh transaksi jurnal dari 1 Januari hingga 31 Desember tahun fiskal berjalan dengan running balance kronologis tak terputus.
  1. Standarisasi Parameter ?unitId= & Fallback Kompatibilitas:
  • URL parameter Buku Besar diseragamkan menggunakan key ?unitId=.
  • Untuk menjaga kompatibilitas tautan lama atau bookmark pengguna, Server Component (page.tsx) dan Client Component (LedgerClient.tsx) menerapkan fallback: const targetUnitId = searchParams.unitId || searchParams.unit || 'all'.
  1. Drill-Down 1-Klik Terisolasi Unit dari Master COA:
  • Halaman Daftar Akun (COAClient.tsx) menyediakan tautan drill-down interaktif pada saldo akun.
  • Tautan otomatis membawa konteks unit kerja aktif: /dashboard/keuangan/buku-besar?accountId={acc.id}&unitId={activeUnitId}&year=${selectedYear}, mencegah kekeliruan auditor melihat saldo unit lain.
  1. Konstanta Tahun Fiskal Terpusat:
  • Pemilihan tahun fiskal memanfaatkan konstanta terpusat FISCAL_YEARS = [2023, 2024, 2025, 2026, 2027, 2028, 2029, 2030].

2.6. 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.

2.7. Benteng Integritas Database & Mesin Jurnal (Migrasi 267)

Untuk menjamin keutuhan Buku Besar dan kepatuhan SAK EP secara mutlak pada lapisan PostgreSQL maupun Server Actions:

  1. Imutabilitas Kode Akun COA (trg_guard_coa_code_immutability):
  • Trigger database BEFORE UPDATE OF code OR DELETE ON public.coa dan validasi Server Action updateAccount() menolak perubahan kode akun (code) maupun penghapusan baris COA apabila akun tersebut sudah memiliki transaksi historis di public.journal_line_items.
  • Format kode akun baru divalidasi dengan COA_CODE_FORMAT_REGEX (^[1-8]-d{3}(\.d{2})?$).
  1. Penguncian Edit Jurnal Non-Draft (update_journal_atomic & updateManualJournalEntry):
  • Hanya jurnal berstatus 'draft' yang diizinkan diedit secara langsung. Jurnal yang telah berstatus 'approved', 'posted', 'locked', atau 'reversed' ditolak pada level RPC maupun Server Action; koreksi wajib melalui mekanisme Jurnal Pembalik (Storno / Reversal).
  1. Penguncian Periode Fiskal Dua Arah (is_period_locked & check_period_lock_on_journal):
  • Menangani jurnal level Holding (target_unit_id IS NULL) dan memeriksa baik tanggal/unit asal (OLD) maupun tanggal/unit tujuan (NEW) saat operasi UPDATE, sehingga jurnal pada periode yang sudah ditutup buku tidak dapat digeser tanggalnya ke periode terbuka.
  1. Presisi Deteksi Akun Kas/Bank Likuid (isCashOrBankAccountCode):
  • Pengecekan saldo kas anti-minus dan aturan wajib 3 foto bukti kas keluar hanya menargetkan akun kas/bank likuid (1-100, 1-101, 1-102, 1-103 beserta sub-akun .xx), sehingga tidak menghasilkan false-positive pada akun Piutang, Persediaan, Pajak Dibayar Dimuka, atau CKPN (1-104 s/d 1-199).

๐Ÿ”’ 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?