# Changelog Semua perubahan penting pada platform KeluargaMart didokumentasikan di berkas ini. Format berkas ini mengacu pada [Keep a Changelog](https://keepachangelog.com/id/1.0.0/) dan mematuhi [Semantic Versioning](https://semver.org/spec/v2.0.0.html). Daftar lengkap seluruh commit beserta atribusi versi tersedia di [CHANGELOG-COMMITS.txt](./CHANGELOG-COMMITS.txt). Catatan pengguna rilis terbaru tersedia dalam bentuk teks: [CHANGELOG-v1.5.0.txt](./CHANGELOG-v1.5.0.txt), [CHANGELOG-v1.4.1.txt](./CHANGELOG-v1.4.1.txt), [CHANGELOG-v1.4.0.txt](./CHANGELOG-v1.4.0.txt), [CHANGELOG-v1.3.0.txt](./CHANGELOG-v1.3.0.txt), dan [CHANGELOG-v1.2.0.txt](./CHANGELOG-v1.2.0.txt); rincian bukti transaksi lokal ada di [CATATAN-PERBAIKAN-INTEGRITAS-TRANSAKSI.txt](./CATATAN-PERBAIKAN-INTEGRITAS-TRANSAKSI.txt). Atribusi commit mengikuti batas rilis monorepo, bukan tanggal semata; riwayat impor tanpa bukti versi ditandai historis tanpa SemVer. --- ## [Unreleased] Belum ada perubahan baru di luar rilis yang dicatat di bawah ini. ## [1.5.0] — 2026-11-01 ### Ringkasan Rilis Rilis 1.5.0 menuntaskan satu keluarga bug yang berakar sama: pesanan e-commerce punya DUA mode pemenuhan (ambil sendiri di toko dan kirim ke alamat) tetapi diperlakukan sebagai satu alur yang seragam. Akibatnya daftar kasir memuat pesanan kurir, daftar gudang memuat pesanan pickup, pesanan pickup dibuatkan Delivery Order otomatis, dan serah terima di kasir tidak pernah berhasil. Rilis ini juga mengembalikan verifikasi manusia pada pesanan yang sudah dibayar, menghentikan penimpaan status `delivered` menjadi `invoiced`, mengganti seluruh angka dashboard dari proksi menjadi agregat tabel yang sama dengan rinciannya, menampilkan diskon member pada detail sales order, dan membuka layar kasir "Ambil Toko" yang sebelumnya tidak pernah bisa diakses. ### Ditambahkan (Added) - **Bukti Foto Penerimaan Barang / POD pada Delivery Order** (`020f740`, migrasi `000143`): `POST /delivery-orders/{id}/deliver` menerima body multipart opsional (foto + nama penerima) yang disimpan melalui pipeline unggah bersama (maks. 5 MB, validasi tipe gambar, kunci `proof-`). Panel "Bukti Foto Penerimaan Barang (POD)" dan badge "Foto POD ✓" di ERP kini punya kolom, endpoint, dan penyimpanan nyata — sebelumnya panel itu hanya bisa menampilkan "Belum Ada Foto POD". - **Bukti Foto Penerimaan dari Pembeli B2B** (`8a23628`, migrasi `000142`): `PATCH /sales-orders/{id}/received-proof` mencatat foto bukti terima yang diunggah pembeli saat mengonfirmasi pesanan. Bersifat bukti, bukan gerbang: kegagalan unggah tidak membatalkan konfirmasi, tetapi pembeli diberi tahu. Kepemilikan diperiksa terhadap customer pesanan tersebut. - **Halaman Kasir "Ambil Toko"** (`7df125b`): layar serah terima pesanan online di POS kini benar-benar terkirim — rute `/pickup`, menu sidebar, `orderService.forPickup` / `completePickupHandover`, dialog serah terima dengan perhitungan kembalian, serta struk bukti serah terima. - **Rincian (drilldown) kartu dashboard** (`0a14d89`): `activeOrders`, `todaySales`, `pendingInvoices`, dan `activePOs` kini dikirim `/dashboard/charts` sehingga setiap kartu yang dapat diklik membuka daftar yang benar. - **Migrasi 000140–000146**: `000140` mengizinkan progres fulfillment gudang pada sales order setelah shift kasir ditutup (tanpa melonggarkan guard finansial); `000141` dan `000145` menetapkan akun pembeli mulai dari tier Bronze; `000142` bukti terima pembeli; `000143` kolom POD pada delivery order; `000144` pembersihan membership hasil auto-enroll (dibalik oleh `000145`); `000146` memberi izin persetujuan order kepada gm/bm/spv. - **Gerbang pengujian baru pada AGENTS.md**: 7-A pemisahan mode pemenuhan, 7-B pemeriksaan UI-orphan (termasuk "halaman tanpa rute belum terkirim"), 7-C status terminal & hook efek samping, 7-D aritmatika uang yang harus reconcile di layar, serta 8-E/8-F untuk paritas dashboard dan verifikasi artefak yang berjalan. ### Diperbaiki (Fixed) - **Pembayaran tidak lagi otomatis menerima pesanan** (`8a23628`): `SettleOrderPayment` tidak lagi memajukan `pending_approval` menjadi `invoiced`. Pelunasan Midtrans hanya mencatat uang; status tetap "Menunggu Konfirmasi" sampai ada manusia yang menjalankan `Confirm` (yang mencatat `approved_by`). - **Serah terima di kasir berfungsi, tanpa membuka celah** (`8a23628`, `915f525`): transisi `pending_approval` → `delivered` diizinkan HANYA untuk pickup tunai (`isCashierHandover && isPickupOrder && isCashOrder`). Pesanan transfer tetap wajib diterima dan dibayar lebih dulu, dan kasir tidak lagi dapat melompatkan pesanan kurir langsung ke `delivered` (sebelumnya HTTP 200 — kini ditolak). - **`delivered` tidak lagi berubah menjadi `invoiced`** (`504da82`): `AdvanceFulfillment` memicu hook `onConfirm` untuk setiap transisi, dan hook itu membuat invoice yang menulis status `invoiced` tanpa syarat — sehingga setiap serah terima berakhir "invoiced" dengan invoice terbuka hantu. Hook kini hanya menyala saat pesanan benar-benar mencapai `confirmed`, dan `CreateInvoice` hanya menstempel `invoiced` pada status pra-fulfillment. - **Daftar tidak lagi saling bocor antar mode** (`8a23628`, `b278bb6`, `3a71081`): `/sales-orders/for-pickup` hanya berisi pesanan pickup (filter `pickup_only` di SQL, sebelum LIMIT/OFFSET), sedangkan daftar Packing Order ERP memakai `exclude_pickup=1`. Sebelumnya keduanya menyaring `order_type` saja sehingga pesanan kurir muncul di layar kasir dan pesanan pickup muncul di antrean gudang. - **Delivery Order otomatis tidak dibuat untuk pickup** (`020f740`): `onOrderConfirmed` melewati pesanan pickup, sehingga barang yang diserahkan di kasir tidak lagi tampil sebagai "Sedang Diantar" di peta dispatch. - **Checkout B2B tidak lagi mengembalikan 500 generik** (`66724db`): lima sentinel `sales.*` yang belum dipetakan (`ErrUnpaidOrderFulfillment`, `ErrFulfillmentForbidden`, `ErrPaymentNotAllowed`, `ErrPaidCannotCancel`, `ErrGatewayDisabled`) kini dipetakan ke 409/403/400/503 dengan pesan aman. Sebuah test tabel mengunci seluruh sentinel agar tidak ada yang kembali menjadi "Something went wrong". - **Kartu dashboard dihitung dari tabel yang sama dengan rinciannya** (`0a14d89`): "Penjualan Hari Ini" tidak lagi `MonthSales / 30`, "Order Aktif" tidak lagi `len(RecentActivity)`, "PO Aktif" tidak lagi konstanta `2`, dan "Net Cashflow" tidak lagi `MonthSales − MonthPurchase`. Predikat status didefinisikan sekali (`activeOrderStatuses`) dan dipakai oleh `COUNT(*)` maupun daftar modal. - **Daftar order menghormati filter tanggal dan cakupan toko** (`3a71081`): query baris kini menerima `date_from`, `date_to`, `store_id`, dan `allowed_store_ids` yang sebelumnya hanya dipakai oleh `COUNT(*)` — pemilih tanggal tidak lagi inert dan pemanggil ter-scope toko tidak lagi menerima baris toko lain. - **Detail sales order menampilkan diskon member** (`1321ff4`): kolom Diskon menampilkan diskon baris + diskon member beserta catatan "Termasuk diskon member …", sehingga `Harga × Qty − Diskon = Subtotal` menutup di layar (laporan "harga jual dan total nominal tidak sesuai" pada pesanan POS). - **Detail sales order tidak lagi menampilkan proses gudang** (`1321ff4`): panel "Status Pengiriman & Distribusi" dan tombol "Buka di Modul Packing Order" dihapus dari halaman sales order; "Batalkan Order" dipindah ke header agar tidak hilang. - **Halaman pesanan B2B sadar mode** (`7d75a63`): pesanan pickup tidak menampilkan tombol "Lacak Pengiriman", stepper kurir, maupun kartu Dokumen; pesanan kurir tetap menampilkan semuanya. - **Notifikasi POS tidak lagi kembali "belum dibaca"** (`aacb4cb`): status baca disimpan per-id di `localStorage`, dan cache PWA dinaikkan ke `km-pos-v4` agar klien menerima bundle baru. - **Nomor SO pada modal dashboard** (`ba36507`): baris rincian membaca `so_number` (sebelumnya `order_number` sehingga setiap baris tampil `#SO-1`). - **Nama dan alasan status transfer/pickup di POS** (`7df125b`): pesanan transfer yang belum lunas diberi badge "Menunggu Transfer" dan tombol serah terima dimatikan dengan penjelasan, bukan dibiarkan memicu penolakan server. - **Hydration mismatch B2B pada deep link tamu** (`fdfbd53`, `a16330d`): middleware auth hanya mengalihkan di klien, sehingga server sudah mengirim halaman terproteksi lalu klien berpindah ke `/login` di tengah hidrasi — dua pohon render, satu peringatan di setiap deep link. Server kini memutuskan lewat cookie token: tanpa cookie → redirect 302 sebelum halaman dikirim; dengan cookie → render dan klien memulihkan sesi. Atribut `` juga dipasang lewat `htmlAttrs` agar cocok antara SSR dan klien. - **Cookie login B2B dibuang di origin http** (`fdfbd53`): atribut `secure` mengikuti `NODE_ENV`, sehingga build mode produksi yang dilayani lewat http kehilangan cookie token — login "berhasil" lalu setiap navigasi penuh terlihat logged-out. `secure` kini mengikuti protokol origin sebenarnya. - **Picker produk pada form transfer ERP** (`a16330d`, `a749b5c`): form memuat satu halaman berisi 200 produk, sehingga produk ke-201 dan seterusnya tidak pernah bisa ditransfer. Diganti `KProductSelect` yang mencari ke API (server-side), dan sisa import yang mati dibersihkan. - **Validasi voucher tidak dikenal menjawab 404** (`540be14`): kasir mengirim kode ke `/sales-vouchers/validate` untuk bertanya "apakah kode ini bisa dipakai?" — jawaban 404 terbaca seperti endpoint rusak. Kode tak dikenal kini menjawab `200 {valid:false, reason}`; kegagalan lain tetap memakai status aslinya. - **Akun pembeli mulai dari tier Bronze** (`000141`, `000145`): pendaftaran dan data akun pembeli mulai dari tier Bronze. Dukungan akun reguler (non-member) tetap dipertahankan pada kode frontend dan backend sebagai penanganan aman (jaga-jaga). - **Status baca notifikasi bertahan setelah reload di ERP dan B2B** (`6fed8d1`): read-state disimpan per id di `localStorage` dan dipakai oleh store notifikasi bersama, sehingga lonceng tidak kembali menyalakan notifikasi yang sudah dibaca setiap kali halaman dimuat ulang. - **"Selesaikan pesanan DO" selalu gagal 500** (`49dc344`): penulis kolom bukti pengiriman (POD) dipanggil dengan transaksi `nil`, sehingga setiap penyelesaian DO — dengan maupun tanpa foto — mengalami panic nil pointer. Metode kini menerima transaksi pemanggil, sehingga bukti pengiriman tersimpan atomik dengan status penyelesaiannya. Diverifikasi live: DO tanpa foto selesai dan SO menjadi delivered; DO dengan foto multipart menyimpan `proof_photo_url` dan nama penerima. - **Tier awal member tertulis 5% padahal backend memberi 2%, dan "Silver" tidak pernah ada** (`97492d1`): halaman Keanggotaan dan ringkasan akun B2B menampilkan bronze 5% / silver 10% / gold 15% / platinum 20%, sementara `membership_tiers` yang dipakai mesin harga berisi bronze 2% / gold 5% / platinum 8% — dan tidak ada kode yang pernah memberikan Silver. Halaman kini memakai angka yang sama dengan backend, entri Silver dihapus (halaman, tipe, dan fallback offline), dan dua test menjaga agar pendaftaran selalu menulis `bronze` pada membership maupun riwayat tier. - **Header tabel Hutang Supplier kini mengurutkan lewat server** (`5aa6bf7`, dipilih pengguna — opsi b): klik header (No. PO, Supplier, Tgl PO, Jatuh Tempo, Total, Dibayar, Sisa Hutang) mengirim `sort_by`/`sort_dir` ke backend dengan whitelist kolom; sebelumnya ikon sortir hanya kosmetik dan urutan kembali seperti semula saat pindah halaman. `useListPage` kini punya `onSort` yang bisa dipakai daftar server-side lain. - **Hutang supplier tanpa rincian: retur pembelian tidak pernah memotong hutang** (`c017b7d`, migrasi `000147`): form Penerimaan Barang memiliki kolom "Retur / Cacat" + foto bukti, tetapi backend tidak memiliki field-nya — nilai penolakan dibuang dan PO tetap berutang penuh atas barang yang ditolak di pintu gudang. Kini `quantity_rejected` + `defect_notes` tersimpan (migrasi 000147), nilai PO otomatis dikurangi saat penerimaan (harga PO sebagai kontrak), dan halaman Hutang Supplier mendapat drill-down per PO: nama supplier, no. referensi, sumber utang, nilai retur, total, dan pembayaran. - **Jurnal otomatis per transaksi galon** (`d414de1`): uang galon tercatat di `payments` tetapi tidak pernah masuk buku besar. Kini setiap penyelesaian galon mem-posting jurnal `cash_receipt`: D Kas Tunai Toko / K Pendapatan Depot Galon Air untuk penjualan, plus K Uang Muka Penjualan / Deposit Customer untuk deposit (liabilitas terpisah agar neraca menyatakan keduanya). Di-posting dengan role system, gagal jurnal dilaporkan bukan ditelan. - **Transaksi galon tidak terlihat di Laporan Penjualan ERP** (`9bf362e`): data galon tersimpan di tabel terpisah (`galon_transactions`), dan backend sebenarnya sudah mengirim `galon_total` + rincian per hari — tetapi halaman Laporan Penjualan membuangnya, sehingga kasir yang melihat uang galon di kasir tidak menemukannya di ERP. Kini tampil KPI "Penjualan Depot Galon" (tetap terpisah dari Total Penjualan) dan grafik "Pasar vs Depot Galon" per hari. - **Selisih opname tidak mengikuti snapshot stok** (`735fb6b`): tiga cacat dengan satu sebab. (a) Baris yang belum dihitung dilaporkan sebagai selisih negatif penuh (produk 9.899 tampil −9.899) karena SQL memakai `COALESCE(physical,0)`. (b) "Terbitkan & Kunci Stok" hanya menulis status, sehingga mutasi gudang tetap menggeser stok di bawah perhitungan. (c) Salinan UI menjanjikan pembekuan penuh padahal kasir harus tetap bisa berjualan. Kini selisih kosong sampai dihitung, mutasi gudang (stok masuk/keluar, transfer, penerimaan) ditolak 409 selama opname terbuka, dan penjualan kasir tetap berjalan dengan penjelasan yang benar di layar. - **Dua tanda plus pada tombol "Input Kunjungan Mandiri"** (`397af9c`): tombol menampilkan ikon Plus sekaligus menuliskan "+" pada labelnya. Teks "+" dihapus (ikon sudah menyampaikan maknanya), dan sebuah test menjaga seluruh berkas Vue agar tidak lagi memakai keduanya sekaligus. - **Tabel ERP sulit dibaca: tanpa garis kolom dan header tipis** (`d925716`): kolom uang rata kanan bercampur kolom teks rata kiri tanpa pemisah, sehingga mata kehilangan baris. Header kini berupa pita tebal dengan garis bawah, ditambah garis kolom tipis, sorotan baris saat kursor, dan angka tabular — diterapkan di komponen tabel bersama sehingga berlaku ke seluruh tabel ERP. - **Urut naik/turun tidak berfungsi di Master Data → Produk** (`f5fb6f2`): tabel ERP mengirim `sort_by`/`sort_dir`, tetapi endpoint produk hanya memahami kosakata storefront (`name`, `price_asc`, …), sehingga klik header Harga Beli / Harga Jual / Stok selalu mengembalikan halaman yang sama. Kini `sort_by`/`sort_dir` dipakai untuk name, code, selling_price, purchase_price, created_at, dan stock — dengan whitelist agar nilai dari query string tidak pernah masuk SQL sebagai identifier. - **Pesanan tanpa metode pembayaran macet di "Menunggu Pembayaran"** (`df2dfc1`): aturan bayar-di-muka hanya mengecualikan order non-e-commerce, sehingga order e-commerce yang metodenya tidak terisi dianggap "transfer belum lunas" dan tidak bisa dikemas. Sekarang hanya penanda eksplisit transfer/gateway/qris yang menahan pesanan; "metode tidak tercatat" bukan bukti transfer. Aturan di halaman Packing disamakan dengan backend agar badge dan aksi tidak berbeda. - **Widget Cashflow menaruh uang bulan ini di bulan yang salah** (`ab15d8d`): seri 12 bulan berakhir di bulan berjalan, tetapi label memakai daftar tetap Jan–Des, sehingga pada 1 November semua batang bergeser satu bulan dan penerimaan 18jt tampil sebagai "Des". Backend kini mengirim `cashflow.months` (YYYY-MM) dari jendela yang sama dengan datanya, dan chart serta modal menampilkan "Nov 2026" sesuai bulannya. - **Tombol Daftar B2B tidak bereaksi** (`89848bd`): aturan wajib "setujui syarat dan ketentuan" tidak punya `UFormField` untuk menampilkan pesan, sehingga menekan Daftar tanpa mencentang syarat tidak mengirim request dan tidak menampilkan apa pun — akun tidak pernah dibuat, lalu login dengan kredensial itu tentu gagal. Kotak centang kini dibungkus `UFormField` sehingga pesannya muncul. - **Feed notifikasi B2B selalu kosong** (`89848bd`): kode memanggil `ORDERS` yang tidak pernah didefinisikan (konstanta sebenarnya `SALES_ORDERS`), sehingga setiap pemanggilan melempar ReferenceError dan ditelan `catch` — pembeli yang sudah masuk tidak melihat notifikasi apa pun. Typecheck B2B kembali bersih. - **Metode pembayaran tidak terlihat di layar Ambil Toko POS** (`6b1c9bf`): kartu hanya menebak "apakah catatannya cash?" dan semua sisanya dilabeli "Menunggu Transfer", sehingga order QRIS/gateway yang belum lunas terbaca seolah menunggu transfer bank. Backend kini mengekstrak penanda `[Metode: …]` sekali (`payment_method`) dan kasir melihat metode sebenarnya — Tunai di Kasir, Transfer Bank, atau QRIS/VA/E-Wallet — beserta status Lunas/Belum dibayar di kartu dan dialog serah terima. - **Antrean persetujuan order tidak pernah muncul untuk atasannya** (`6349751`, migrasi `000146`): tidak ada satu pun role yang memegang `sales.sales-orders.confirm` — hanya admin/owner lewat bypass kode — sehingga order berstatus "Menunggu Persetujuan" tidak menampilkan banner maupun tombol Setujui bagi GM/BM/SPV. Izin kini diberikan ke gm, bm, dan spv; sales sengaja tidak diberi agar pemohon tidak menyetujui ordernya sendiri (aturan yang sama dengan pemisahan PO). Tombol Setujui di Packing Order juga kini mengikuti izin yang sama, sehingga peran gudang tidak lagi ditawari aksi yang berakhir 403. ### Ditingkatkan (Improvements) - **Satu penanda, tiga konsumen** (`8a23628`, `57c0271`): `isPickupOrder` pada backend Go, `isPickupOrder` pada `apps/b2b/app/utils/paymentMethods.ts`, dan pola regex SQL `shipping_address` dipertahankan identik dan saling dirujuk pada komentar. - **Kontrak & permission disinkronkan**: drift check bersih pada **395 route** dan **207 permission**. - **Cakupan pengujian**: backend 42 paket hijau (termasuk `-race` pada sales/cashier/cart), ERP 361 test, POS 123 test, B2B 182 test; paritas dashboard dikunci oleh `TestDashboard_SummaryMatchesDrilldown`, dan pemetaan serah terima POS oleh unit test service. - **Verifikasi UI nyata**: sweep Playwright 9/9, deep sweep 74/74, interaksi menyeluruh tanpa kegagalan, dan alur data end-to-end 28/28 — termasuk satu pesanan pickup dan satu pesanan kurir nyata yang diperiksa pada daftar POS, daftar Packing ERP, dan halaman pesanan B2B. - **Perintah sweep yang didokumentasikan akhirnya ada** (`797b043`): `pnpm sweep`, `pnpm test:e2e`, `pnpm test:ui`, `pnpm sweep:deep`, dan `pnpm test:flow` tertulis di AGENTS.md sebagai quality gate tetapi tidak pernah ada di `package.json`. Kini terhubung ke implementasinya beserta devDependency playwright. ## [1.4.1] — 2026-10-30 ### Ringkasan Rilis Pembaruan Versi 1.4.1 berfokus pada sinkronisasi tahapan linier progres pelacakan Delivery Order (DO 5-tahap) dan validasi fulfillment kuantitas barang terkirim di ERP, otomatisasi penyelesaian pembayaran pesanan COD (Auto-Settlement on Delivery) di B2B, penuntasan bug 403 Forbidden pada formulir pengajuan retur pelanggan e-commerce, penguatan Service Worker PWA (*bulletproof navigation error handling* dan isolasi cross-origin) di ERP/POS/B2B, penambahan tag meta standar `mobile-web-app-capable`, serta publikasi Master System Reference & Audit Ledger operasional monorepo. ### Ditambahkan (Added) - **Master System Reference, Operational Guidelines & Audit Ledger** (`3bc20a6`): Publikasi panduan master kanonikal pada `docs/MASTER_SYSTEM_REFERENCE_AND_GUIDELINES.md` yang mencatat batas arsitektur (*single source of truth*), audit kesehatan 14 container, 139 migrasi database, drift check 389 route & 207 permission, register perbaikan masalah, serta runbook operasional produksi dan staging. - **Offline HTML Fallback PWA & Isolasi Cross-Origin** (`197f651`): Service Worker `sw.js` pada ERP, POS, dan B2B kini menyajikan fallback halaman offline HTTP 503 yang ramah pengguna jika jaringan offline dan cache shell belum terisi. Request cross-origin (analitik Cloudflare, payment gateway, CDN) di-bypass otomatis agar tidak terpengaruh oleh ekstensi browser atau adblocker. - **Meta Tag Standar PWA Modern** (`197f651`): Menambahkan `` pada `apps/erp/index.html`, `apps/pos/index.html`, dan `apps/b2b/nuxt.config.ts` untuk mematuhi standar spesifikasi browser Chrome 119+ dan menghilangkan peringatan deprecation. ### Diperbaiki (Fixed) - **Sinkronisasi Stepper Delivery Order (DO) & Guard Selesai** (`4455cc6`): Modal "Perkembangan Orderan & DO" di ERP kini secara presisi memetakan 5 tahapan linier (1. Order Dibuat -> 2. Sedang Dikemas -> 3. Siap Diantar -> 4. Dalam Pengiriman -> 5. Selesai / Diterima). Tombol "Selesaikan Pesanan" dikunci secara ketat dan tidak dapat ditekan jika barang belum dikirim (`shipped_quantity == 0`) atau status DO belum dalam pengiriman. - **Otomatisasi Pelunasan COD saat Diterima (Auto-Settle on Delivery)** (`4455cc6`): Pada saat pengiriman pesanan tunai/COD diselesaikan oleh kurir/gudang (`DELIVERED`), backend Go secara otomatis menandai status pembayaran pesanan menjadi `PAID` (Lunas) dan mencatat transaksi kas. Serta melakukan penyelesaian tuntas pada database untuk pesanan COD terdahulu yang telah diterima. - **Penyembunyian Tombol Bayar Sekarang B2B** (`4455cc6`): Tombol "Bayar Sekarang" di kartu daftar pesanan dan detail akun B2B disembunyikan secara menyeluruh untuk pesanan COD/CASH, status Selesai, atau status Lunas, mencegah pembeli membuka gateway e-wallet / transfer untuk pesanan tunai fisik. - **Otorisasi Pengajuan Retur Pelanggan B2B (HTTP 403 Resolved)** (`4455cc6`): Mengatasi kendala otorisasi saat submit retur pesanan di B2B dengan memperbarui resolver data pembeli, memastikan role `buyer` memegang akses submit retur, dan memastikan token otorisasi disertakan saat formulir dikirim. - **Eliminasi TypeError Service Worker Navigation** (`197f651`): Menghilangkan crash `TypeError: Failed to convert value to 'Response'` pada `sw.js` dengan mengubah handler fetch navigasi menggunakan async/await yang menjamin kembalinya objek `Response` valid, serta menaikkan versi cache menjadi `km-erp-v2`, `km-pos-v2`, dan `km-b2b-v2`. ### Ditingkatkan (Improvements) - **Transisi Status Order & DO Atomik di Backend** (`4455cc6`): Fungsi `AdvanceFulfillment` dan `DeliverDeliveryOrder` pada modul sales dan distribusi mengelola kuantitas `shipped_qty` dan `remaining_qty` secara atomik di dalam transaksi database. - **Deploy Mount Live Service Worker** (`197f651`): Sinkronisasi berkas `sw.js` langsung pada volume container deployment di produksi dan staging (`data/deploy/*/sw.js`). ## [1.4.0] — 2026-10-29 ### Ringkasan Rilis Pembaruan Versi 1.4.0 berfokus pada sistem Background Push Notification (PWA Web Push & Service Worker) di ERP dan B2B, pengetatan kontrol akses otorisasi gudang tujuan pada penerimaan transfer stok, perbaikan hak akses pengajuan retur B2B, pemisahan tegas hak akses operasional gudang dari halaman Sales Order ERP, pembenahan logika pembayaran Cash/COD tanpa popup online gateway, serta pemulihan keandalan login kasir (fail-open rate limiter) dan pencegahan kebocoran port Nginx pada unduhan APK. ### Ditambahkan (Added) - **Background Push Notification (Full-Stack PWA)** (`d6907b7`): Dukungan Web Push Notification aktif di latar belakang (background) menggunakan Service Worker (`sw.js`) pada ERP dan B2B. Dilengkapi pemutaran audio chime notifikasi pesanan (`/sounds/notification.mp3`), vibration pattern, badge, serta aksi klik notifikasi untuk membuka atau memfokuskan tab aplikasi. - **Backend Push Notification Service** (`d6907b7`): Tabel database `push_subscriptions` (migration `000139`), endpoints `/api/v1/notifications/push-subscriptions`, `/vapid-key`, dan pengujian `/push-test`. Otomatis mengirim push notification ke staf (admin, owner, warehouse, sales) saat pesanan baru masuk dan ke pembeli saat pesanan dikemas/dikirim/selesai. - **Kartu Pelacakan Distribusi Sales Order (Read-Only)** (`d6907b7`): Halaman detail Sales Order ERP kini menampilkan ringkasan status distribusi dan pengiriman dengan deskripsi alur operasional dan navigasi langsung ke modul Packing Order (`/distribution/customer-orders/:id`). ### Diperbaiki (Fixed) - **Otorisasi Penerimaan Transfer Stok Antar Gudang** (`569d475`): Tombol "Terima" pada tabel transfer stok ERP hanya muncul jika user terhubung dengan gudang tujuan (`currentUser.warehouse_id === destination_warehouse_id`). Backend Go memvalidasi otorisasi dan menolak aksi dari gudang asal dengan HTTP 403 Forbidden (*"Hanya gudang tujuan yang berhak menyelesaikan penerimaan barang"*). - **Pengajuan Retur Pelanggan B2B** (`569d475`): Memperbaiki error `403 Forbidden` saat customer B2B mengirim formulir retur untuk Sales Order miliknya. Sistem kini memverifikasi klaim `customer_id` pembeli dengan kepemilikan pesanan secara akurat. - **Tombol & Modal Bayar Sekarang B2B** (`d6907b7`): Tombol "Bayar Sekarang" disembunyikan secara menyeluruh pada kartu pesanan dan detail pesanan B2B jika pesanan menggunakan metode pembayaran Tunai/COD atau berstatus Selesai/Dibatalkan/Lunas. Backend menolak inisiasi pembayaran online untuk pesanan COD atau yang tidak berstatus payable. - **Pemisahan Wewenang Pemenuhan Gudang di ERP** (`d6907b7`): Tombol aksi eksekusi gudang (`Proses — Mulai Packing` dan `Selesaikan Pesanan`) dihapus dari tampilan Sales Order umum ritel. Backend mengunci endpoint transisi fulfillment hanya untuk role warehouse officer atau superadmin. - **Ketahanan Login Kasir POS & ERP** (`3efede2`): Rate limiter autentikasi login menerapkan mekanisme *fail-open* jika server Redis terputus sementara, mencegah kasir terblokir oleh error *"rate limiter unavailable"*. - **Pencegahan Leak Port 8080 pada Unduhan APK** (`3efede2`): Menonaktifkan `port_in_redirect` pada reverse proxy Nginx sehingga pengalihan URL `/apk` tidak mengekspos port internal 8080. ## [1.3.0] — 2026-10-27 ### Ringkasan Rilis Pemisahan alur pemenuhan pesanan B2B melalui modul ERP Packing Order khusus, modul pengajuan retur barang di B2B E-Commerce, standardisasi penomoran dokumen dengan format tanggal penuh YYYYMMDD dan reset sequence bulanan, perbaikan tuntas metode pembayaran Cash/COD tanpa popup Midtrans, penyempurnaan alur transfer stok dengan approval fallback, serta dokumentasi komprehensif naskah video presentasi omnichannel. ### Ditambahkan (Added) - **Modul ERP Packing Order** (`1f12615`, `17e9d15`, `4143ffe`, `9dddca4`, `b4e9fa1`): Pemisahan antrean fulfillment grosir B2B dari Sales Order reguler di menu *Distribusi & Pengiriman -> Packing Order*. Dilengkapi dengan kartu statistik (`KStatCard`), tabel standar (`KDataTable`), modal detail (`DetailItem`), filter toko/outlet, serta alur bertahap (Ambil Pesanan, Input Resi, Assign Driver, Tandai Siap Kirim). - **Pengajuan Retur di B2B E-Commerce** (`17e9d15`): Form pengajuan pengembalian barang langsung dari akun pesanan pembeli B2B dengan input alasan (rusak/cacat/kurang) dan upload bukti foto fisik yang terhubung ke verifikasi ERP. - **Penomoran Dokumen Reset Bulanan** (`2f7b9d3`, `f29859a`): Penomoran PO, Transfer Stok, dan Jurnal Akuntansi tetap mempertahankan format tanggal lengkap `YYYYMMDD` dengan nomor urut yang direset per awal bulan kalender untuk menjaga kesinambungan audit pembukuan. - **Panduan & Skrip Video Presentasi** (`0d148d8`, `d1fd076`): Penambahan dokumen storyboard teknis (`docs/PANDUAN_ALUR_VIDEO_PRESENTASI.md`) dan naskah voiceover siap rekam kata-demi-kata (`docs/SKRIP_VIDEO_PRESENTASI_LENGKAP.md`) mencakup modul POS, B2B, dan ERP Sales/LHPP. ### Diperbaiki (Fixed) - **Pembayaran Cash / COD B2B** (`8ac3cbf`): Memperbaiki bug di mana memilih metode pembayaran tunai (Cash/COD) sempat memicu popup Midtrans Snap; mengklasifikasikan metode sebagai `kind: 'cash'`, menampilkan modal petunjuk COD resmi, dan menyembunyikan tombol pembayaran kartu/gateway. - **Pencegahan Hydration Mismatch B2B** (`02ba2d2`): Memperbaiki SSR/CSR hydration mismatch pada halaman riwayat pesanan akun B2B dan memastikan token otorisasi tersambung saat pagination dan filter. - **Isolasi Sequence Stock Movement Harian** (`13c5562`): Mengunci sequence penomoran mutasi stok dalam lingkup hari kalender untuk mencegah tabrakan unique constraint di database PostgreSQL. - **Persetujuan Transfer Stok & Approval Fallback** (`2f7b9d3`): Menyediakan alur transit fisik perpindahan stok antar cabang dan fallback persetujuan otomatis jika supervisor outlet asal berhalangan. - **Pembersihan Dependensi & Laporan Laba Rugi ERP** (`9aaa237`, `4143ffe`): Memperbaiki import `warehousesService` pada halaman Packing Order dan menjaga pelaporan PnL di dashboard. ### Ditingkatkan (Improvements) - **Auto-Refresh Status Pengiriman** (`1998441`, `fe177d8`): Sinkronisasi real-time status pelacakan pengiriman (Delivery Order) ke antarmuka pembeli B2B saat barang berpindah status (Processing -> In-Transit -> Delivered -> Completed). - **Filter Toko/Outlet Multi-Cabang** (`9dddca4`): Penambahan filter toko pada halaman Packing Order dan Sales Order untuk kemudahan pemantauan multi-outlet. - **Validasi Gudang & Toko Aktif** (`95f28ae`, `4c32cad`): Kueri inventori dibatasi secara ketat hanya pada gudang aktif di bawah toko/cabang yang aktif beroperasi. ## [1.2.0] — 2026-10-26 ### Ringkasan Rilis Integritas transaksi POS, pergerakan stok, checkout B2B, dan siklus transfer fisik dengan transit serta voucher persisten. Rilis ini juga mencakup perbaikan rincian shift, tiket bantuan, notifikasi mendesak, dan label versi login dari empat commit setelah bump 1.1.0: `7d67730`, `771105d`, `3bad1e8`, dan `c9f9ef2`. Tanggal rilis dokumentasi bukan konfirmasi deployment produksi. ### Ditambahkan (Added) - **Siklus Transfer Fisik** (`c9f9ef2`): Draft tanpa mutasi stok, pengiriman ke transit persisten, voucher snapshot unik, penerimaan baik/rusak/parsial, dan rekonsiliasi kehilangan berotorisasi dengan audit (migration `000135`). Cetak ulang voucher bersifat baca-saja. - **Bukti Transaksi PostgreSQL** (`c9f9ef2`): Regression kas Rp8.000, selisih/override, penutupan bersamaan, receipt pembelian, checkout/retry/rollback, transfer normal/parsial/konkurensi, dan kegagalan atomik. Bukti tersebut berasal dari pengujian lokal terisolasi, bukan produksi. ### Diperbaiki (Fixed) - **Kas Shift POS** (`3bad1e8`, `c9f9ef2`): Rincian penutupan dan detail shift menampilkan komponen kas serta selisih. Ringkasan dan detail membaca ledger persisten yang sama; kas non-tunai dan order batal tidak menambah laci, refund tunai mengurangi tepat sekali. Penutupan normal berselisih ditolak; override admin/owner wajib alasan dan audit. Guard database menolak perubahan finansial pada shift tertutup (migration `000134`). - **Stock Movements** (`c9f9ef2`): Penerimaan pembelian dan pembatalan penjualan menghasilkan movement atomik; arah opname berasal dari perubahan saldo. Filter gudang fail-closed dan total mencakup seluruh hasil, bukan satu halaman. Retry manual/receipt memakai bukti persisten (migration `000136`); opsi mati `LOG_GR_MOVEMENTS` dihapus. - **Checkout B2B** (`c9f9ef2`): Validasi harga/minimum/stok menghasilkan error bisnis yang aman; kegagalan refresh histori atau inisialisasi pembayaran sesudah commit tidak lagi menyamar sebagai checkout gagal. Cart terkunci dan bukti checkout persisten mencegah pesanan ganda saat retry (migration `000137`). Form dan keranjang dipertahankan saat validasi gagal. - **Tiket Bantuan & Notifikasi** (`771105d`): Detail tiket tersedia pada tabel/modal ERP, perbaikan tampilan detail tiket dan dukungan hak kelola melalui migration `000133`, serta peringatan suara untuk tiket mendesak. ### Ditingkatkan (Improvements) - **Label Versi Login** (`7d67730`): Menambahkan label versi pada halaman login ERP dan POS; commit asal menampilkan v1.1.0. Versi platform dan catatan rilis bersama kini diselaraskan ke 1.2.0 di ERP, POS, dan B2B. ### Diketahui (Known Limitations) - Riwayat movement pembelian yang dahulu tidak dicatat tidak direkonstruksi otomatis. Transfer lama yang sudah dikirim tanpa model transit baru memerlukan rekonsiliasi berbasis bukti; saldo historis tidak diubah oleh migrasi. - Voucher pengiriman membutuhkan identitas perusahaan yang tersimpan pada konfigurasi; barang rusak dicatat terpisah pada dokumen transfer dan tidak menambah stok siap jual. - Integrasi posting GL yang belum diaktifkan dan kebijakan koreksi lintas periode tetap mengikuti batasan akuntansi pada rilis 1.1.0. ## [1.1.0] — 2026-10-24 ### Ringkasan Rilis Pembaruan komprehensif tata kelola keuangan (*financial closing lifecycle* & *reversal integrity*), sistem dashboard personal berbasis peran (*role-based dynamic widgets*) dengan modal popup rincian interaktif di seluruh 14 widget, standarisasi presisi rumus konversi pelanggan (Active Outlet / AO), isolasi hak akses lintas aplikasi (ERP, POS, B2B), kecepatan transaksi kasir *walk-in*, dan pusat tiket bantuan terpadu. ### Ditambahkan (Added) - **Tutup Buku Keuangan**: Siklus hidup periode pembukuan (`open`, `locked`, `reopened`) dengan snapshot data permanen tak terubahkan (*immutable close snapshot*), validasi keseimbangan debit-kredit & kas, dan pembukaan kembali periode berizin khusus (`accounting.periods.reopen`) wajib mengisi justifikasi bisnis minimal 10 karakter dengan riwayat terekam di `accounting_period_logs`. - **Isolasi Hak Akses 3 Aplikasi**: Penegakan batasan hak akses akun (*access isolation*) fail-closed di backend (`RequireApp`) dan route guard frontend sehingga akun ERP hanya dapat mengakses ERP kantor, akun POS hanya untuk kasir, dan akun mitra toko hanya untuk portal B2B. - **Filter Piutang & Pembayaran**: Penambahan filter nama Toko / Pelanggan di posisi utama tabel pada modul Piutang dan Pembayaran (`/sales/receivables`). - **Dashboard Berbasis Peran (16 Role)**: Kebijakan widget default terkurasi untuk 16 jabatan/role bawaan dengan penyimpanan persisten di `app_settings` dan menu kustomisasi yang dipindahkan ke menu Pengaturan Sistem di sidebar. - **14 Modal Popup Rincian Widget**: Seluruh 14 widget dan kartu angka di dashboard kini interaktif (*clickable*) untuk membuka jendela popup rincian data operasional (*drill-down analysis*). - **Perhitungan Standar Active Outlet (AO)**: Standarisasi rumus konversi pelanggan `(Pelanggan Order / Total Pelanggan) * 100%` dengan floating-point division tanpa pemotongan integer, penanganan pembagian nol yang aman, dan pembulatan standar 2 desimal (`2,74%`) bersih dari glitch spasi. - **Kasir Cepat Walk-in & Stok Fleksibel**: Dukungan checkout instan pelanggan umum tanpa registrasi pelanggan dan transaksi tetap dapat dilayani tanpa terhalang sinkronisasi data stok. - **Support Ticketing System**: Integrasi pengiriman tiket bantuan kendala teknis langsung dari dalam aplikasi di ERP, POS, dan B2B. ### Diperbaiki (Fixed) - **Integritas Reversal Jurnal**: Jurnal posted tidak dapat divoid secara sembarangan, koreksi wajib melalui jurnal pembalik berpasangan dengan akun yang sama dan debit-kredit terbalik tepat (migration `000128`). - **Pencegahan Jurnal Ganda**: Otomatis mendeteksi dan mencegah pencatatan berulang pada transaksi penerimaan barang supplier dan penggajian karyawan. - **Notifikasi Login Kasir POS**: Perbaikan teks notifikasi penolakan login saat akun kantor non-kasir mencoba mengakses POS. ### Rincian Teknis & Referensi Commit - **Kontrol Reversal Jurnal** (`21863e5`): Migration `000128` memeriksa pasangan reversal historis sebelum menambahkan constraint unik dan guard database untuk jurnal posted serta barisnya. Reversal wajib terhubung dengan akun/departemen yang sama dan debit-kredit yang dibalik tepat; endpoint void jurnal posted menjawab `409 Conflict`. - **Bukti & Mapping Akuntansi** (`ff5078d`, `55e1dfb`, `fb4b744`, `21863e5`): Dokumentasi mapping akun, pengujian PostgreSQL reversal/imutabilitas jurnal, dan validasi tutup buku memakai GL kanonis dengan penolakan jurnal draft/tidak seimbang serta pengujian posting-vs-close dan close-vs-close. Ini rincian rilis 1.1.0 yang sebelumnya masih tercantum di Unreleased. - **Riwayat CI yang Dibatalkan**: Dual-tag alias legacy GHCR pada `0f887c8` dibatalkan oleh `d59dd5b`; tidak dicatat sebagai fitur aktif. Seluruh commit lainnya beserta subjek asli tersedia pada ledger lengkap. ### Diketahui (Known Limitations) - Posting GL untuk POS, pembayaran invoice, settlement gateway, retur, dan HPP belum diaktifkan. Mapping akun dan kebijakan bisnis terkait belum disetujui. - Reversal atas jurnal di periode tertutup tetap ditolak oleh period guard; kebijakan koreksi lintas periode belum diputuskan. ## [1.0.0] — 2026-10-17 ### Ringkasan Rilis Rilis besar migrasi arsitektur polyrepo menjadi **Unified Monorepo** (pnpm workspaces v12 + Turborepo v2), peluncuran paket sistem desain bersama `@keluargamart/ui`, audit dan perbaikan total 100% reliabilitas icon, pengenalan modul tiket kendala terpusat, serta optimasi produksi Hostinger KVM 2. ### Ditambahkan (Added) - **Unified Monorepo**: Mengintegrasikan `apps/backend`, `apps/erp`, `apps/pos`, `apps/b2b`, dan `apps/nextreport` di bawah satu repositori monorepo. - **Design System (`@keluargamart/ui`)**: Paket shared token warna, tipografi font IBM Plex, dan komponen atomik (`KButton`, `KBadge`, `KCard`, `KModal`, `KSkeleton`, `KEmptyState`, `KAlert`, `KSpinner`). - **Support Ticketing System**: Modul pelaporan tiket kendala/bug terpusat dengan schema migrasi database backend (`tickets` & `ticket_comments`), RBAC permissions (`tickets.create`, `tickets.view`, `tickets.manage`, `tickets.assign`), dashboard manajemen tiket di ERP, modal pelaporan cepat di POS, dan portal bantuan di B2B. - **Changelog & About**: Halaman catatan rilis dan dialog informasi sistem pengembang yang terintegrasi di seluruh aplikasi client. - **Icon Audit Automation**: Skrip otomasi `scripts/audit-icons.mjs` (`pnpm audit:icons`) untuk memvalidasi ketersediaan seluruh icon Phosphor dan Lucide secara presisi. ### Diperbaiki (Fixed) - **Lucide Icons**: Memperbaiki 33 referensi icon Lucide yang usang/berganti nama pada `apps/b2b` (seperti `building-2` → `building`, `check-circle-2` → `circle-check`, `alert-triangle` → `triangle-alert`, `trash-2` → `trash`, `x-circle` → `circle-x`). - **POS AppIcon Registry**: Memvalidasi seluruh registry semantic alias Phosphor pada POS sehingga tidak ada peringatan icon hilang saat runtime. - **Resource Bounds**: Pengetatan batas alokasi memori pada Hostinger KVM 2 (`GOMEMLIMIT=512MiB`, Node `max-old-space-size=256MB`) untuk menjaga stabilitas VPS berkapasitas 2 vCPU / 8 GB RAM. --- ## [0.9.0] — 2026-09-28 ### Ringkasan Rilis Fokus pada keandalan operasional kasir toko (POS) dengan offline-first caching, integrasi scanner barcode WASM berkecepatan tinggi, dan rekonsiliasi kas shift. ### Ditambahkan (Added) - **POS Offline Indexing**: Penyimpanan lokal katalog produk dan harga bertingkat pada browser IndexedDB. - **Barcode Engine**: Integrasi ZXing-WASM untuk deteksi barcode instan via kamera maupun scanner barcode fisik USB. - **Shift & Cash Drawer**: Pencatatan saldo awal, transaksi kas keluar/masuk, dan verifikasi saldo akhir shift kasir. ### Diperbaiki (Fixed) - **Idempotency Safeguard**: Implementasi token idempotensi pada endpoint checkout kasir untuk mencegah duplikasi order saat koneksi jaringan tidak stabil. --- ## [0.8.0] — 2026-09-05 ### Ringkasan Rilis Penyempurnaan tata kelola multi-gudang ERP, kartu stok persediaan, pencatatan jurnal akuntansi otomatis, dan kontrol akses berbasis peran (RBAC). ### Ditambahkan (Added) - **Multi-Warehouse Stock**: Alokasi stok terpisah per gudang dan transfer antar outlet/gudang dengan surat jalan. - **Automated Financial Journaling**: Pembuatan jurnal entri otomatis saat transaksi penjualan, pembelian, retur, dan penyesuaian opname persediaan. - **Role-Based Access Control**: 198 permission terdefinisi secara katalogik di backend Go (`catalog.go`). --- ## [0.7.0] — 2026-08-15 ### Ringkasan Rilis Peluncuran platform grosir B2B berbasis Nuxt 4 (SSR/Nitro) untuk melayani pesanan dari mitra toko kelontong. ### Ditambahkan (Added) - **Wholesale Price Tiers**: Penetapan harga khusus grosir berdasarkan volume kuantiti belanja mitra. - **Order Tracking & Tempo**: Manajemen termin pembayaran (tempo/kredit) dan pelacakan status armada pengiriman.