14 Des 2024·7 menit membaca

Sistem notifikasi multi-saluran: template, percobaan ulang, preferensi

Rancang sistem notifikasi multi-saluran untuk email, SMS, dan Telegram dengan template, pelacakan status pengiriman, percobaan ulang, dan preferensi pengguna yang konsisten.

Sistem notifikasi multi-saluran: template, percobaan ulang, preferensi

Apa yang diselesaikan oleh satu sistem notifikasi

Saat email, SMS, dan Telegram dibangun sebagai fitur terpisah, celah cepat terlihat. Peringatan yang “sama” berakhir dengan kata-kata berbeda, waktu berbeda, dan aturan berbeda tentang siapa yang menerimanya. Tim support lalu mengejar tiga versi kebenaran: satu di penyedia email, satu di gateway SMS, dan satu di log bot.

Sistem notifikasi multi-saluran memperbaiki ini dengan memperlakukan notifikasi sebagai satu produk, bukan tiga integrasi. Satu peristiwa terjadi (reset kata sandi, faktur dibayar, server turun), dan sistem memutuskan cara mengirimkannya ke berbagai saluran berdasarkan template, preferensi pengguna, dan aturan pengiriman. Pesan masih bisa diformat berbeda per saluran, tetapi makna, data, dan pelacakannya tetap konsisten.

Kebanyakan tim akhirnya membutuhkan fondasi yang sama, terlepas dari saluran mana yang mereka mulai: template versi dengan variabel, pelacakan status pengiriman ("tersedia, terkirim, gagal, kenapa"), percobaan ulang dan fallback yang masuk akal, preferensi pengguna dengan consent dan quiet hours, serta jejak audit supaya support bisa melihat apa yang terjadi tanpa menebak.

Keberhasilan terlihat membosankan, dalam arti baik. Pesan dapat diprediksi: orang yang tepat menerima konten yang tepat, pada waktu yang tepat, melalui saluran yang mereka izinkan. Saat ada yang salah, pemecahan masalah menjadi mudah karena setiap percobaan dicatat dengan status jelas dan kode alasan.

Contoh yang bagus adalah peringatan "login baru". Anda membuatnya sekali, isi dengan data pengguna, perangkat, dan lokasi yang sama, lalu kirim sebagai email untuk detail, SMS untuk urgensi, dan Telegram untuk konfirmasi cepat. Jika penyedia SMS timeout, sistem mencoba lagi sesuai jadwal, mencatat timeout, dan bisa fallback ke saluran lain alih-alih menjatuhkan peringatan.

Konsep inti dan model data sederhana

Sistem notifikasi multi-saluran tetap mudah dikelola ketika Anda memisahkan “mengapa kita memberi tahu” dari “bagaimana kita mengirimkannya.” Itu berarti satu set objek bersama yang kecil, plus detail khusus-saluran hanya di tempat yang benar-benar berbeda.

Mulailah dengan sebuah event. Event adalah pemicu bernama seperti order_shipped atau password_reset. Jaga nama konsisten: huruf kecil, underscore, dan past tense ketika cocok. Perlakukan event sebagai kontrak stabil yang menjadi dasar template dan aturan preferensi.

Dari satu event, buat sebuah record notification. Ini adalah niat yang terlihat oleh pengguna: untuk siapa, apa yang terjadi, dan data apa yang dibutuhkan untuk merender konten (nomor pesanan, tanggal pengiriman, kode reset). Simpan field bersama di sini seperti user_id, event_name, locale, priority, dan scheduled_at.

Lalu bagi menjadi message per saluran. Satu notification bisa menghasilkan 0 sampai 3 message (email, SMS, Telegram). Message menyimpan field khusus-saluran seperti destinasi (alamat email, nomor telepon, Telegram chat_id), template_id, dan konten yang sudah dirender (subject/body untuk email, teks pendek untuk SMS).

Terakhir, lacak setiap pengiriman sebagai delivery attempt. Attempt berisi provider request_id, timestamp, response code, dan status yang dinormalisasi. Inilah yang Anda periksa saat pengguna berkata, "Saya tidak menerimanya."

