LabaBersih v2
Accounting, inventory, dan order management untuk seller online Indonesia. Dibangun dengan Elixir/Phoenix, di-deploy di Fly.io.
Apa itu LabaBersih
LabaBersih adalah platform financial management all-in-one untuk seller online Indonesia. Kalau kamu kenal A2X (jembatan Shopify/Amazon ke Xero/QuickBooks), LabaBersih mirip itu — tapi lebih lengkap karena accounting, inventory, dan order management ada dalam satu tempat.
Perbandingan dengan A2X
| Kapabilitas | A2X | LabaBersih |
|---|---|---|
| Accounting (COA, jurnal, laporan, trial balance) | Bridge ke Xero | Built-in |
| Reconciliation (per-fee matching, suspense) | Ada | Ada |
| Inventory + FEFO | Tidak ada | Ada |
| Order management + packing | Pakai Shopify | Built-in |
| RTS / Returns + inbound | Tidak ada | Ada (baik/rusak/hilang) |
| Purchasing (PO) | Tidak ada | Ada |
| Platform | Shopify, Amazon | TikTok, Shopee, Mengantar |
| Target market | Global (English) | Indonesia (Bahasa, Rupiah, WIB) |
5 Masalah yang Diselesaikan
| Masalah | Penjelasan |
|---|---|
| Laba semu | Laba kelihatan besar, tapi saat rekonsiliasi ternyata minus. Fee marketplace tersembunyi. LabaBersih pakai per-fee reconciliation — setiap fee di-match satu-satu, bukan lump sum. |
| Manual import/export | Copy-paste data antar platform setiap hari. LabaBersih punya staging pipeline + XLSX import yang langsung masuk ke sistem. |
| HPP gak akurat | Seller nebak HPP dari harga modal rata-rata. LabaBersih pakai FEFO lot tracking — HPP dihitung dari cost per unit di setiap lot, bukan tebakan. |
| Laporan keuangan berantakan | Trial Balance gak balance, COA gak konsisten. LabaBersih enforce jurnal balanced, COA immutable, dan sequential period closing. |
| RTS silent killer | Return barang gak ke-track, stok gak balik, piutang menggantung. LabaBersih track inbound RTS (baik/rusak/hilang) dengan jurnal otomatis per kondisi. |
Tech Stack
| Layer | Teknologi | Catatan |
|---|---|---|
| Bahasa | Elixir | Immutable, pattern matching, BEAM concurrency |
| Framework | Phoenix 1.8 | Context = DDD, LiveView = realtime tanpa JS |
| UI | LiveView + Tailwind v4 | Server-rendered, 1 bahasa end-to-end |
| Database | PostgreSQL | Di Fly.io, ACID, proven |
| DB Library | Ecto | Schema, changeset, query, migration |
| Auth | Guardian (JWT) + bcrypt | Custom auth, full kontrol |
| Background Jobs | Oban | Persistent job queue, retry, scheduling |
| Swoosh + Resend | Transactional email | |
| HTTP Client | Req | Untuk API TikTok, Mengantar, Facebook, dll |
| Hosting | Fly.io | Region Singapore, ~$10-15/bulan |
Arsitektur 6 Domain
Sistem dibagi menjadi 6 domain bisnis yang berkembang di 3 fase. Setiap domain punya bounded context sendiri — gak boleh circular dependency.
| Domain | Scope | Phase 1 | Phase 2 | Phase 3 |
|---|---|---|---|---|
| Master Data | Product, Warehouse, Store, Legal Entity, Supplier, Courier | Bundle + unit conv, courier mapping, reserved_stock | Multi-warehouse enforcement | — |
| Accounting | COA, Journal, Reconciliation, Closing, Tax, Reports | Daily summary journal (Oban) | Recurring expenses, aged receivables, financial health | — |
| Order Intake | XLSX import, API sync, SKU matching | XLSX auto-import, SKU importer | API staging pipeline (TikTok/Shopee/Mengantar) | Settlement XLSX |
| Fulfillment | Packing, ship, pick, handover, GRN | Keep current + reserved_stock | FO → PickList → Ship → Handover, GRN | PackingIncident QC |
| Returns | RTS, inbound, klaim, supplier return | Sudah selesai | Customer refund/replacement | — |
| Intelligence | Demand, ABC-XYZ, spike, campaign, reorder | — | — | Full implementation |
Keputusan Arsitektur Kunci
| Keputusan | Detail |
|---|---|
| Customer | Denormalized di order (customer_name, customer_phone). Tidak ada tabel terpisah. Aggregate by phone kalau butuh nanti. |
| Product | 2 tipe: simple (punya stok) dan bundle (virtual, dari komponen via BOM). Bundle stok = floor(min(komponen_stok / qty)). |
| Journal | Daily summary per toko per hari + per-order lines. Scale: 300 order/hari = 6 jurnal vs 600 (kalau per-order). |
| Fulfillment | Phase 1: keep packing session + ship_order. Phase 2: full FulfillmentOrder → PickList → Shipment → CourierHandover. |
| ID Generation | Advisory lock di PostgreSQL. Format: PS2603-00001, JE2603-00001, RTS-260331-001. Human-readable, anti race condition. |
Status Development
Yang Sudah Selesai
UI Phase 1-5 — semua list page + detail page + shared components
Refactor Step 1-14 — legal entity, COA auto-generate, per-fee rekon, tax, store FK
Deploy — lababersih.id live di Fly.io
Status Per Halaman
| Halaman | List | Create | Edit | Delete | Detail | Search | Filter | Pagination |
|---|---|---|---|---|---|---|---|---|
| Dashboard | — | — | — | — | — | — | — | — |
| Pesanan | v | v | x | x | v | v | v | v |
| Packing | v | v | — | — | x | v | v | — |
| RTS | v | v | — | — | v | v | v | v |
| Produk | v | v | v | v | v | v | x | v |
| Pembelian (PO) | v | v | — | — | v | v | v | v |
| Toko / Channel | v | v | v | v | x | v | x | — |
| Bagan Akun | v | v | v | v | x | v | x | — |
| Jurnal | v | v | — | Void | v | v | v | v |
| Rekonsiliasi | v | v | — | — | x | v | x | — |
| Laporan | v | — | — | — | — | — | — | — |
| Buku Besar | v | — | — | — | — | — | — | — |
| Settings | v | — | v | — | — | — | — | — |
Yang Sedang Dikerjakan (Session 7-10)
| Session | Scope | Status |
|---|---|---|
| G1 | Staging Service — backend functions untuk staging pipeline | SELANJUTNYA |
| G2 | Staging UI — list page, preview, bulk approve/reject | Menunggu |
| G3 | XLSX Parser — TikTok, Shopee, Mengantar (3 format) | Menunggu |
| G4 | Settlement XLSX — parser untuk rekonsiliasi | Opsional |
Prinsip Akuntansi
10 aturan fundamental yang tidak boleh dilanggar. Semua logic akuntansi di LabaBersih dibangun di atas prinsip ini.
| # | Prinsip | Penjelasan |
|---|---|---|
| 1 | Pendapatan selalu di CREDIT | Revenue accounts normal_balance = credit |
| 2 | Beban selalu di DEBIT | Expense accounts normal_balance = debit |
| 3 | Trial Balance harus balance | Total debit = total credit. Ada UI khusus untuk verifikasi. |
| 4 | Kode akun immutable | Sekali dibuat, kode akun gak boleh diubah. |
| 5 | Fee estimation bukan fakta | Saat kirim = asumsi 80-90%. Saat rekonsiliasi = fakta terungkap. |
| 6 | Per-fee reconciliation | Setiap fee di-match individual, bukan lump sum (pendekatan A2X). |
| 7 | Unknown fee → suspense | Fee tak dikenal masuk akun penampung (61-999), user kategorikan manual. |
| 8 | Rekonsiliasi validasi toko | order.store_id harus sama dengan selected store_id. Gak boleh cross-store. |
| 9 | COA auto-generate per toko | Saat buat toko → auto-create akun (piutang, kas, pendapatan, retur) di bawah platform header. |
| 10 | COA structure strict | Selalu group by platform. Piutang Shopee → leaf per toko. Aggregate di header. |
COA Architecture
Chart of Accounts dibangun dengan hierarchy 3 level. Level 1 = template (di-seed otomatis), Level 2 = per platform (auto saat platform pertama), Level 3 = per toko (auto saat toko dibuat).
Auto-generate Flow
Auto-generate dilindungi oleh advisory lock per org+platform untuk mencegah race condition saat concurrent store creation.
Legal Entity & Pajak
Seller Indonesia sering memecah bisnis ke beberapa entitas hukum (PT, CV, personal) untuk pengelolaan pajak. LabaBersih mendukung ini dari awal.
PPh Final 0.5%
Per legal entity per bulan, LabaBersih otomatis menghitung:
Threshold PKP (Rp 4.8M/tahun) juga di-track per entity — ada warning saat mendekati batas.
Journal Architecture
Jurnal menggunakan pendekatan Daily Summary + Per-Order Lines (Opsi 4) — kompromi antara granularity dan scale.
Alur 3 Tahap
| Tahap | Apa yang terjadi | Kapan |
|---|---|---|
| SHIP | Stok potong (FEFO lot consumption), HPP tercatat per order. Jurnal fee belum dicatat. | Real-time per order |
| DAILY BATCH | 1 jurnal penjualan per toko per hari (lines per order: Dr. Piutang + Dr. Fee / Cr. Revenue). 1 jurnal HPP summary. | Oban job akhir hari |
| SETTLEMENT | Per-fee matching (estimasi vs aktual). 1 jurnal adjustment per settlement. Unknown fee → suspense. | 7-14 hari kemudian |
Scale Comparison
| Order/hari | Per-order approach | Daily summary approach |
|---|---|---|
| 300 | 600 jurnal | 6 jurnal + 300 line sets |
| 6.300 | 12.600 jurnal | ~30 jurnal + 6.300 line sets |
Audit tetap granular — setiap line punya order_id, bisa di-trace ke order spesifik.
Pipeline Architecture
Status order dipecah menjadi 3 track independen — setiap track punya lifecycle sendiri dan tidak boleh dicampur.
Side Effects Per Event
| Event | Side Effects |
|---|---|
| shipped | Stock deduction (FEFO) + HPP lot consumption + audit trail. Jurnal fee di-batch nanti. |
| settled | Per-fee matching + jurnal rekonsiliasi (Dr. Kas / Cr. Piutang +/- adjustment). |
| returned | Reverse jurnal penjualan + stok kembali (kalau baik) atau jurnal kerugian (kalau rusak/hilang). |
3 Trigger Sources, 1 Shared Function
Semua sumber data melewati function yang sama. Logic hanya ada di 1 tempat — gak ada duplikasi per source.