Alur Sinkronisasi Kontak
Tabel contacts diisi dari dua jalur yang saling melengkapi.
| Jalur | Kecepatan | Menangkap apa |
|---|---|---|
| Real-time (webhook) | Seketika | Nomor yang mengirim pesan ke kami |
| Terjadwal (10 menit) | Lambat | Kontak yang dibuat langsung di ChatPanel Jasnita, dan nomor yang webhooknya terlewat saat aplikasi mati |
Jalur utama sudah real-time. Sapuan ini hanya jaring pengaman, dan ia memanggil API pihak ketiga — jadi kadensinya tidak perlu agresif.
Jalur 1 — Pencatatan real-time
Terjadi di dalam ProcessInboundWhatsappMessage, setelah pesan tersimpan dan sebelum AI membalas.
Kegagalannya tidak boleh menjatuhkan job: pesannya sudah tersimpan, balasan otomatis jauh lebih penting daripada satu baris kontak yang toh akan disusul sapuan.
Jalur 2 — Sapuan terjadwal
Perintah: contacts:sync · Jadwal: WHATSAPP_CONTACT_SYNC_CRON (default */10 * * * *), zona Asia/Jakarta, withoutOverlapping(), onOneServer()
Bisa dimatikan per-lingkungan lewat WHATSAPP_CONTACT_SYNC_ENABLED=false — karena ia memanggil API pihak ketiga dan mesin lokal tidak selalu ingin ikut menekan kuota.
Kalau lingkungan memang belum punya akun Jasnita aktif, command keluar dengan status sukses dan tidak mencatat lintasan. Kalau tidak, cron akan merah setiap sepuluh menit dan halaman Kontak akan penuh baris "gagal" yang tidak berarti apa-apa.
Batas pengaman
| Batas | Nilai | Alasan |
|---|---|---|
| Halaman maksimal | 200 | Berjaga bila last_page dari API tidak masuk akal |
| Baris per halaman | 500 | per_page dihormati Jasnita; limit tidak |
| Panjang nomor | 30 karakter | Kolom number adalah string(30) |
Satu halaman = satu transaksi
Kegagalan di tengah tidak menyisakan separuh data pada halaman itu.
Aturan upsert (dipakai kedua jalur)
Inilah bagian terpenting — dan aturannya identik di jalur real-time maupun terjadwal.
Yang TIDAK PERNAH ditimpa sinkronisasi
Jasnita hanya menyimpan identitas kontak (nomor, nama, channel). Status chat, agen penangan, dan timestamp percakapan dikelola CRM sendiri.
Nomor milik akun sendiri dilewati
Nomor WABA kita sendiri ikut muncul di daftar kontak Jasnita. Sistem membandingkannya dengan gateway_account_id dan whatsapp_business_number akun, lalu melewatinya.
Nama "placeholder"
Jasnita mengisi name dengan nomor itu sendiri kalau kontak belum pernah diberi nama. Begitu juga pushName WhatsApp. Karena itu:
| Nilai nama lokal | Dianggap placeholder? | Boleh ditimpa gateway? |
|---|---|---|
kosong / null | ✅ Ya | ✅ Ya |
6281234567890 (semua digit) | ✅ Ya | ✅ Ya |
Budi Santoso | ❌ Tidak | 🔒 Tidak |
Riwayat lintasan (ContactSyncRun)
Setiap lintasan dicatat — inilah yang membuat halaman Kontak bisa menampilkan kapan sinkron terakhir terjadi.
Tanpa riwayat ini, "sinkron otomatis" tidak bisa dibedakan dari "sinkron otomatis yang diam-diam mati". Halaman Kontak menampilkan waktu lintasan terakhir yang sudah selesai — sukses maupun gagal — supaya masalahnya terlihat.
Lintasan yang gagal tetap ditutup dengan finished_at, supaya halaman Kontak tidak menampilkan waktu sukses yang sudah basi.
Menjalankan manual
| Cara | Trigger tercatat |
|---|---|
Tombol di halaman Kontak (/admin/contacts) | manual + id user yang menekan |
php artisan contacts:sync | scheduled |
Output command: Sync kontak selesai: N baru, M diperbarui, K dilewati.
Ekspor kontak ke Excel
Halaman Kontak juga menyediakan ekspor daftar kontak ke berkas Excel (ContactExcelExporter). Berguna untuk pelaporan dan blast di luar sistem.
Konfigurasi
| Env | Fungsi | Default |
|---|---|---|
WHATSAPP_CONTACT_SYNC_ENABLED | Nyalakan/matikan sapuan terjadwal | true |
WHATSAPP_CONTACT_SYNC_CRON | Ekspresi cron | */10 * * * * |
Zona waktu selalu Asia/Jakarta.