Model sederhana sering muat dalam empat tabel atau koleksi:

  • Event (katalog nama event yang diizinkan dan default)
  • Notification (satu per niat pengguna)
  • Message (satu per saluran)
  • DeliveryAttempt (satu per percobaan)

Rencanakan idempoten sejak awal. Beri setiap notification sebuah kunci deterministik seperti (event_name, user_id, external_ref) agar percobaan ulang dari sistem upstream tidak membuat duplikat. Jika sebuah langkah workflow dijalankan ulang, idempoten adalah yang mencegah pengguna menerima dua SMS.

Simpan jangka panjang hanya apa yang perlu diaudit (event, notification, status akhir, timestamp). Simpan antrean pengiriman jangka pendek dan payload mentah provider hanya selama Anda membutuhkan untuk menjalankan dan men-debug.

Alur end-to-end praktis (langkah demi langkah)

Sistem notifikasi multi-saluran bekerja terbaik saat ia memisahkan “memutuskan apa yang dikirim” dari “mengirimnya.” Itu menjaga aplikasi Anda cepat dan membuat kegagalan lebih mudah ditangani.

Alur praktis terlihat seperti ini:

  1. Produser event membuat request notifikasi. Ini bisa berupa "password reset," "invoice paid," atau "ticket updated." Request mencakup user ID, tipe pesan, dan data konteks (nomor pesanan, jumlah, nama agen support). Simpan request segera supaya Anda punya jejak audit.

  2. Router memuat aturan pengguna dan pesan. Ia melihat preferensi pengguna (saluran yang diizinkan, opt-in, quiet hours) dan aturan pesan (misalnya: alert keamanan harus coba email dulu). Router memutuskan rencana saluran, misalnya Telegram, lalu SMS, lalu email.

  3. Sistem mengantri job pengiriman per saluran. Setiap job berisi kunci template, saluran, dan variabel. Job masuk ke antrean sehingga aksi pengguna tidak terblokir oleh proses pengiriman.

  4. Worker saluran mengirim lewat provider. Email ke SMTP atau API email, SMS ke gateway SMS, Telegram lewat bot Anda. Worker harus idempoten, sehingga mengulang job yang sama tidak mengirim duplikat.

  5. Update status mengalir kembali ke satu tempat. Worker mencatat queued, sent, failed, dan bila tersedia, delivered. Jika provider hanya mengonfirmasi "accepted," catat itu juga dan perlakukan berbeda dari delivered.

  6. Fallback dan retry berjalan dari state yang sama. Jika Telegram gagal, router (atau worker retry) bisa jadwalkan SMS berikutnya tanpa kehilangan konteks.

Contoh: pengguna mengganti kata sandi. Backend Anda mengirim satu request dengan user dan alamat IP. Router melihat pengguna memilih Telegram, tapi quiet hours memblokirnya di malam hari, jadi ia menjadwalkan email sekarang dan Telegram di pagi hari, sambil melacak keduanya di bawah satu record notification.

Jika Anda mengimplementasikan ini di AppMaster, simpan request, job, dan tabel status di Data Designer dan ekspresikan logika routing serta retry di Business Process Editor, dengan pengiriman ditangani secara asinkron agar UI tetap responsif.

Struktur template yang bekerja di berbagai saluran

Sistem template yang baik dimulai dari satu ide: Anda memberi tahu tentang sebuah event, bukan "mengirim email" atau "mengirim SMS." Buat satu template per event (Password reset, Order shipped, Payment failed), lalu simpan varian khusus-saluran di bawah event yang sama.

Jaga variabel yang sama di setiap varian saluran. Jika email memakai first_name dan order_id, SMS dan Telegram harus memakai nama variabel yang sama. Ini mencegah bug halus saat satu saluran ter-render baik tetapi saluran lain menunjukkan kosong.

Bentuk template sederhana dan dapat diulang

Untuk setiap event, definisikan sekumpulan field kecil per saluran:

  • Email: subject, preheader (opsional), HTML body, fallback teks
  • SMS: body teks biasa
  • Telegram: body teks biasa, plus tombol opsional atau metadata singkat

Satu-satunya yang berubah per saluran adalah format, bukan makna.

