# BUGSWEEP REPORT — RONDE 4: B2B LIVE (2026-10-01) Lanjutan `BUGSWEEP_REPORT_R3.md`. Live E2E storefront B2B: frontend = `localhost:3000` (= origin/main via `nuxt dev`), backend = live dev (`api-km.trl.my.id`), buyer demo `buyer@keluargamart.local`. Semua write diizinkan (host DEV, banner amber terverifikasi). ## 1. Verifikasi fitur yang berjalan (bukti live) | # | Skenario | Hasil | |---|---|---| | 1 | Search suggestion: ketik "indomie" | ✅ dropdown terbuka, 2 hit dengan thumbnail + SKU + harga, footer "Lihat semua hasil" | | 2 | Modal lokasi: resolved hub row + daftar manual | ✅ "Kota Binjai (Hub …)", collapsed 0 → expand 9 area | | 3 | Pilih alamat Medan → gudang re-resolve | ✅ localStorage `WH-KM-PLM` (Plasamas), chip tetap "Alamat Utama · Medan" | | 4 | Checkout: kartu gudang read-only + "Ubah" | ✅ "KeluargaMart Plasamas - Gudang", alamat tersimpan terpilih otomatis | | 5 | Harga member tampil | ✅ Subtotal 3.500, "Hemat member −Rp 280", total 3.220 | | 6 | Place order COD | ✅ SO-202610-000039 dibuat, halaman konfirmasi + instruksi bayar tunai | | 7 | Tab pesanan | ✅ Semua/Menunggu/Diproses/Selesai, order baru muncul | | 8 | Halaman galon: harga tampil vs tagih | ✅ hanya Rp 8.000 (harga sebenarnya); phantom 0.35× (P1 #22 ronde 1) tidak muncul di main terkini | ## 2. Temuan baru ### R4-1 — P1 — Refresh halaman kadang "logout" sendiri (sesi persist kosong-token, intermiten) **Gejala (repro 2×):** setelah sesi SPA yang normal (order sukses, API 200 terus), hard refresh membuat state kembali logged-out; ditemukan `keluargamart.session` bertahan di localStorage **dengan `token: ""`** (atau hilang sama sekali), padahal sesi SPA berjalan normal dengan token valid. **Dampak:** refresh = logout + data hilang; alur pembayaran yang me-reload halaman bisa terputus. **Akar (belum sepenuhnya terkunci):** penulis satu-satunya session ber-token kosong adalah `me()` di `app/composables/useAuth.ts` (fallback `token: session.value?.token || tokenCookie.value || ''`) — berarti pernah berjalan saat session/cookie kosong namun `/auth/me` tetap sukses; dan/atau `repos.auth.login` sesekali mengembalikan session tanpa token (envelope salah baca / respons parsial). Trace `localStorage.setItem` yang dipatch menunjukkan login bersih menulis 2× dengan token valid — bug-nya intermiten. **Instrumen untuk root-cause (tempel di console sebelum login):** ```js window.__trace = [] const os = Storage.prototype.setItem Storage.prototype.setItem = function (k, v) { if (/keluargamart.session/.test(k)) { let tok = null try { const p = JSON.parse(v); tok = p?.token ? p.token.slice(0, 6) : 'EMPTY' } catch { tok = 'PARSE_FAIL' } window.__trace.push({ op: 'set', tok, stack: new Error().stack?.split('\n').slice(2, 6).join(' > ') }) } return os.call(this, k, v) } ``` **STATUS: SUDAH DIPERBAIKI (root cause terkunci).** Akarnya: `restore()` (client) hanya me-hydrate token ketika `session.value === null`, tetapi setelah hard reload `session.value` SUDAH terisi oleh SSR seed (`plugins/session.ts` membaca cookie `km_auth_token` → `GET /auth/me` → payload useState). Akibatnya restore() melewati `setAuthToken` di sisi client — modul HTTP client tidak punya token — lalu tetap memanggil `me()` header-less → 401 → handler 401-nya **menghapus sesi localStorage yang valid**. (Trace: login bersih menulis 2× token valid; state rusak muncul setelah reload, bukan setelah login.) Fix (`app/composables/useAuth.ts`): 1. `restore()` kini selalu me-attach ulang token terbaru ke modul HTTP sebelum revalidasi (prioritas: session → localStorage → cookie). 2. `me()` tidak pernah lagi mem-persist sesi tanpa token (fallback `getAuthToken()` + skip persist bila token kosong) — artefak `token: ""` tidak mungkin tercipta lagi. Terverifikasi live: login → hard reload `/account/orders` → tetap login, token persist, daftar pesanan tampil. Suite 169/169, `nuxt build` + typecheck bersih. ### R4-2 — P1 (environment) — b2b-km.trl.my.id menjalankan bundle yang tidak sama dengan origin/main **Gejala:** kartu katalog di host dev menampilkan tombol `aria-label="Tambah"` (add-to-cart langsung di kartu). String tersebut TIDAK ADA di seluruh `origin/main` (`AppProductCard.vue` adalah kartu display-only → PDP). Klik tombol itu tidak menghasilkan POST /cart apa pun. **Dampak:** sweep fungsional terhadap host dev tidak mewakili main; klik-klik di UI dev menyesatkan QA. **STATUS TERBUKA (ops):** host perlu `docker compose pull` + `up -d` untuk frontend B2B — catatan: host tidak auto-pull; semua deploy selama ini manual di VPS. ### R4-3 — P3 — `GET /auth/me` mengembalikan 401 dengan token dari cookie `km_auth_token` Tertangkap saat R4-1: cookie berisi token yang sudah tidak valid, sementara token valid ada di memori. Penyebab utama mengikuti R4-1; dicatat sebagai data point (cookie ditulis `useCookie` saat login/me, tidak diperbarui saat token di-refresh memori). ## 3. Jejak QA - Order SO-202610-000039 (COD, Indomie 1× Rp 3.220) — penjualan valid, dibiarkan. - Tidak ada produk/kategori/pelanggan baru dibuat; shift tidak disentuh. ## 4. Belum dites / lanjutan - QRIS end-to-end (Midtrans sandbox) — walk-in QRIS kini lolos guard client setelah fix sentinel R3-4b; perlu sandbox untuk menyelesaikan. - Retur B2B end-to-end (butuh order delivered/invoiced). - Sesi debug R4-1 dengan instrumen di atas. - Backlog: R2 + P1/P2 ronde 1 (BUGSWEEP_REPORT.md urutan fix item 7).