BMP

Business Management Platform

Project Blueprint & Design Documentation

Dokumen Gabungan — v1.0

Daftar Isi

Daftar Isi 2

Pendahuluan 4

Peta Keseluruhan & Status 4

Dua “Architecture” yang Berbeda Level 4

Urutan Pengerjaan 4

0. Latar Belakang — Analisis 12 ERP Open Source 5

Chapter 1: Design Foundation 6

1.1 Theme 6

1.2 Color System 6

1.3 Typography 8

1.4 Iconography 8

1.5 Contoh Penerapan 10

Contoh 1 — Home Dashboard 10

Contoh 2 — List View 10

Chapter 2: Interaction Structure 11

2.1 Landing Page & Layout 11

2.2 List / Table View 12

2.3 Navigation & Information Structure 13

Global Navigation vs Local Navigation 13

Pola Sidebar 14

Lima Hal Spesifik Navigasi ERP/BMP 14

2.4 Form & Detail View 16

Conditional Field vs Progressive Disclosure 18

2.5 Search & Command Palette 18

2.6 Notification & Approval Workflow 20

Pola Fork-Join Checker Lintas Divisi 20

2.7 Personalization & Account Model 22

Model Akun, bukan Persona Gabungan 22

Admin vs Business Home 23

2.8 Consistency Patterns 24

2.9 Responsive & Usage Context 25

Catatan: Konvensi Bahasa UI Sistem 26

Chapter 3: Architecture 26

0. Architecture Invariants 26

1. Fondasi: Phoenix — Ash — Event-driven 27

2. Async & Data Processing 27

3. Data Layer — Full SQLite 28

4. Audit, Retensi & Kepatuhan (final) 28

5. Ledger Khusus 28

6. Cache & State 29

7. Observability, I18n, Storage 29

8. Testing & Static Analysis 29

9. Deployment Profiles 29

10. Hierarki Pemilihan Dependency (kebijakan resmi) 30

Addendum: Mekanisme Sync-Agent — Penjelasan Detail 30

Chapter 4: Development Conventions 35

Chapter 5: System UI/UX 36

Chapter 6: Report & Workflow 37

Chapter 7: Modul ERP Core 38

Chapter 8: Modul Optional/Community 39

Pendahuluan

Dokumen ini adalah blueprint proyek BMP (Business Management Platform) secara utuh — menggabungkan seluruh keputusan desain dan arsitektur yang telah disepakati ke dalam satu struktur dokumentasi resmi, menggantikan catatan sesi yang sebelumnya tersebar di beberapa file terpisah.

Peta Keseluruhan & Status

Seluruh cakupan proyek dipetakan ke dalam empat kelompok besar berikut, masing-masing dengan status pengerjaan saat dokumen ini disusun:

Cluster Item Status
UI Design Foundation (Theme, Color System, Typography, Iconography) Selesai — Chapter 1
UI Interaction Structure (Layout, Nav, Dashboard, Components, Workflow) Selesai — Chapter 2
UI System UI/UX (Module toggle, Permission, Role/Account, Workspace, Settings) Belum — Chapter 5
Architecture Phoenix, Ash, event-driven, sync-agent, deployment profile Selesai — Chapter 3
Development Coding Standard, Naming, Folder Convention, Generator, Testing, CI/CD, Extension SDK, Migration, Versioning Belum — Chapter 4
Modul ERP Administration, System & Utilities, Accounting, Inventory, Purchase, Sales, Manufacturing, HR, Asset Mgmt, Quality, Project Mgmt (Core) Belum — Chapter 7
Modul ERP POS, E-commerce, Website, Helpdesk (Official); Fleet, Rental, Healthcare, Agriculture, Hospitality, dll. (Community, togglable) Belum — Chapter 8
Umum Report & Workflow lintas modul Belum — Chapter 6

Dua “Architecture” yang Berbeda Level

Penting dipisahkan agar tidak rancu: “System UI/UX” (Chapter 5) dan “Architecture” (Chapter 3) sama-sama menyentuh topik Module/Permission/Role/Workspace, tapi dari sudut pandang berbeda.

Chapter Sudut pandang Contoh
5. System UI/UX Bagaimana konsep ini terlihat & terasa oleh user/admin Halaman kelola Role, toggle modul di UI, tampilan Workspace switcher
3. Architecture Bagaimana itu benar-benar berjalan di level infrastruktur Ash.Policy.Authorizer menegakkan Permission, Reactor menjalankan Workflow

Urutan Pengerjaan