SMS butuh aturan khusus karena pendek. Putuskan sejak awal apa yang terjadi saat konten terlalu panjang, dan buat konsisten: tetapkan batas karakter, pilih aturan pemotongan (potong dan tambahkan ... atau hilangkan baris opsional dulu), hindari URL panjang dan tanda baca ekstra, dan taruh aksi utama di awal (kode, tenggat, langkah berikutnya).

Lokalisasi tanpa menyalin logika bisnis

Perlakukan bahasa sebagai parameter, bukan workflow terpisah. Simpan terjemahan per event dan saluran, lalu render dengan variabel yang sama. Logika "Order shipped" tetap sama sementara subject dan body berubah per locale.

Mode preview sangat berguna. Render template dengan data contoh (termasuk kasus ujung seperti nama panjang) supaya tim support bisa memverifikasi varian email, SMS, dan Telegram sebelum dipakai.

Status pengiriman yang bisa dipercaya dan di-debug

Luncurkan event pertama Anda hari ini
Mulai dengan satu event seperti reset kata sandi, lalu tambahkan saluran satu per satu.
Prototipe Sekarang

Sebuah notifikasi hanya berguna jika Anda bisa menjawab satu pertanyaan nanti: apa yang terjadi padanya? Sistem notifikasi multi-saluran yang baik memisahkan pesan yang Anda maksudkan kirim dari tiap percobaan untuk mengirimkannya.

Mulailah dengan sekumpulan status bersama yang kecil yang bermakna sama di email, SMS, dan Telegram:

  • queued: diterima oleh sistem Anda, menunggu worker
  • sending: percobaan pengiriman sedang berjalan
  • sent: diserahkan ke API provider dengan sukses
  • failed: percobaan berakhir dengan error yang bisa diambil tindakan
  • delivered: Anda memiliki bukti pesan mencapai pengguna (jika memungkinkan)

Simpan status ini di record message utama, tetapi lacak setiap percobaan di tabel history. History itulah yang membuat debugging mudah: percobaan #1 gagal (timeout), percobaan #2 berhasil, atau SMS berhasil sementara email terus bouncing.

Apa yang disimpan per percobaan

Normalisasi respons provider agar Anda bisa mencari dan mengelompokkan masalah meski provider memakai istilah berbeda.

  • provider_name dan provider_message_id
  • response_code (kode yang dinormalisasi seperti TIMEOUT, INVALID_NUMBER, BOUNCED)
  • raw_provider_code dan raw_error_text (untuk kasus support)
  • started_at, finished_at, duration_ms
  • channel (email, sms, telegram) dan destination (dimask)

Rencanakan untuk keberhasilan parsial. Satu notification dapat membuat tiga message channel yang berbagi parent_id dan konteks bisnis (order_id, ticket_id, alert_type). Jika SMS terkirim tapi email gagal, Anda masih ingin cerita lengkap di satu tempat, bukan tiga insiden tak terkait.

Apa arti "delivered" sebenarnya

"Sent" bukan berarti "delivered." Untuk Telegram, Anda mungkin hanya tahu API menerima pesan. Untuk SMS dan email, pengiriman sering tergantung webhook atau callback provider, dan tidak semua provider sama andal. Tentukan arti delivered per saluran sejak awal. Gunakan konfirmasi webhook saat tersedia; jika tidak, perlakukan delivered sebagai tidak diketahui dan terus laporkan sent. Itu menjaga pelaporan Anda jujur dan jawaban support konsisten.

Percobaan ulang, fallback, dan kapan berhenti mencoba

Percobaan ulang sering jadi tempat sistem notifikasi salah. Ulang terlalu cepat dan Anda menciptakan badai. Ulang selamanya dan Anda menciptakan duplikat serta kepusingan support. Tujuannya sederhana: coba lagi saat peluang berhasil nyata, dan berhenti saat tidak.

Mulailah dengan mengklasifikasikan kegagalan. Timeout dari penyedia email, 502 dari gateway SMS, atau error sementara API Telegram biasanya bisa dicoba ulang. Alamat email yang salah format, nomor telepon yang gagal validasi, atau chat Telegram yang memblokir bot Anda tidak bisa dicoba ulang. Memperlakukan semuanya sama buang-buang biaya dan memenuhi log.

