Lewati ke konten utama

Ringkasan Perubahan Alur

Bagian ini menjawab satu pertanyaan: alur lamanya seperti apa, dan sekarang jadi seperti apa?

Setiap halaman di bawah menyajikan tiga hal:

  1. Diagram alur lama
  2. Diagram alur baru
  3. Kenapa diubah, dan konsekuensi yang diterima
Alur lama tidak dihapus dari dokumen

Sesuai permintaan, alur lama tetap didokumentasikan apa adanya. Ini penting untuk memahami data historis, membaca log lama, dan mengerti kenapa beberapa kolom/tabel ada.


Tujuh perubahan besar

#PerubahanDariMenjadiDetail
1BookingAI langsung membuat janji temu, gratisDraft berbayar → janji temu setelah lunasBaca
2Konfirmasi pembayaranDikirim langsung dari service pembayaranEvent ReservationPaid → listener → notifier terpusat + sapuan 5 menitBaca
3Chat RoomsMembaca store lokal hasil webhookLive proxy ke ChatPanel JasnitaBaca
4Sinkronisasi kontakHanya tombol manualReal-time via webhook + sapuan 10 menit + riwayat lintasanBaca
5SIMRS SyncSatu lintasan penuh; gagal = ulang dari nolCursor checkpoint per chunk; dilanjutkan otomatisBaca
6Pemegang percakapanSemua percakapan tampak dipegang AI; balasan agen tidak dicatatAtribusi sent_by, inferensi pemegang, takeover eksplisit, labelBaca
7Akun WhatsAppBisa dihapusHanya bisa diaktifkan/dinonaktifkanLihat di bawah

Perubahan yang lebih kecil tapi penting

Tool allowlist: dari "tidak diiklankan" jadi ditegakkan

Kenapa mendesak: dulu create_appointment yang dihalusinasikan hanya membuat satu janji temu gratis — tidak berbahaya. Setelah booking jadi berbayar, tool yang sama menerbitkan invoice Duitku sungguhan. Model yang menyebut nama tool tak diiklankan (halusinasi, riwayat dari konfigurasi lama, atau prompt injection) berarti pasien ditagih untuk booking yang tak pernah ia minta.

Penjagaannya diletakkan di kelas yang memiliki allowlist-nya, bukan disalin ke dua pemanggil — aturan yang disalin ke dua tempat adalah persis cara celah itu lahir.

payment_url: dari tidak disimpan jadi disimpan

Bonus: link juga tersimpan seandainya balasan AI yang membawanya gagal terkirim (LLM error setelah tool berjalan, batas iterasi tool tercapai, atau gelembung pesan gagal). Tanpa salinan itu, invoice Duitku hidup sementara pasien tidak memegang apa pun — lalu menerima pemberitahuan kedaluwarsa untuk link yang tak pernah ia terima.

Penjagaan callback: dari "terminal" jadi "verdict-aware"

Prinsipnya: Expired hanyalah tebakan lokal kami, bukan fakta. Duitku yang tahu kenyataannya.

Callback Duitku: dibaca di dalam transaksi + terkunci

Dulu baris Payment dibaca di luar transaksi mana pun, sehingga dua callback bersamaan untuk satu order bisa sama-sama membaca Pending, sama-sama lolos penjagaan, dan sama-sama memancarkan ReservationPaid. Untuk booking berdraft, lockForUpdate() milik confirmPaid() masih menyelamatkannya — tapi untuk pembayaran tanpa draft (reservasi manual dari Chat Rooms), tidak ada penjagaan sama sekali: pasien menerima dua pesan dan dua baris WhatsappMessage.

Sekarang pembacaan, penjagaan, dan penulisan berada dalam satu transaksi dengan lockForUpdate().

Hapus akun WhatsApp → tombol aktif/nonaktif

Akun nonaktif memang sudah dilewati sebagai pengirim (ChatRoomService dan ChatPanelService mengambil baris is_active pertama). Penghapusan ditutup di level resource (canDelete()/canDeleteAny() mengembalikan false), bukan sekadar tombolnya dilepas — supaya aksinya tidak bisa kembali hanya dengan pemberian izin Shield.

Perubahan serupa juga diterapkan pada panel Kontak: tombol hapus dilepas.

Whitelist balasan AI untuk testing

Fitur baru, bukan penggantian: WHATSAPP_TEST_MODE sebagai saklar global, plus kolom "Whitelist Balasan AI" per akun. Saat testing, hanya nomor tester yang dibalas AI dan setiap pesan keluar dialihkan ke nomor tester — supaya pasien asli tidak pernah menerima apa pun. Detail di WhatsApp & AI.

Chat Rooms: pemuatan data ditunda

Dulu data ditarik saat render pertama sehingga halaman memblokir menunggu API Jasnita — agen melihat layar kosong beberapa detik. Sekarang kerangka halaman tampil instan lewat wire:init, data menyusul, dengan status loading dan auto-scroll ke pesan terbaru.

Kontak: ekspor Excel

Fitur baru di halaman Kontak untuk mengekspor daftar kontak ke berkas Excel.


Kolom & tabel yang lahir dari perubahan ini

Kalau Anda membaca skema database dan bertanya "kolom ini untuk apa":

Kolom / TabelLahir dari perubahan
booking_requests (seluruh tabel)Booking gratis → berbayar
booking_requests.payment_urlKehilangan link tidak boleh berarti tagihan kedua
booking_requests.whatsapp_account_idKonfirmasi harus kembali lewat akun percakapan yang sama
booking_requests.expires_atSapuan kedaluwarsa
sync_states.cursorSIMRS Sync resumable
contact_sync_runs (seluruh tabel)"Sinkron otomatis" harus bisa dibedakan dari "sinkron otomatis yang diam-diam mati"
whatsapp_business_accounts.ai_reply_whitelistMode testing
whatsapp_business_accounts.gateway_* (OAuth)Integrasi Jasnita Toschat
contacts.assigned_user_idAssign/Transfer di Chat Rooms
contacts.handled_byTakeover eksplisit — memblokir auto-reply AI
whatsapp_messages.media_*Kirim/terima media di Chat Rooms
whatsapp_messages.sent_by / sent_by_user_idMembedakan balasan AI dari balasan agen
chat_labels + chat_label_contactLabel percakapan buatan tim
ai_token_usagesPencatatan pemakaian token per balasan
ai_agents.knowledge_files*Ekstraksi PDF/gambar jadi knowledge
ai_agents.llm_last_usage_snapshot / llm_last_probe_snapshotMonitoring LLM di UI