Urutan bab dalam dokumen ini disusun berdasarkan ketergantungan — apa yang harus mapan dulu sebelum yang lain bisa dibangun konsisten di atasnya, bukan sekadar urutan sembarang:

  1. Design Foundation — token visual (warna, tipografi, ikonografi) yang jadi dasar semua komponen bersama; ditunda akan berarti banyak yang harus diubah retroaktif.
  2. Interaction Structure — pola perilaku layar (layout, navigasi, list, form, report, workflow) yang dibangun di atas Design Foundation.
  3. Architecture — pondasi teknis (Phoenix, Ash, event-driven, sync-agent, deployment) sebelum konvensi kode ditulis.
  4. Development Conventions — bergantung pada keputusan Architecture di atas.
  5. System UI/UX — formalisasi Module/Permission/Role/Workspace/Settings sebagai spesifikasi resmi, karena modul-modul di bawah akan mengacu ke sini.
  6. Report & Workflow — struktur lintas modul yang dipakai oleh seluruh Modul ERP.
  7. Modul ERP Core — memakai seluruh fondasi di atas.
  8. Modul Optional/Community — paling akhir, dapat didorong ke kontributor komunitas.

0. Latar Belakang — Analisis 12 ERP Open Source

Sebelum menyusun prinsip desain BMP, dilakukan analisis terhadap 12 aplikasi ERP open source sebagai pembanding: ERPNext, Dolibarr, Apache OFBiz, metasfresh, iDempiere, Tryton, OpenPetra, Axelor, inoERP, LedgerSMB, BlueSeer, dan WebERP.

Kesimpulan utama: hampir semua ERP tersebut membangun UI dengan mengikuti struktur backend (skema database, metadata resource), bukan mengikuti alur kerja/pengalaman user. Pola kesalahan yang berulang:

Prinsip inti yang menjadi fondasi seluruh dokumen ini:

UI yang nyaman selalu menjawab “apa yang sedang ingin dicapai user saat ini” — bukan “bagaimana data ini disimpan di backend”.

BMP (Business Management Platform) secara sadar dirancang untuk UMKM yang sedang berkembang menuju skala menengah — bukan enterprise. Konsekuensinya: default harus cukup sederhana untuk dipakai tanpa training/konsultan, approval bertingkat bersifat opsional (bukan default wajib), dan satu orang boleh memegang lebih dari satu akun fungsi sesuai kebutuhan bisnis kecil yang masih hemat sumber daya.

Chapter 1: Design Foundation

Design Foundation adalah bahasa visual dasar yang dipakai seluruh komponen UI (button, badge, toast, card). Bagian ini didahulukan sebelum Interaction Structure karena semua komponen bersama yang dirancang di Bab 2 bergantung pada token yang ditetapkan di sini — makin lama ditunda, makin banyak yang harus diubah retroaktif.

1.1 Theme

Arah visual BMP: profesional tapi tidak mengintimidasi — berbeda dari kesan “software korporat kaku” ala ERP enterprise yang membuat pemilik UMKM merasa perlu training dulu sebelum berani memakainya.

1.2 Color System

Token warna bersifat semantik (berdasarkan fungsi), bukan sekadar warna brand. Satu token = satu makna, berlaku konsisten di seluruh komponen.

Token Fungsi Nilai
--color-accent Aksi utama, elemen aktif/terpilih #0D9488 (teal)
--color-accent-bg Latar lembut untuk elemen accent #ECFDF9
--color-success / --bg-success Status positif (disetujui, berhasil) #15803D / #F0FDF4
--color-warning / --bg-warning Butuh perhatian, belum kritis #B45309 / #FFFBEB
--color-danger / --bg-danger Kritis, destruktif, overdue #B91C1C / #FEF2F2
--text-primary Teks utama #18181B
--text-secondary Teks pendukung #52525B
--text-muted Teks tersier / placeholder #8B8B93
--border Garis pemisah standar #E4E4E7
--surface-1 / --surface-2 Latar sekunder (card) / latar utama #F7F7F8 / #FFFFFF

Teal dipilih sebagai warna accent (bukan biru/ungu seperti kebanyakan SaaS) supaya BMP memiliki identitas visual sendiri yang tidak generik, dengan asosiasi tenang dan terpercaya tanpa terasa dingin seperti biru korporat murni.

1.3 Typography

Dua kebutuhan khusus aplikasi bertipe ERP/BMP yang sering diabaikan desain UI generik:

Font terpilih: Inter — open source, mendukung tabular numerals bawaan, teruji untuk UI aplikasi data-berat.

Karena aplikasi berjalan offline/LAN-only, font wajib di-bundle lokal (file .woff2 di priv/static/fonts/), tidak boleh bergantung pada Google Fonts CDN.