Rencana retry praktis dibatasi dan memakai backoff:

  • Percobaan 1: kirim sekarang
  • Percobaan 2: setelah 30 detik
  • Percobaan 3: setelah 2 menit
  • Percobaan 4: setelah 10 menit
  • Berhenti setelah umur maksimum (misalnya 30-60 menit untuk alert)

Berhenti perlu tempat nyata di model data Anda. Tandai message sebagai dead-letter (atau failed-permanently) setelah melebihi batas retry. Simpan kode error terakhir dan pesan error singkat supaya support bisa bertindak tanpa menebak.

Cegah pengiriman berulang setelah sukses dengan idempoten. Buat kunci idempoten per message logis (sering notification_id + user_id + channel). Jika provider merespons terlambat dan Anda mencoba lagi, percobaan kedua harus dikenali sebagai duplikat dan dilewati.

Fallback harus disengaja, bukan panik otomatis. Definisikan aturan eskalasi berdasarkan tingkat keparahan dan waktu. Contoh: reset kata sandi tidak boleh fallback ke saluran lain (risiko privasi), tapi alert insiden produksi mungkin mencoba SMS setelah dua percobaan Telegram gagal, lalu email setelah 10 menit.

Rancang model data inti
Modelkan event, message, dan delivery attempt di AppMaster Data Designer.
Mulai Proyek

Sistem notifikasi terasa "pintar" ketika menghormati orang. Cara termudah adalah membiarkan pengguna memilih saluran per tipe notifikasi. Banyak tim membagi tipe menjadi bucket seperti security, account, product, dan marketing karena aturan dan persyaratan hukum berbeda.

Mulailah dengan model preferensi yang bekerja bahkan saat saluran tidak tersedia. Pengguna mungkin punya email tapi tidak punya nomor telepon, atau belum menghubungkan Telegram. Sistem notifikasi multi-saluran harus memperlakukan itu sebagai hal normal, bukan error.

Sebagian besar sistem butuh sekumpulan field ringkas: tipe notifikasi (security, marketing, billing), saluran yang diizinkan per tipe (email, SMS, Telegram), consent per saluran (tanggal/waktu, sumber, dan bukti jika perlu), alasan opt-out per saluran (pilihan pengguna, email bounce, balasan "STOP"), dan aturan quiet hours (mulai/selesai plus zona waktu pengguna).

Quiet hours sering bikin sistem bermasalah. Simpan zona waktu pengguna (bukan hanya offset) supaya perubahan daylight savings tidak mengejutkan siapa pun. Saat pesan dijadwalkan selama quiet hours, jangan tandai gagal. Tandai sebagai deferred dan pilih waktu kirim berikutnya yang diperbolehkan.

Default penting, terutama untuk alert kritis. Pendekatan umum: notifikasi keamanan mengabaikan quiet hours (tetap hormati opt-out keras bila diperlukan), sementara pembaruan non-kritis mengikuti quiet hours dan pilihan saluran.

Contoh: reset kata sandi harus keluar segera ke saluran tercepat yang diizinkan. Digest mingguan harus menunggu pagi dan melewatkan SMS kecuali pengguna secara eksplisit mengaktifkannya.

Operasi: monitoring, log, dan alur kerja support

Permudah debugging status
Berikan tim support satu tampilan pencarian untuk setiap percobaan, status, dan alasan error.
Buat Dashboard

Saat notifikasi menyentuh email, SMS, dan Telegram, tim support butuh jawaban cepat: Apakah kita mengirimnya, apakah sampai, dan apa yang gagal? Sistem notifikasi multi-saluran harus terasa seperti satu tempat untuk investigasi, walau di belakangnya memakai beberapa provider.

Mulailah dengan tampilan admin sederhana yang bisa dipakai siapa saja. Buat bisa dicari berdasarkan pengguna, tipe event, status, dan jendela waktu, dan tampilkan percobaan terakhir terlebih dahulu. Setiap baris harus memperlihatkan saluran, respons provider, dan tindakan yang direncanakan berikutnya (retry, fallback, atau dihentikan).

