Pesanan mengalir dua arah melalui backend-go. Inbound dari WhatsApp gateway via webhook callback_message. Outbound dari handler Go menulis ke chat_outbox, lalu Node engine mengirim ke WA gateway.
Inbound — POST /v1/callback_message
Dipanggil oleh WhatsApp gateway :5002 setiap pesan masuk. Handler: handlers/chat_callback.go:89 CallbackMessage.
WA gateway :5002
│ POST /v1/callback_message
▼
CallbackMessage (chat_callback.go:89)
│
├─ 1. Parse body → Payload
├─ 2. Resolve device via InstanceID (GetDevice)
├─ 3. Branch: Result==true && Report==false (inbound, bukan status)
│ └─ Extract pesan, split number@server
│ ├─ s.whatsapp.net → private chat
│ └─ g.us → group chat
├─ 4. Categorize (private/group) + auto-create group doc
├─ 5. Auto-create customer (GetCustomer → CreateCustomer)
├─ 6. First-chat / new-chat detection
│ └─ isonnew = true jika chatList nil/new/close/pending
├─ 7. CS rotator dispatch (chat_callback.go:305)
│ └─ h.svc.GetRotator(ctx, device.StoreId, instance) → returnid_cs
├─ 8. Update chat_history dengan CS terpilih
├─ 9. Build & save ChatList (create atau update)
├─ 10. Save inbound ke chat_inbox (chat_callback.go:529)
│ └─ CreateChatInbox(newChatInbox)
└─ 11. Bot dispatch (goroutine, chat_callback.go:549-561)
└─ if HandleByBot && !is_start && !fromMe:
go submitBot(newChatInbox) → createOutboxBotBot dispatch — chatbot engine
submitBot (chat_callback.go:1357) memanggil chatbot engine:
| Endpoint | URL | Fungsi |
|---|---|---|
| Chatbot reply | EngineBot + "api/chatbot-api" (:1637) | Kirim context + dapatkan reply |
| Instruction/QnA | EngineBot + "api/question" (:1763) | Question dispatch |
Bot dispatch dijalankan dalam goroutine — non-blocking. Reply dari bot ditulis ke chat_outbox via createOutboxBot, lalu Node engine mengirim ke WA gateway.
Outbound — chat_outbox + Node engine
Handler Go tidak langsung memanggil WA gateway. Ia menulis row ke chat_outbox, lalu Node engine memproses.
Handler (mis. SubmitMessage)
│
├─ saveMessageMongo (chat_submit.go:425)
│ ├─ Loop per phone number:
│ │ ├─ CreateChatInbox (chat_submit.go:815) — simpan ke chat_inbox dulu
│ │ └─ CreateChatOutbox (chat_submit.go:856) — simpan ke chat_outbox
│ └─ Return resultChatData, chatInboxList
│
▼
chat_outbox collection (MongoDB)
│
▼
Node engine (terpisah, PM2)
├─ cron_message/dispatcher.js — watch change stream (beta devices)
│ └─ Enqueue ke Redis BullMQ queue (per-device)
└─ cron_mdv2.js — poll chat_outbox (legacy devices)
│
▼
worker_message.js (BullMQ consumer)
├─ get_result_data.js — enrich payload
└─ POST :5002 (WA gateway)
│
▼
On success:
├─ chat_inbox.status_ack = "sent"
└─ delete chat_outbox rowField yang ditulis ke chat_outbox
chat_submit.go:820-844 — ChatOutboxStruct:
| Field | Sumber | Catatan |
|---|---|---|
ID | uuid | Primary key |
Pesan | payload | Konten pesan |
Nohp | normalized phone | Format +62… |
Waktu | time.Now() atau payload | Timestamp |
Jenis | "keluar" | Outbound marker |
Instance | device instance | |
Tipe | messageType | text/image/video/document/audio/link/location |
Caption | payload | Untuk media |
StatusAck | "pending" | Akan diupdate Node engine |
IdUser, IdCs | context | |
Jalur | "API" | Via API (vs manual) |
InboxID | chatInbox.ID | Link ke chat_inbox row |
PesanId, Noted, TempId | conditional | Override dari payload |
Dua mode pengiriman
| Mode | Trigger | Mechanism |
|---|---|---|
| Beta devices | chat_outbox insert | MongoDB change stream → dispatcher.js → BullMQ → worker_message.js |
| Legacy devices | polling | cron_mdv2.js poll chat_outbox per tick → POST :5002 |
Tenant variants
Pola yang sama berlaku untuk _admin dan _crm:
| Tenant | Handler inbound | Handler outbound | Outbox write |
|---|---|---|---|
| default | chat_callback.go:CallbackMessage | chat_submit.go:saveMessageMongo | CreateChatOutbox |
| admin | chat_callback_admin.go:CallbackMessageAdmin | chat_submit_admin.go:saveMessageMongoAdmin | CreateChatInboxAdmin (admin_chat_inbox) |
| crm | chat_callback_crm.go:CallbackMessageCrm | chat_submit_crm.go:saveMessageMongoCrm | CreateChatInboxCrm (CRM chat_inbox) |
Status ACK lifecycle
Field chat_inbox.status_ack melacak status pengiriman:
| Nilai | Arti | Setter |
|---|---|---|
pending | Menunggu dikirim | Handler Go (saat insert) |
sent | Berhasil terkirim | Node engine (setelah WA gateway confirm) |
error | Gagal | Handler Go (express mode) atau Node engine |
Shared collections — kontrak implisit
Go API dan Node engine berbagi koleksi tanpa schema validation:
| Koleksi | Go menulis | Node membaca | Node menulis |
|---|---|---|---|
chat_outbox | ✅ insert | ✅ poll/change stream | ❌ |
chat_inbox | ✅ insert (inbound + outbound row) | — | ✅ update status_ack |
chat_list | ✅ | — | ✅ update-chatlist via WA gateway |
Langkah berikutnya
- Cara CS dipilih? Baca CS Rotator.
- Cara broadcast mengirim? Baca Broadcast Scheduler.