Skala Ukuran Pemakaian
text-xs 11px Caption, label kolom tabel
text-sm 13px Body dasar (list, form)
text-base 14px Teks utama form / paragraf
text-lg 16px Judul dokumen / card
text-xl 20px Judul halaman / section

Berat font dibatasi 2 saja: Regular (400) untuk body, Medium (500) untuk judul/emphasis — mencegah developer bebas memakai Bold/Semibold/Black secara tidak konsisten.

1.4 Iconography

Satu sumber ikon untuk seluruh aplikasi, bukan campuran beberapa icon set.

— widget: "design_foundation_styleguide"_
Lembar acuan visual: swatch warna, contoh type scale dengan tabular numerals, dan sampel ikon dua ukuran._

1.5 Contoh Penerapan

Dua contoh berikut menunjukkan token di atas diterapkan pada tampilan halaman web yang mendekati bentuk final (bukan wireframe kotak-kotak).

Contoh 1 — Home Dashboard

— widget: "bmp_home_high_fidelity"_
Halaman Home dengan sidebar ikon, search bar, feed My Attention, dan 3 KPI card dengan tabular numerals._

Contoh 2 — List View

— widget: "bmp_list_view_high_fidelity"_
Tabel Sales Order dengan tab saved-view, badge status berwarna, dan kolom nilai rata kanan tabular numerals._

Chapter 2: Interaction Structure

Bagian ini mendefinisikan bagaimana tiap jenis layar disusun secara konsisten di seluruh modul BMP — mengikuti prinsip inti Bab 0: alur kerja user, bukan struktur backend.

2.1 Landing Page & Layout

Masalah pada ERP pembanding: landing page berupa “app launcher” (grid ikon besar) menyisakan ruang kosong besar saat modul sedikit; semua ikon modul diberi bobot visual sama padahal frekuensi pemakaian berbeda jauh; tidak menjawab “apa yang perlu dikerjakan hari ini”.

Prinsip pengorganisasian:

— widget: "erp_home_consolidated_revision"_
Hasil konsolidasi landing page: feed My Attention, KPI ringkas, dan dokumen terakhir — dibanding versi awal yang terlalu ramai._

2.2 List / Table View

Masalah pada ERP pembanding: kolom mengikuti urutan tabel database; status hanya teks polos tanpa sinyal visual; filter tersembunyi di panel terpisah; bulk action sulit ditemukan.

Prinsip pengorganisasian:

— widget: "bmp_list_view_high_fidelity"_
List view Sales Order versi high-fidelity — dapat dipakai ulang sebagai referensi visual bagian ini._

2.3 Navigation & Information Structure

Koreksi konsep penting: navigasi bukan flowchart (satu jalur linear). Model yang tepat adalah peta kedalaman dengan panah dua arah di tiap level, ditambah jalur pintas (search) yang dapat melompati level tengah.

— widget: "navigasi_bukan_flowchart_linear"_
Diagram lima level kedalaman navigasi (Home → Workspace → List → Detail → Sub-record) dengan panah dua arah dan jalur pintas via search._

Global Navigation vs Local Navigation

Global Navigation Local Navigation
Definisi Tidak berubah di manapun user berada Berubah total tergantung level/konteks saat ini
Isi App switcher, search universal, notifikasi, identitas akun, shortcut Home Breadcrumb, tab dalam record, related-list/link
Aturan Isi minim Maksimal 5–6 tab; breadcrumb maksimal 3–4 level

— widget: "global_vs_local_navigation"_
Kombinasi rak ikon (global nav) yang identik di semua halaman dengan breadcrumb + tab (local nav) yang berubah sesuai konteks._

Pola Sidebar

Tree bersarang (expand/collapse permanen) tidak disarankan karena mencerminkan struktur database, bukan frekuensi pemakaian. Sidebar flat (1 level) adalah baseline yang benar; flyout saat hover dipakai untuk shortcut cepat tertentu tanpa mengubah bentuk sidebar utama.

— widget: "sidebar_flyout_vs_tree"_
Perbandingan sidebar flat dengan flyout munculan saat hover, tanpa mengubah tinggi sidebar utama._

Lima Hal Spesifik Navigasi ERP/BMP

— widget: "document_trail_navigation"_
Rantai dokumen Quotation → Sales Order → Delivery Note → Invoice → Payment dengan status kini disorot._

— widget: "settings_hub_discoverable"_
Settings Hub sebagai jalur discovery untuk config/master data, dikelompokkan per kategori fungsional._