Metrik yang menangkap masalah lebih awal

Gangguan jarang muncul sebagai satu error bersih. Lacak beberapa angka kecil dan tinjau secara teratur:

  • Laju pengiriman per saluran (pesan per menit)
  • Tingkat kegagalan per provider dan kode kegagalan
  • Tingkat retry (berapa banyak pesan membutuhkan percobaan kedua)
  • Waktu ke pengiriman (queued ke delivered, p50 dan p95)
  • Tingkat drop (dihentikan karena preferensi pengguna, consent, atau max retries)

Korelasikan semuanya. Buat correlation ID saat event terjadi (misalnya "invoice overdue") dan teruskan melalui templating, queueing, panggilan provider, dan update status. Di log, ID itu menjadi benang untuk diikuti saat satu event menyebar ke beberapa saluran.

Replay ramah support tanpa kejutan

Replay itu penting, tapi perlu pembatas supaya Anda tidak mengirimi spam orang atau menagih dua kali. Alur replay aman biasanya berarti: kirim ulang hanya message ID spesifik (bukan semua event batch), tunjukkan versi template dan konten yang dirender sebelum mengirim, minta alasan dan simpan siapa yang memicu replay, blokir replay jika message sudah delivered kecuali dipaksa, dan terapkan batas laju per pengguna dan per saluran.

Keamanan dan privasi dasar untuk notifikasi

Sistem notifikasi multi-saluran menyentuh data pribadi (email, nomor telepon, chat ID) dan sering menangani momen sensitif (login, pembayaran, support). Asumsikan setiap body pesan dan setiap baris log bisa dilihat nanti, lalu desain untuk membatasi apa yang disimpan dan siapa yang bisa melihatnya.

Jaga data sensitif keluar dari template bila memungkinkan. Template harus dapat digunakan ulang dan sederhana: "Your code is {{code}}" cukup, tapi hindari menyematkan detail akun penuh, token panjang, atau apa pun yang bisa dipakai untuk mengambil alih akun. Jika pesan harus menyertakan kode sekali pakai atau token reset, simpan hanya yang Anda butuhkan untuk memverifikasinya (misalnya hash dan masa berlaku), bukan nilai mentah.

Saat Anda menyimpan atau mencatat event notifikasi, mask secara agresif. Agen support biasanya perlu tahu bahwa kode telah dikirim, bukan kodenya sendiri. Sama berlaku untuk nomor telepon dan email: simpan nilai penuh untuk pengiriman, tapi tampilkan versi yang dimask di sebagian besar layar.

Kontrol minimum yang mencegah sebagian besar insiden

  • Akses berbasis peran: hanya sejumlah kecil peran yang bisa melihat body pesan dan info penerima penuh.
  • Pisahkan akses debug dari akses support agar troubleshooting tidak menjadi kebocoran privasi.
  • Lindungi endpoint webhook: gunakan callback yang ditandatangani atau shared secret, validasi timestamp, dan tolak sumber tak dikenal.
  • Enkripsi field sensitif saat disimpan dan gunakan TLS saat transit.
  • Definisikan aturan retensi: simpan log detail singkat, lalu simpan hanya agregat atau identifier yang di-hash.

Contoh praktis: jika SMS reset kata sandi gagal dan Anda fallback ke Telegram, simpan percobaan, status provider, dan penerima yang dimask, tetapi hindari menyimpan link reset itu sendiri di database atau log.

Skenario contoh: satu alert, tiga saluran, hasil nyata

Siapkan varian template dengan cepat
Jaga konsistensi variabel antar saluran dengan satu struktur template per event.
Buat Template

Seorang pelanggan, Maya, mengaktifkan dua tipe notifikasi: Password reset dan New login. Dia memilih Telegram dulu, lalu email. Dia hanya ingin SMS sebagai fallback untuk password reset.

Suatu malam, Maya meminta reset kata sandi. Sistem membuat satu record notification dengan ID stabil, lalu mengembangkannya menjadi percobaan saluran berdasarkan preferensinya saat itu.

Yang Maya lihat sederhana: pesan Telegram datang dalam beberapa detik dengan kode reset singkat dan waktu kedaluwarsa. Tidak ada yang lain karena Telegram berhasil dan tidak perlu fallback.

