specs / 027-Changes-Datamart-Sync-Hardening

027 - Datamart sync hardening + kesiapan multi-bisnis

  • Tanggal: 2026-08-12
  • Chat/topik: Perbaikan titik rawan ksr-sync (soft/hard delete, orphan, timestamp kembar), omzet per cabang, metrik mpc-owner, dokumentasi multi-bisnis.

Ringkasan perubahan

  • ksr-sync v0.4: cursor watermark komposit (timestamp ms, id); drain loop per entitas (dimensi habis dulu baru fact); pass soft-delete per entitas; GC hard-delete tiap putaran; booking non-visit-status dihapus dari fact_visit; fact_transaction.branch_id diisi via transaction_itemsbookingscourts; script npm run reconcile (count + SUM mpcdb vs ksrdb, exit 1 jika selisih).
  • mpc-owner v0.5: filter omzet pakai paidAt (index + semantik bayar); getVisitsByWeekday pakai zona Asia/Jakarta.
  • README ksr-sync: cara kerja sync + panduan menambah bisnis baru (multi-industry). Connector non-mpcdb dan business switcher dashboard sengaja ditunda sampai ada kebutuhan nyata.

Impact bisnis

Angka dashboard owner kini bisa dipercaya: transaksi yang dibatalkan/dihapus (soft maupun hard delete) tidak lagi terhitung omzet; booking cancelled tidak terhitung kunjungan; metrik per pelanggan tidak kehilangan tautan saat backfill. Omzet per cabang jadi mungkin (kolom terisi). Rekonsiliasi memberi deteksi dini drift data. Fondasi multi-bisnis (padel + resto + ballroom + cafe dalam satu dashboard) terdokumentasi.

Epic / User stories

  • Epic: Datamart ksrdb yang akurat dan siap multi-bisnis.
  • US: Sebagai owner, saya ingin angka omzet/kunjungan di dashboard mencerminkan data operasional terkini (termasuk pembatalan/penghapusan), agar keputusan bisnis tidak berdasar angka basi.
  • US: Sebagai operator sistem, saya ingin alat rekonsiliasi otomatis, agar drift antara mpcdb dan ksrdb terdeteksi tanpa audit manual.

User terdampak

Owner (dashboard mpc-owner), operator sistem (worker sync).

Aplikasi terdampak

  • ksr-sync: PERLU — semua perbaikan sync di atas (v0.4).
  • mpc-owner: PERLU — filter paidAt + timezone weekday (v0.5).
  • mpc-be: TIDAK — hanya dibaca (read-only query tambahan ke mpcdb).
  • mpc-be-pos: TIDAK — tidak tersentuh.
  • mpc-admin: TIDAK — tidak tersentuh.
  • mpc-android / mpc-ios / mpc-web: TIDAK — bukan domain member.
  • mpc-pos: TIDAK — tidak tersentuh.

Perubahan schema

Tidak ada. Kolom fact_transaction.branch_id sudah ada di schema ksrdb; format cursor baru tetap di kolom string sync_watermark.cursor (mundur-kompatibel dengan cursor lama tanpa |).

Perubahan kode

  • ksr-sync/src/index.ts: rewrite — runCursorBatch (tuple comparison + date_trunc milidetik + penjaga cursor macet), drain(), pass purgeDeleted* per entitas, gcHardDeleted(), subquery branch attribution, status booking non-visit → delete fact_visit.
  • ksr-sync/src/reconcile.ts (baru) + script reconcile di package.json.
  • ksr-sync/README.md: cara kerja + panduan bisnis baru.
  • mpc-owner/src/lib/metrics.ts: filter/bucketing omzet ke paidAt (6 fungsi), weekday via localWeekdayIndex.
  • mpc-owner/src/lib/business-time.ts: helper localWeekdayIndex (WIB).

Catatan verifikasi

Dev DB: sync:once stabil (drain berhenti, tidak refetch); reset watermark bookings + transactions untuk backfill logika baru; reconcile menangkap 2 visit yatim (booking hard-deleted) → GC menghapusnya → semua cocok; branch_id terisi untuk semua transaksi ber-booking (F&B murni tetap kosong, by design); build mpc-owner sukses.