Broadcast mengirim pesan WhatsApp massal ke kontak. dazoapp hanya menyimpan konfigurasi & template — eksekusi sebenarnya ditangani backend Go (url_api). dazoapp tidak punya job/cron untuk broadcast.
Ringkasan alur
CONFIGURE (di dazoapp):
1. Buat BroadcastMessage (template: text + optional 1 file)
2. Buat BroadcastSceduler:
- pilih device (device.token = autentikasi ke engine WA)
- pilih message (BroadcastMessage.id)
- pilih target audience (all / select / order_product / order_status / tag / segment)
- set schedule (once / daily / range) + time
- set send_mode (slow / medium / fast)
EXECUTE (di backend Go):
Frontend POST {url_api}send_broadcast
→ payload: id_sceduler, token (device.token), numbers, message, send_mode, ...
→ Go call engine WhatsApp untuk kirim per nomor
→ Go return {result: true}
TRACK (di dazoapp):
BroadcastLog.status (bool: true=sukses, false=gagal)
→ Hanya 2 status. Tidak ada pending/delivered/read.
→ Tidak ada retry otomatis.1. Broadcast model
Tiga model terkait (semua MongoDB, UUID string PK):
BroadcastMessage — template pesan
app/Models/BroadcastMessage.php
| Field | Tipe | Catatan |
|---|---|---|
title | string | max 30 char |
message | array of object | Entry [0] = text, entry [1] = file (hanya 1 file per pesan) |
media_type / file_type | enum | text, images, video, file, default |
team_id | string | — |
store_id | string | Scope multi-tenant |
Struktur message entry:
[
{ "type": "text", "message": "Halo...", "original_name": null, "stored_name": null, "size": 0, "timestamp": "..." },
{ "type": "images", "message": "...", "original_name": "foto.jpg", "stored_name": "s3-key", "size": 102400, "timestamp": "..." }
]Validasi upload (BroadcastMessageStoreRequest.php:35-48):
- Image:
max:10240(10MB) - Video:
mimes:3gp,mp4 max:20480(20MB) - File:
mimes:txt,xls,xlsx,doc,docx,ppt,pptx,pdf max:20480(20MB)
Relasi: scheduler() hasMany BroadcastSceduler, log() hasMany BroadcastLog.
Ada duplicateBroadcast (BroadcastchatController.php:736-884) untuk duplikasi template (termasuk copy file S3).
BroadcastSceduler — jadwal broadcast
app/Models/BroadcastSceduler.php (catatan: nama model & controller typo “Sceduler”/“Scedular” — jangan perbaiki tanpa diminta).
| Field | Tipe | Catatan |
|---|---|---|
device | string (FK Device.id) | — |
message_id | string (FK BroadcastMessage.id) | — |
type | enum (cast SchedulerTypeCast) | once, everiday (daily), once-range, everidate (specific date), every-range |
mode | enum (BroadcastTarget) | Target audience — lihat §3 |
status | boolean | Active/inactive |
send_mode | enum (SendMode) | slow/medium/fast — lihat §4 |
is_filter | boolean | Filter tag tambahan untuk segment |
criteria | string | and/or/exclude — kombinasi tag |
broadcast_type | string | langsung (kirim segera) / jadwal |
start_date, end_date | string (Y-m-d) | Rentang tanggal |
status_start_date, status_end_date | string | Filter order status |
time | string (HH:mm:ss) | Waktu kirim |
contact_list, product_list, status_list, tag_list, segment_list | array | Target filter |
team_id, store_id | string | Scope |
onprogress | boolean | Sedang berjalan? |
last_execute_date, last_manualrun_date | datetime | Tracking |
use SoftDeletes aktif. retrieved event (:28-35): auto-set status=false jika data_device.sender atau message.id kosong — disable otomatis saat data tidak lengkap.
BroadcastLog — log pengiriman
app/Models/BroadcastLog.php. Table fisik: broadcast_submit_log (:19).
| Field | Tipe | Catatan |
|---|---|---|
store_id | string | Scope |
broadcast_id | string | FK BroadcastMessage |
id_sceduler | string | FK BroadcastSceduler |
customer_id | string | FK Customer |
status | boolean (cast) | true = sukses, false = gagal |
batch_id | string | UUID untuk group batch |
created_at | datetime | — |
2. Scheduling
Endpoint
| Route | Handler | Fungsi |
|---|---|---|
POST /api/broadcast/sceduler/save (:643) | storeScheduler (:898) | Create |
PUT /api/broadcast/sceduler/update/{id} (:645) | updateSceduler (:1005) | Update |
PATCH /api/broadcast/sceduler/change-status/{id} (:644) | changeStatus (:653) | Toggle active |
DELETE /api/broadcast/sceduler/delete/{id} (:651) | destroy | Delete |
Atur schedule
Tidak pakai cron expression. Pakai kombinasi field enum:
type(app/Enums/SchedulerType.php):once,everiday(daily),once-range,everidate(specific date),every-rangestart_date+end_date(stringY-m-d) +time(HH:mm:ss)broadcast_type:langsung(kirim segera) vsjadwal/lainnya
Job/cron di dazoapp
Dampak QUEUE_CONNECTION=sync
Tidak ada Job/Queue yang dipakai untuk broadcast di dazoapp. sync berarti job apapun (mis. UpdateChatlist, push-notif) berjalan sinkron dalam request. Untuk broadcast: tidak relevan karena eksekusi ada di sisi Go.
3. Execution
Job/Command yang memproses
TIDAK ADA di dazoapp. Frontend memanggil backend Go url_api + send_broadcast:
// resources/js/Pages/Broadcast/Schedular/SchedularCreate.vue:1342
const uri = `${livechatUri.value}send_broadcast`
// livechatUri = global.url_api (SchedularCreate.vue:541)Payload ke engine Go
Dari SchedularCreate.vue:1314-1334 & PenjadwalanBroadcastTab.vue:778-800:
id_broadcast, id_sceduler, token (device.token), numbers,
message (array), send_all (mode), is_filter, send_mode, criteria,
team_id, contact_list, product_list, status_list, tag_list,
segment_list, status_start_date, status_end_date,
running_mode: "broadcast_sceduler", batch_id (uuid)Target audience
app/Enums/BroadcastTarget.php:
| Mode | Deskripsi | Filter |
|---|---|---|
all | Semua customer | — |
select | Customer spesifik | contact_list individual |
order_product | Customer yang beli produk | product_list |
order_status | Customer dengan status order | status_list + status_start_date/status_end_date |
tag_customer | Customer dengan tag | tag_list + criteria (and/or/exclude) |
segment_customer | Customer di segmen | segment_list (+ optional filter tag via is_filter) |
Hitung recipient: POST /api/broadcast/sceduler/count-recipients (routes/api.php:647). Query: Customer where store_id, category='private', status != archive + filter tag/segment.
Cara pesan dikirim
Backend Go yang call engine WhatsApp url_engine. dazoapp TIDAK langsung call url_engine untuk kirim broadcast — hanya untuk cek device info (DeviceService.php:33).
4. Rate limiting
Via send_mode (app/Enums/SendMode.php):
| Mode | Delay per nomor |
|---|---|
slow | 60-120 detik |
medium | 10-30 detik |
fast | 3-8 detik |
Rate limit dikirim ke backend Go di payload (send_mode field), dieksekusi di sisi Go.
5. Status & tracking
Status per-pesan
BroadcastLog.status — boolean. true = sukses, false = gagal. Hanya 2 status — tidak ada pending/delivered/read di model.
Per-scheduler: logSukses & logError relation. Di UI: total_success_log, total_error_log, total_log (BroadcastscedularController.php:585-612). Deduplikasi log per customer_id (:582-583).
Endpoint cek status
| Endpoint | Fungsi |
|---|---|
GET /api/broadcast/sceduler | List scheduler + device status realtime + count log |
GET /api/broadcast/sceduler_paginate | List paginated |
GET /api/broadcast/show/{id} | Detail pesan + scheduler terkait |
GET /api/broadcast/log_statistic | Chart success/fail per tanggal (default 7 hari) |
GET /api/broadcast/kuotaBroadcastLog | Status kuota harian |
Retry untuk failed message
TIDAK DITEMUKAN mekanisme retry otomatis. BroadcastLog hanya catat status, tidak ada field retry_count/next_retry_at. Manual retry = user re-kirim lewat UI “Kirim Langsung” lagi.
6. Edge case
Cancel setelah start
Toggle status via PATCH /api/broadcast/sceduler/change-status/{id} — hanya enable/disable scheduler (tidak aktif = tidak dieksekusi cron di Go-side). TIDAK ADA cancel in-progress untuk batch yang sedang berjalan. Field onprogress ada di model, tapi tidak ada endpoint yang mengubahnya menjadi false untuk cancel. Kemungkinan onprogress diupdate oleh backend Go via callback (tidak ditemukan route callback-nya di routes/api.php).
Device disconnected saat broadcast berjalan
- Cek realtime status device tiap request listSceduler (
BroadcastscedularController.php:516-552) — callDeviceService::deviceInfo()ke engineurl_engine+api/device-info?instance={id} - Auto-disable scheduler di
retrievedevent (BroadcastSceduler.php:28-35): jikadata_device.senderataumessage.idkosong, setstatus=false - Di
listSceduler(:567-572): jikadata_device.sender/message.id/deviceIdkosong → auto-setstatus=false - Tidak ada handling untuk broadcast yang sudah mid-flight saat device disconnect — itu tanggung jawab backend Go
Limit jumlah pesan
- Kuota harian per store lewat
findAccessFeature($store->features, 'broadcast')(BroadcastchatController.php:900-928). HitungBroadcastLoghari ini grouped bybatch_id. Jikaquantity≤ current count →out_of_range - Limit ukuran file per pesan: image 10MB, video/file 20MB
- Title max 30 char, message_text max 5000 char
- Tidak ditemukan limit jumlah recipient per broadcast (selain kuota harian)
Referensi file
| File | Peran |
|---|---|
app/Models/BroadcastMessage.php | Template pesan |
app/Models/BroadcastSceduler.php | Jadwal + config (SoftDeletes) |
app/Models/BroadcastLog.php | Log pengiriman (table broadcast_submit_log) |
app/Http/Controllers/BroadcastscedularController.php | Endpoint scheduler |
app/Http/Controllers/BroadcastchatController.php | Endpoint message template |
app/Enums/SchedulerType.php | Schedule type enum |
app/Enums/BroadcastTarget.php | Target audience enum |
app/Enums/SendMode.php | Rate limiting enum |
resources/js/Pages/Broadcast/Schedular/SchedularCreate.vue | Frontend call ke Go |