Yang dicatat sistem lebih rinci:

  • Notification: type=PASSWORD_RESET, user_id=Maya, template_version=v4
  • Percobaan #1: channel=TELEGRAM, status=SENT lalu DELIVERED
  • Tidak ada percobaan email atau SMS dibuat (kebijakan: berhenti setelah sukses pertama)

Beberapa hari kemudian, alert New login dipicu dari perangkat baru. Preferensi Maya untuk login hanya Telegram. Sistem mengirim Telegram, tetapi provider Telegram mengembalikan error sementara. Sistem mencoba lagi dua kali dengan backoff, lalu menandai percobaan sebagai FAILED dan berhenti (tidak ada fallback untuk tipe alert ini).

Sekarang kegagalan nyata: Maya meminta reset kata sandi lagi saat bepergian. Telegram dikirim, tetapi fallback SMS dikonfigurasi jika Telegram tidak deliver dalam 60 detik. Provider SMS timeout. Sistem mencatat timeout, mencoba sekali lagi, dan percobaan kedua berhasil. Maya menerima kode SMS satu menit kemudian.

Saat Maya menghubungi support, mereka mencari berdasarkan pengguna dan jendela waktu dan langsung melihat riwayat percobaan: timestamp, kode respons provider, jumlah retry, dan hasil akhir.

Daftar periksa cepat, kesalahan umum, dan langkah berikutnya

Sistem notifikasi multi-saluran lebih mudah dijalankan ketika Anda bisa menjawab dua pertanyaan cepat: "Apa tepatnya yang kita coba kirim?" dan "Apa yang terjadi setelah itu?" Gunakan daftar periksa ini sebelum menambahkan saluran atau event.

Daftar periksa cepat

  • Nama event dan kepemilikan jelas (misal, invoice.overdue dimiliki oleh billing)
  • Variabel template didefinisikan sekali (wajib vs opsional, default, aturan format)
  • Status disepakati di muka (created, queued, sent, delivered, failed, suppressed) dan arti tiap status
  • Batas retry dan backoff (maks percobaan, jarak waktu, aturan berhenti)
  • Aturan retensi (berapa lama menyimpan body pesan, respons provider, dan riwayat status)

Jika Anda hanya melakukan satu hal, tuliskan perbedaan antara sent dan delivered dengan kata-kata sederhana. Sent adalah apa yang sistem Anda lakukan. Delivered adalah apa yang dilaporkan provider (dan bisa terlambat atau hilang). Mencampur keduanya akan membingungkan tim support dan pemangku kepentingan.

Kesalahan umum yang harus dihindari

  • Menganggap sent berarti sukses dan melaporkan angka pengiriman yang berlebih
  • Membiarkan template khusus-saluran menyimpang sampai email, SMS, dan Telegram saling bertentangan
  • Mengulang tanpa idempoten, menyebabkan duplikat ketika provider timeout tetapi kemudian menerima pesan
  • Mengulang selamanya, mengubah outage sementara menjadi insiden berisik
  • Menyimpan terlalu banyak data pribadi di log dan record status "untuk berjaga-jaga"

Mulailah dengan satu event dan satu saluran utama, lalu tambahkan saluran kedua sebagai fallback (bukan sebagai kiriman paralel). Setelah alur stabil, perluas event demi event, jaga template dan variabel tetap bersama agar pesan tetap konsisten.

Jika Anda ingin membangun ini tanpa menulis setiap bagian manual, AppMaster (appmaster.io) adalah pilihan praktis untuk bagian inti: modelkan event, template, dan delivery attempt di Data Designer, implementasikan routing dan retry di Business Process Editor, dan hubungkan email, SMS, dan Telegram sebagai integrasi sambil menjaga pelacakan di satu tempat.

Mudah untuk memulai
Ciptakan sesuatu yang menakjubkan

Eksperimen dengan AppMaster dengan paket gratis.
Saat Anda siap, Anda dapat memilih langganan yang tepat.

Memulai
Sistem notifikasi multi-saluran: template, percobaan ulang, preferensi | AppMaster