widget: "erp_full_page_navigation_concept"_
Contoh satu halaman penuh yang menggabungkan global nav, local nav, status-aware action bar, dan document trail sekaligus._

2.4 Form & Detail View

Masalah pada ERP pembanding: field diurutkan sesuai skema tabel; tabel item/baris sulit dinavigasi keyboard; validasi baru muncul setelah submit; field read-only tidak dibedakan visual.

Prinsip pengorganisasian:

— widget: "form_detail_view_organized"_
Form Sales Order tersusun Who → What → When/How dengan validasi inline dan field read-only bertanda visual._

— widget: "form_advanced_section_expanded"_
Bagian Advanced Details dalam kondisi terbuka, termasuk contoh conditional field (metode pembayaran)._

Conditional Field vs Progressive Disclosure

Progressive Disclosure Conditional Field
Siapa kontrol User (klik untuk buka) Sistem (otomatis berdasar nilai field lain)
Kapan muncul Kapan saja user mau lihat Hanya saat kondisi tertentu terpenuhi
Tujuan Menyembunyikan yang jarang dipakai Menyembunyikan yang tidak relevan di konteks itu

Aturan desain conditional field: jangan bikin layout “lompat” kasar; validasi harus ikut kondisi aktif (field tersembunyi tidak boleh dianggap wajib); data lama tidak boleh hilang diam-diam saat kondisi berubah; jangan berantai lebih dari 2 tingkat.

2.5 Search & Command Palette

Masalah pada ERP pembanding: search tercecer per-modul; hasil tidak dikelompokkan; tidak ada “command” (search hanya bisa navigasi); kotak kosong tidak menawarkan apa-apa.

