| .. | ||
| client | ||
| domain | ||
| dto | ||
| entity | ||
| handler | ||
| migrations | ||
| repository | ||
| service | ||
| tests | ||
| transformer | ||
| validator | ||
| worker | ||
| .env.example | ||
| config.go | ||
| go.mod | ||
| go.sum | ||
| main.go | ||
| README.md | ||
omnix-broadcast
Collection broadcast worker: mengirim invoice via WhatsApp (Sopiga Collar API) ke nasabah Gadai Mulia.
Architecture
Gadai Collection Service
→ INSERT broadcast_staging (message_payload JSONB, status=pending)
→ BroadcastWorker (poll every 30s)
→ Query template_variable_mapping
→ Build message dynamically
→ POST Sopiga Collar API
→ status=dispatched (sopiga_recipient_detail_id disimpan)
→ DeliverySyncWorker (poll every 5 min)
→ GET recipient detail dari Sopiga
→ status=delivered (delivered_at diisi) atau status=failed
Tiga komponen jalan bersamaan (lihat main.go):
- BroadcastWorker (
worker/broadcast_worker.go) — pollpending, dispatch ke Sopiga. - Webhook receiver (
handler/webhook.go,POST /webhooks/sopiga/delivery-status) — jalur utama update status delivery. Begitu Omnix push callback, status langsung diupdate tanpa perlu polling balik ke Sopiga sama sekali. - DeliverySyncWorker (
worker/delivery_sync_worker.go) — polling fallback/backstop untuk recorddispatchedyang tidak kunjung dapat webhook (mis. delivery gagal terkirim/network hiccup di sisi Omnix). Karena webhook jadi jalur utama, interval ini bisa diperlonggar jauh lebih besar dari 5 menit tanpa menambah beban signifikan ke Omnix.
⚠️ Catatan: payload webhook di
dto/webhook.godan skema signature (X-Sopiga-Signature, HMAC-SHA256) masih asumsi kita sendiri — belum dikonfirmasi tim Omnix, karena endpoint registrasi callback tidak ditemukan di dokumentasi resmi (/docs?api-docs.yaml) saat implementasi ini dibuat. Sebelum pakai di production: (1) konfirmasi ke tim Omnix apakah mereka support outgoing webhook untuk status collar recipient, (2) minta format payload & skema signature asli mereka, (3) sesuaikandto/webhook.godanhandler/webhook.go, (4) daftarkan URL/webhooks/sopiga/delivery-statuske mereka.
Template baru cukup didaftarkan lewat database (sopiga_template_config +
template_variable_mapping + sopiga_collar_config) — tanpa redeploy kode.
Lihat docs/implementasi_guide.md dan
docs/quick_start.md untuk panduan lengkap.
Layers
| Layer | Responsibility |
|---|---|
worker/ |
Poller loop untuk dispatch + delivery sync fallback, fan-out ke concurrent processing |
handler/ |
WebhookHandler — HTTP receiver untuk callback status delivery dari Omnix |
transformer/ |
Entity ↔ Domain mapping, BuildDynamicMessage interpolasi template |
service/ |
Business logic: fetch pending/dispatched, validate, dispatch, sync delivery (polling & webhook), retry, mark failed |
repository/ |
Query broadcast_staging & template_variable_mapping, update status, lookup by recipient_detail_id |
client/ |
HTTP client ke Sopiga Collar API (add-recipient + get recipient detail) |
domain/ |
Broadcast, TemplateVariable |
entity/ |
DB row mapping |
dto/ |
Sopiga API request/response |
validator/ |
Validasi payload sebelum dispatch |
migrations/ |
Schema collection_broadcasts (tables, views, functions) |
Configuration (env vars)
| Var | Default |
|---|---|
DATABASE_DSN |
— |
DB_MAX_CONNS |
25 |
DB_MIN_CONNS |
5 |
SOPIGA_BASE_URL |
https://omnix.promas.site |
SOPIGA_TOKEN |
— |
WORKER_CHECK_INTERVAL_SEC |
30 |
WORKER_BATCH_SIZE |
100 |
WORKER_MAX_RETRIES |
3 |
WORKER_SYNC_INTERVAL_SEC |
300 (fallback saja — perlonggar kalau webhook sudah aktif) |
WORKER_SYNC_BATCH_SIZE |
100 |
WEBHOOK_PORT |
8081 |
WEBHOOK_SECRET |
— (HMAC-SHA256 shared secret; kosongkan untuk skip verifikasi saat dev) |
Run
psql -d gadai_mulia -f migrations/001_create_collection_broadcasts.up.sql
export DATABASE_DSN="postgres://user:pass@localhost:5432/gadai_mulia"
export SOPIGA_TOKEN="your_api_token"
go run ./...
Test
go test ./tests/... -v