Prinsip pengorganisasian: kelompokkan hasil berdasarkan jenis (Action → Document → Report → Setting); toleran typo & bisa cari lewat kode/nomor dokumen; prefix untuk mempersempit cepat (# report, > action); sajikan status di tiap hasil; kotak kosong menampilkan Recent Activity & Quick Actions sebelum user mengetik.

— widget: "command_palette_organized"_
Command palette dengan hasil terkelompok: Action, Document (dengan badge status), dan Report._

2.6 Notification & Approval Workflow

Masalah pada ERP pembanding: sebagian besar tidak punya sistem notifikasi terpadu; notifikasi terpecah ke banyak sumber; harus buka dokumen penuh untuk approve hal sederhana; tidak ada progres approval bertingkat yang terlihat; approval yang didiamkan lama diperlakukan sama seperti yang baru masuk.

Terminologi resmi alur approval BMP: Submitter → Checker (paralel, lintas divisi) → Approver (final).

— widget: "notification_approval_flow"_
Feed notifikasi terpadu (item actionable vs info-only) dan contoh progres approval bertingkat linear (stepper 2 tingkat)._

Pola Fork-Join Checker Lintas Divisi

Untuk kasus seperti Purchase Order yang membutuhkan verifikasi dari lebih dari satu divisi (contoh: Manager Production & Manager Accounting) sebelum sampai ke Approver akhir (Direktur/GM), alur tidak lagi linear melainkan fork-join:

— widget: "fork_join_approval_flow"_
Diagram fork-join: Purchasing submit → dua Checker paralel (Manager Production, Manager Accounting) → Approver terkunci sampai kedua Checker selesai._

Catatan implementasi: pola ini secara alami dipetakan ke Reactor (fan-out/fan-in dengan compensation saat salah satu step gagal) — dibahas lebih lanjut di bagian Architecture.

2.7 Personalization & Account Model

Tiga lapisan yang dipisah tegas: Permission (apa yang boleh dilihat/dilakukan, diatur admin) → Role Default (dari yang boleh diakses, mana yang relevan ditampilkan duluan untuk fungsi tertentu, template per fungsi) → Personal Customization (penyesuaian individu di atas default).

— widget: "role_based_personalization_layers"_
Role default per fungsi (Sales/Warehouse/Finance) sebagai template admin, dengan contoh override personal seorang user dan opsi reset ke default._

Model Akun, bukan Persona Gabungan

Keputusan desain BMP: satu orang dapat memiliki lebih dari satu akun terpisah (contoh: budi.kasir dan budi.pemilik), bukan satu akun dengan banyak peran digabung otomatis. Personalisasi dan permission melekat ke akun, bukan ke individu fisiknya.

widget: "account_switcher_pattern"_
Pola account switcher: daftar akun yang tersimpan sesi-nya, badge notifikasi per akun tanpa menggabungkan datanya._

Admin vs Business Home

Akun IT/Sysadmin murni (tanpa keterlibatan transaksi bisnis) mendapat home berupa System Console (status job, backup, permintaan akses user) yang berbeda kategori sepenuhnya dari home operasional bisnis — bukan sekadar varian KPI dari template yang sama.

— widget: "business_home_vs_admin_home"_
Perbandingan Home akun bisnis (Sales) dengan Home akun IT Admin (System Console) — dua kategori informasi yang berbeda total._

2.8 Consistency Patterns

Kamus perilaku — satu pola untuk satu situasi, dipakai persis sama di seluruh aplikasi, dipaksakan lewat komponen bersama (bukan sekadar dokumentasi yang harus diingat manual).

— widget: "interaction_pattern_library"_
Lembar acuan pola interaksi: hierarki tombol, toast, modal konfirmasi destruktif, empty state, loading skeleton._

Cara menjaga konsistensi secara teknis: shared Phoenix function components (<.modal>, <.toast>, <.button variant="...">, <.empty_state>) dengan attr/slot untuk kontrak yang dicek saat compile; katalog visual komponen (mis. PhoenixStorybook); test khusus untuk komponen bersama karena dampak perubahannya luas.

2.9 Responsive & Usage Context

Untuk konteks kantor lokal (LAN, offline), isu klasik field usage (sinyal putus-putus, offline sync) tidak relevan. Yang tetap relevan: kemungkinan ada titik pemakaian fisik berbeda dalam satu lokasi — bukan device berbeda karena di luar kantor, tapi konteks fisik berbeda dalam satu gedung/toko.

— widget: "context_specific_priority"_
Perbandingan prioritas informasi: tabel padat untuk Desktop staf akuntansi vs target sentuh besar untuk Tablet staf gudang._

Catatan: Konvensi Bahasa UI Sistem

Konsep Label UI (English)
Feed perhatian utama di Home My Attention
Saved view — dokumen milik user Assigned to Me
Saved view — menunggu approval Pending Approval
Riwayat dokumen terakhir dibuka Recent Activity
Bagian field yang di-collapse Advanced Details
Tombol simpan tanpa submit Save Draft
Hub konfigurasi/master data Settings

Chapter 3: Architecture

0. Architecture Invariants

Prinsip yang mengikat seluruh keputusan di bawah — bukan sekadar filosofi tersirat, tapi aturan yang tidak boleh dilanggar modul manapun.

  1. Business logic tidak pernah bergantung pada topologi deployment (Standalone → Office Local-First).
  2. Domain logic hidup di Ash Resource/Action, bukan di Phoenix controller.
  3. Baca lintas domain lewat public action; efek samping lintas domain lewat event.
  4. Transaksi lintas domain yang butuh kepastian “semua-atau-tidak” memakai Reactor.
  5. Replikasi (sync-agent) tidak pernah memanggil Ash action.
  6. Mutasi hasil replikasi harus aman di level constraint database (CHECK, UNIQUE) — ini last line of defense, bukan pengganti validasi Ash.
  7. Data ledger transaksional bersifat append-only (insert-only, tidak pernah UPDATE/DELETE).
  8. Derived state (mis. stok saat ini) tidak pernah jadi source of truth — selalu rebuildable dari data ledger.
  9. Data finansial/audit tidak pernah dihapus otomatis.
  10. Sync infrastructure (sync-agent) berada di luar domain model Ash — infrastructure layer, bukan business/service layer BMP.

1. Fondasi: Phoenix — Ash — Event-driven

Elemen Peran
Ash.Domain Bounded context per modul (DDD) — Sales, Inventory, Accounting, dst.
Ash Resource Model — data, validasi, business rule, policy.
LiveView (default) / LiveState (khusus POS/kiosk) View + Controller. LiveView wajib pakai komponen bersama; LiveState untuk titik interaksi yang butuh respons sangat cepat di client atau harus tahan koneksi kurang stabil.
Ash.Notifier + AshEvents Event bus antar domain. Baca data lintas domain = panggilan langsung ke public action; efek samping akibat suatu aksi = event.
Reactor Orkestrasi transaksi “semua-atau-tidak” lintas domain (fork-join Checker, Sales Order → reservasi stok → jurnal).

DDD sebagai struktur makro (satu Ash.Domain = satu bounded context), tiap domain punya Model + Domain Logic sendiri, tetapi View tetap mengikuti Design System terpusat — bukan MVC penuh yang berdiri sendiri per domain. Folder structure per-domain (lib/bmp/sales/), bukan per-layer teknis.

2. Async & Data Processing

Library Dipakai untuk
Reactor Transaksi butuh rollback/compensation eksplisit.
Oban Job async reliable, terjadwal (eskalasi urgensi approval, dst).
AshOban Job yang terikat lifecycle satu Resource — diprioritaskan di atas Oban mentah bila relevan.
Broadway Ingest data volume/stream dari luar (batch harian POS/E-commerce).
NimblePool Worker pool untuk operasi resource-terbatas (generate PDF/laporan besar, panggilan API eksternal terbatas concurrency).

3. Data Layer — Full SQLite

Karena hanya satu data layer, tidak ada lagi kebutuhan “test matrix lintas database” — menyederhanakan CI dan menghilangkan kelas bug “jalan di SQLite, gagal di Postgres” (atau sebaliknya) yang sebelumnya jadi risiko di desain dual-layer.

4. Audit, Retensi & Kepatuhan (final)

AshArchival + AshPaperTrail, dengan empat aturan wajib:

  1. Tidak ada purge otomatis untuk Resource finansial/audit (PO, Invoice, Journal Entry, Approval/Checker-Approver record). Archive bersifat permanen — tidak ada job terjadwal yang menghapus data ini bahkan setelah retention period (10 tahun untuk pajak Indonesia) terlewati. Storage murah, kehilangan bukti hukum mahal.
  2. Aksi archive itu sendiri wajib tercatat AshPaperTrail — setiap “penghapusan” (arsip) harus punya jejak siapa/kapan/kenapa, sebagai meta-audit atas aksi audit-nya sendiri.
  3. Document Trail dan tab Archived wajib menampilkan record yang diarsipkan secara utuh — query di kedua tempat ini harus eksplisit menyertakan data ter-archive (include_archived?: true), tidak boleh ikut tersaring oleh filter default AshArchival.
  4. Archive adalah state transition (ACTIVE → ARCHIVED), bukan deletion secara konsep maupun implementasi — baris tetap ada secara fisik di database, hanya ditandai archived_at. Mental model ini yang membuat aturan 1–3 di atas konsisten.

Lapis keamanan lain (tidak berubah): AshAuthentication (model akun terpisah) → Ash.Policy.Authorizer (otorisasi) → AshCloak (enkripsi field sensitif) → AshRateLimiter (endpoint publik).

5. Ledger Khusus

TigerBeetle (via TigerBeetlex) — bukan pengganti RDBMS BMP Core, hanya untuk POS & E-commerce standalone. Scope sempit: cuma Account/Transfer (ledger kas) — katalog/sesi/cart tetap SQLite. Terhubung ke BMP Core lewat batch sync harian (Oban scheduled job, konfigurable), longgar — bukan transaksi real-time lintas sistem.

6. Cache & State

Dengan topologi disederhanakan menjadi SQLite-per-node, kebutuhan shared cache/pub-sub lintas node (Redix) tidak lagi relevan — tiap node (server kantor maupun laptop) berjalan sebagai instance mandiri.

Komponen Kapan dipakai
ETS Default satu-satunya — cache in-process ringan, nol dependency tambahan, dipakai di semua node.

Mnesia dan Redix tidak masuk stack — keduanya menjawab kebutuhan cluster/multi-node yang sudah tidak ada di topologi ini.

7. Observability, I18n, Storage

8. Testing & Static Analysis

9. Deployment Profiles

Dua profil, disederhanakan dari desain sebelumnya setelah PostgreSQL/cloud dihapus dari scope.

Profile Topologi Node & peran
1. Standalone Satu mesin, satu SQLite Tidak ada node lain — dipakai UMKM sekecil apa pun (1 komputer/laptop).
2. Office + Mobile Laptop (Local-First Sync) Satu server kantor on-premise + PC kantor (thin client) + sejumlah laptop mobile Lihat rincian peran per node di bawah.

Peran node di Profile 2

Node Instalasi Sync
Server kantor Ash app penuh + SQLite (source of truth kantor) Menjalankan sync-agent, menunggu koneksi dari laptop mobile
PC kantor (desktop, tidak keluar kantor) Thin client — connect langsung ke server kantor lewat LAN (browser/LiveView biasa) Tidak perlu — tidak ada SQLite lokal, tidak ada sync-agent
Laptop mobile (kadang di luar kantor) Ash app penuh + SQLite lokal Menjalankan sync-agent — connect ke localhost saat di luar kantor, ke IP server saat di kantor

Ini koreksi penting dari desain sebelumnya: bukan semua komputer perlu instalasi penuh + sync-agent. Hanya laptop yang benar-benar berpindah lokasi (dan karenanya butuh kemampuan offline) yang menjalankan SQLite lokal dan sync-agent. PC kantor yang selalu berada di LAN cukup jadi client biasa ke server kantor — persis seperti aplikasi web internal pada umumnya, tanpa kompleksitas sync sama sekali.

Detail lengkap mekanisme sync-agent (komponen, alur, protokol, failure mode, keamanan) dibahas di Addendum.

10. Hierarki Pemilihan Dependency (kebijakan resmi)

Tier 1 Ash/Phoenix → Tier 2 Elixir umum → Tier 3 Erlang/OTP langsung. Di mana pun Ash punya ekstensi resmi (Ash*), itu selalu dipilih di atas library generik non-Ash. Non-Ash hanya dipakai untuk hal di luar cakupan Ash (Phoenix itu sendiri, LiveState, Swoosh, Waffle, sync-agent) — semuanya tetap murni ekosistem Erlang/Elixir/Rust resmi tanpa dependency berat di luar itu.

Rincian Library Tier 2 (Elixir Umum) yang Dikunci untuk BMP:

  1. PDF Engine: tincture (pure Elixir). Menghasilkan PDF berkualitas tipografi tinggi (PDF/A untuk arsip, AES-256 untuk slip gaji) tanpa binary eksternal seperti wkhtmltopdf atau Chrome headless. Template PDF disimpan sebagai data XML, bukan HTML.
  2. QR Code: eqrcode (pure Elixir, zero dependencies). Dipakai untuk men-generate QR code Batch ID pada label traceability CPKB (Modul Manufacturing & Sales). Output SVG-nya langsung di-embed ke dalam template tincture.
  3. XLSX Export: exceed (pure Elixir, stream-oriented). Dipakai untuk mengekspor laporan berskala besar (misal: GL drill-down ribuan baris di Accounting, atau Sales Analytics tahunan) langsung ke format Excel .xlsx tanpa menyebabkan memory blow-up.
  4. CSV Import/Export: nimble_csv (pure Elixir). Dipakai sebagai jalur utama ingest data massal, seperti import rekap CSV harian dari marketplace (Sales) dan import statement bank (Accounting).
  5. Image Processing: DITOLAK. Kebutuhan manipulasi foto produk (resize, crop) dilayani di client-side (browser) atau tidak diperlukan sama sekali. Library populer seperti image (yang membungkus NIF libvips dari bahasa C) ditolak agar stack BMP tetap 100% pure BEAM tanpa risiko segmentation fault atau keharusan mengompilasi binary C di server produksi.
  6. Email (Swoosh): DITUNDA. Sesuai keputusan arsitektur, pengiriman dokumen (Invoice/DN) di Fase 1 dilakukan manual (Save PDF → Gmail/WA). Integrasi SMTP otomatis ditunda ke Fase 2.

Addendum: Mekanisme Sync-Agent — Penjelasan Detail

1. Gambaran Besar

Sync-agent adalah proses Rust kecil yang berjalan di server kantor dan di tiap laptop mobile (bukan di PC kantor — lihat bagian 9). Tugasnya satu: memastikan perubahan data di SQLite laptop dan SQLite server kantor selalu sinkron, tanpa Ash app perlu tahu apa pun.

2. Komponen Utama

Diagram 1 — Komponen Sync-Agent

2.1 Session Manager

Bertanggung jawab atas capture perubahan dari SQLite: membuat SQLite Session via rusqlite (feature session), attach ke tabel-tabel yang perlu disinkronkan, merekam setiap INSERT/UPDATE/DELETE yang dilakukan Ash app, dan menghasilkan changeset (blob biner) saat flush dipanggil. Session Manager tidak mengintervensi Ash app sama sekali — Ash menulis ke SQLite seperti biasa, Session Extension merekam efeknya di belakang layar.

2.2 Flush Scheduler

Bertanggung jawab memutuskan kapan changeset diambil dan dikirim. Model koneksi: begitu laptop pertama kali terhubung ke server kantor, seluruh perubahan tertunda langsung di-flush dan disinkronkan penuh (initial full sync). Setelah itu, koneksi TCP+TLS dijaga tetap terbuka (persistent) — setiap ada perubahan baru, flush dipicu segera (event-driven), bukan menunggu timer. Timer berkala (5–10 detik) tetap dipertahankan sebagai heartbeat/fallback (menjaga koneksi hidup dan menangkap perubahan yang mungkin terlewat), bukan sebagai mekanisme utama.

2.3 Transport Layer

Bertanggung jawab mengirim dan menerima changeset antar node.

2.4 Apply Engine

Bertanggung jawab menerapkan changeset yang diterima ke SQLite lokal: memanggil sqlite3changeset_apply() via rusqlite, menjalankan conflict handler per baris per tabel, dan mengirim ACK ke pengirim setelah berhasil.

2.5 State Manager

Bertanggung jawab menyimpan status sync — high_water_mark (offset changeset terakhir yang berhasil di-ACK, berfungsi sebagai sync cursor), schema_version (versi schema SQLite saat ini), last_synced_at, dan peer_status (reachable/unreachable). Disimpan di file lokal kecil terpisah (bukan di SQLite utama) agar tidak tercampur dengan data bisnis.

2.6 Telemetry Publisher

Mempublikasikan metrik ke Elixir lewat named pipe/Unix socket — event :telemetry (sync.changeset.sent, sync.changeset.applied, sync.conflict.resolved, sync.lag_seconds) yang dikonsumsi System Console BMP untuk menampilkan status sync per node.

3. Alur Lengkap: Laptop ke Server Kantor

Diagram 2 — Alur Lengkap Sync (Laptop → Server → Laptop)

Fase 1 — Capture

Ash app (exqlite) menulis ke SQLite (WAL mode) seperti biasa — INSERT/UPDATE/DELETE apa pun. Session Manager (rusqlite + session feature) merekam semua perubahan secara otomatis di belakang layar.

Fase 2 — Flush

Dipicu oleh perubahan baru (event-driven, koneksi persistent), timer heartbeat, peer baru terdeteksi, atau manual trigger. Session Manager memanggil sqlite3session_changeset() dan menghasilkan changeset blob biner.

Fase 3 — Transport

Transport Layer di laptop mengecek peer reachable, membuka (atau memakai) koneksi TCP+TLS ke server kantor, mengirim schema_version untuk verifikasi, mengirim changeset dalam frame length-prefixed, lalu menunggu ACK.

Fase 4 — Apply di Server

Server menerima frame, memverifikasi schema_version (tidak cocok → tolak koneksi, kirim error), lalu meneruskan ke Apply Engine yang memanggil sqlite3changeset_apply() dengan conflict handler:

Berhasil → kirim ACK. Gagal → kirim NACK + alasan.

Fase 5 — Konfirmasi & State Update

Laptop menerima ACK → update high_water_mark, update last_synced_at, publish telemetry (sync.changeset.sent + applied). Menerima NACK → log error, retry dengan backoff eksponensial, publish telemetry sync.conflict.manual bila perlu.

Fase 6 — Sync Balik (Server → Laptop)

Setelah ACK terkirim, server melakukan hal yang sama: flush session server (perubahan dari user kantor), kirim changeset ke laptop, laptop apply lalu kirim ACK balik. Ini yang membuat sync dua arah berjalan dalam satu koneksi persistent yang sama — bukan dua koneksi terpisah.

4. Conflict Resolution

Diagram 3 — Conflict Resolution per Jenis Tabel

5. Failure Mode & Recovery

Diagram 4 — Failure Mode & Recovery

6. Catatan Penting Operasional

WAL Mode wajib — semua SQLite yang terlibat harus dikonfigurasi:

PRAGMA journal_mode=WAL; PRAGMA busy_timeout=5000;

Tanpa ini, Ash app dan sync-agent bisa saling block saat menulis bersamaan.

CHECK Constraint wajib — karena apply changeset bypass Ash action, business rule kritikal harus ada di level SQLite, bukan hanya di validasi Ash:

CHECK (qty >= 0) CHECK (amount > 0)

Schema Version wajib — setiap migrasi Ash harus menaikkan schema_version di metadata database. Sync-agent membaca ini sebelum menerima koneksi apa pun, dan menolak sync jika versi laptop dan server tidak cocok (urutan upgrade: server kantor dulu, baru laptop — selama laptop belum di-upgrade, sync berhenti sementara, bukan corrupt).

Chapter 4: Development Conventions

Belum disusun — akan dibahas pada sesi berikutnya.

Cakupan yang direncanakan:

Chapter 5: System UI/UX

Belum disusun — akan dibahas pada sesi berikutnya.

Cakupan yang direncanakan:

Chapter 6: Report & Workflow

Belum disusun — akan dibahas pada sesi berikutnya.

Cakupan yang direncanakan:

Chapter 7: Modul ERP Core

Belum disusun — akan dibahas pada sesi berikutnya. Sales sudah dipakai sebagai contoh acuan pada sesi-sesi sebelumnya.

Cakupan yang direncanakan:

Chapter 8: Modul Optional/Community

Belum disusun — akan dibahas pada sesi berikutnya. Modul-modul ini dirancang togglable per instalasi dan dapat didorong ke kontributor komunitas.

Cakupan yang direncanakan: