Notifications (Notifikasi)
| Code | ACC-NTF |
| Module | Account |
| Type | Inbox + delivery channels |
| Status | Implemented |
| Priority | P1 |
| Process | Komunikasi sistem ke pengguna |
| API | [URL Postman] |
1. Overview
Notifikasi memberi tahu pengguna tentang kejadian yang relevan, misalnya PO yang perlu diajukan atau data yang berubah. Notifikasi dibuat oleh BE dan dikirim ke pengguna lewat tiga kanal:
- Kotak masuk (inbox) — daftar notifikasi di lonceng header (10 terbaru) dan halaman Akun → Notifikasi (lengkap, bisa dicari).
- Notifikasi aplikasi (realtime) — toast yang muncul langsung saat aplikasi terbuka, lewat WebSocket (Laravel Reverb / Echo) pada channel privat
tenant.users.{userId}. - Notifikasi browser (push) — notifikasi sistem operasi lewat Web Push, tetap muncul saat aplikasi tertutup (termasuk PWA yang di-install).
Setiap notifikasi membawa petunjuk tujuan (module, resource, operation, params), bukan URL. FE menerjemahkannya menjadi rute aplikasi sehingga pengguna bisa langsung membuka data terkait.
Hasil yang diharapkan: pengguna tidak melewatkan pekerjaan yang menunggu mereka, dan bisa langsung menuju data terkait dengan satu klik.
2. Problem
- Tugas yang menunggu seseorang (misalnya PO yang harus diajukan PIC) tidak diketahui tanpa membuka setiap modul.
- Pengguna yang tidak sedang membuka aplikasi melewatkan kejadian penting.
- Notifikasi tanpa tautan memaksa pengguna mencari data secara manual.
3. Goals & Non-goals
Goals
- Pengguna tahu ada notifikasi baru. Indikator: badge jumlah belum dibaca di lonceng, toast realtime.
- Pengguna bisa mengatur kanal. Indikator: toggle notifikasi aplikasi dan notifikasi browser.
- Notifikasi bisa ditindaklanjuti. Indikator: tombol Lihat Detail membuka data terkait.
Non-goals
- Preferensi notifikasi per jenis kejadian
- Notifikasi email / WhatsApp
- Menghapus notifikasi
- Membuat notifikasi manual dari UI (endpoint test hanya untuk pengujian)
4. User Scenarios
| Role | Scenario |
|---|---|
| PIC PO | Mendapat toast saat ditetapkan sebagai PIC, klik toast, langsung membuka detail PO |
| Kepala Toko | Menerima notifikasi browser di ponsel (PWA) saat aplikasi tertutup |
| Semua pengguna | Membuka lonceng, melihat 10 notifikasi terbaru, lalu membuka halaman Notifikasi untuk menandai semua sudah dibaca |
| Semua pengguna | Mencari notifikasi lama di halaman Notifikasi dengan filter Belum Dibaca |
| Pengguna di perangkat bersama | Mematikan notifikasi browser agar tidak muncul di perangkat itu |
5. User Flow
- Inbox — Semua notifikasi tersimpan dan tampil di lonceng serta halaman Notifikasi.
- Realtime — Bila toggle “Notifikasi Aplikasi” aktif (default aktif, disimpan per browser), aplikasi terhubung ke channel privat pengguna. Setiap notifikasi baru memuat ulang daftar/jumlah dan menampilkan toast yang bisa diklik.
- Push — Bila toggle “Notifikasi Browser” diaktifkan, browser meminta izin notifikasi, mendaftarkan service worker, membuat subscription dengan public key dari BE, lalu mengirim subscription ke BE.
- Klik toast — Menandai notifikasi dibaca dan langsung membuka rute tujuan.
- Klik notifikasi OS — Service worker memfokuskan tab aplikasi yang terbuka dan mengirim petunjuk tujuan; aplikasi membuka rutenya. Bila tidak ada tab, aplikasi dibuka di beranda.
- Klik item inbox — Menandai dibaca bila belum, lalu membuka dialog detail (judul, waktu relatif, isi lengkap). Tombol Lihat Detail tampil bila tujuan bisa dipetakan ke rute.
Alternative paths
- Browser tidak mendukung push — toggle nonaktif dengan keterangan “Tidak didukung di browser ini”.
- Izin notifikasi ditolak — toggle nonaktif dengan keterangan “Izin ditolak — aktifkan dari pengaturan browser”.
- Gagal subscribe / unsubscribe — toast error, status toggle tidak berubah.
- Subscription lama dengan key berbeda — dihapus di BE dan browser, lalu dibuat ulang otomatis.
- Browser merotasi subscription — service worker membuat subscription baru dan mengirimkannya ke BE.
6. User Stories
Prioritas: P0 wajib untuk rilis, P1 penting, P2 kalau sempat.
US-01 — Lonceng notifikasi (P1)
Sebagai pengguna, saya ingin melihat notifikasi terbaru dari header, agar cepat tahu ada yang baru.
| ID | Kriteria penerimaan |
|---|---|
| AC-01.1 | Lonceng menampilkan badge jumlah belum dibaca; lebih dari 99 ditampilkan “99+”. |
| AC-01.2 | Popover menampilkan 10 notifikasi terbaru dengan tab Semua / Belum Dibaca. |
| AC-01.3 | Tersedia tautan “Lihat semua” ke /account/notifications; klik item menutup popover dan membuka dialog detail. |
| AC-01.4 | State kosong: “Belum ada notifikasi” / “Tidak ada notifikasi yang belum dibaca”. |
US-02 — Halaman notifikasi (P1)
Sebagai pengguna, saya ingin melihat semua notifikasi saya, agar bisa menemukan notifikasi lama.
| ID | Kriteria penerimaan |
|---|---|
| AC-02.1 | Tab Semua / Belum Dibaca dan kata kunci pencarian disimpan di URL (?tab=, ?keyword=). |
| AC-02.2 | Daftar dimuat bertahap 15 per muatan dengan tombol “Muat lebih banyak”. |
| AC-02.3 | Tombol “Tandai semua dibaca” menandai semua notifikasi pengguna dan memuat ulang daftar serta badge. |
| AC-02.4 | Item belum dibaca dibedakan secara visual; ikon mengikuti modul (inventory, purchase, settings, atau lonceng default). |
US-03 — Detail dan navigasi (P1)
Sebagai pengguna, saya ingin membaca notifikasi lengkap dan membuka data terkait.
| ID | Kriteria penerimaan |
|---|---|
| AC-03.1 | Klik item menandai dibaca (bila belum) dan membuka dialog detail berisi judul, waktu relatif, dan isi. |
| AC-03.2 | Tombol Lihat Detail hanya tampil bila tujuan bisa dipetakan ke rute (BR-04). |
| AC-03.3 | Lihat Detail menutup dialog dan membuka rute tujuan. |
US-04 — Notifikasi aplikasi realtime (P1)
Sebagai pengguna, saya ingin notifikasi muncul langsung saat aplikasi terbuka.
| ID | Kriteria penerimaan |
|---|---|
| AC-04.1 | Toggle “Notifikasi Aplikasi” di menu pengaturan header; default aktif, disimpan di browser. |
| AC-04.2 | Status koneksi ditampilkan: Menghubungkan / Terhubung / Terputus. |
| AC-04.3 | Notifikasi baru menampilkan toast yang bisa diklik dan memperbarui badge serta daftar. |
| AC-04.4 | Klik toast menandai dibaca dan membuka rute tujuan. |
US-05 — Notifikasi browser (push) (P1)
Sebagai pengguna, saya ingin menerima notifikasi walau aplikasi tertutup.
| ID | Kriteria penerimaan |
|---|---|
| AC-05.1 | Toggle “Notifikasi Browser” mencerminkan ada/tidaknya subscription di perangkat ini. |
| AC-05.2 | Mengaktifkan meminta izin browser hanya sebagai respons klik pengguna, lalu mendaftarkan subscription ke BE. |
| AC-05.3 | Menonaktifkan menghapus subscription di browser dan di BE. |
| AC-05.4 | Toggle nonaktif dengan keterangan bila push tidak didukung atau izin ditolak. |
| AC-05.5 | Notifikasi OS tetap tampil walau payload tidak valid (judul fallback). |
7. Document Structure
Notifikasi
| Field | Required | Default | Notes |
|---|---|---|---|
id | — | — | |
type | — | — | Jenis notifikasi BE |
data.title | — | — | Judul |
data.body | — | — | Isi |
data.action | — | — | { module, resource, operation, params } atau null |
read_at | — | null | Terisi saat dibaca |
created_at | — | — | Ditampilkan relatif (“5 menit lalu”) |
Jumlah: total, unread_total.
Push subscription (dikirim FE): endpoint, expirationTime, keys.p256dh, keys.auth, content_encoding (aes128gcm, fallback aesgcm).
Pemetaan tujuan → rute
module:resource | Rute | Detail / form |
|---|---|---|
inventory:product | /inventory/products | Ya |
inventory:product-group | /inventory/product-groups | Daftar saja |
inventory:product-category | /inventory/product-categories | Daftar saja |
inventory:measurement-unit | /inventory/measurement-units | Daftar saja |
purchase:supplier | /purchase/suppliers | Ya |
purchase:purchase-order | /purchase/purchase-orders | Ya |
purchase:goods-receipt | /purchase/goods-receipts | Ya |
settings:store | /settings/stores | Ya |
settings:employee | /settings/employees | Ya |
settings:user | /settings/users | Ya |
settings:role | /settings/roles-and-permissions | Ya |
operation: view → /:id/detail, edit → /:id/edit, create → /add, lainnya → daftar.
8. Status Lifecycle
| Status | Label UI | Meaning | Editable | Next status |
|---|---|---|---|---|
Belum dibaca (read_at: null) | Disorot | Belum dibuka | — | Dibaca |
Dibaca (read_at terisi) | Normal | Sudah dibuka | — | — |
9. Permissions & Actions
Permissions
| Action | Permission | Syarat tambahan |
|---|---|---|
| Semua aksi notifikasi | — | Pengguna login; hanya notifikasi milik sendiri |
| Channel realtime | — | Otorisasi channel privat tenant.users.{userId} oleh BE |
10. Business Rules
Aturan bisnis adalah ketentuan yang berlaku di semua layar dan semua aksi, siapa pun yang melakukannya. FE memakainya sebagai validasi di form, BE memakainya sebagai sumber kebenaran; jika keduanya berbeda, perilaku BE yang dianggap benar dan FE menyesuaikan.
- BR-01 BE tidak mengirim URL; hanya petunjuk tujuan (
module,resource,operation,params). FE yang memetakan ke rute. - BR-02 Preferensi realtime disimpan per browser (
localStorage: notif-realtime), default aktif. - BR-03 Subscription push berlaku per perangkat/browser; satu pengguna bisa punya banyak subscription.
- BR-04 Tombol Lihat Detail dan navigasi hanya tersedia bila
module:resourceada di tabel pemetaan. - BR-05 Izin notifikasi browser hanya diminta sebagai respons langsung klik pengguna.
- BR-06 Service worker harus selalu menampilkan notifikasi untuk setiap push yang diterima, walau payload rusak.
- BR-07 Service worker tidak boleh mencegat request (
fetchhandler inert) dan tidak boleh di-unregister di dev.
11. Edge Cases
Edge case adalah kondisi yang jarang terjadi tetapi pasti muncul di operasional nyata. Perilaku yang diharapkan ditetapkan di sini agar tidak diputuskan sendiri-sendiri saat implementasi.
| ID | Case | Expected behavior |
|---|---|---|
| EC-01 | Klik notifikasi OS saat tidak ada tab aplikasi terbuka | Aplikasi dibuka di beranda; tujuan tidak dibuka dan notifikasi tidak ditandai dibaca |
| EC-02 | Klik notifikasi OS saat tab terbuka | Tab difokuskan dan rute tujuan dibuka; notifikasi tidak otomatis ditandai dibaca (berbeda dengan klik toast) |
| EC-03 | Notifikasi dari modul yang belum dipetakan (misalnya Bill) | Tidak ada tombol Lihat Detail; toast tidak menavigasi |
| EC-04 | Otorisasi channel realtime gagal | Status “error”, peringatan di console; inbox tetap berfungsi |
| EC-05 | Konfigurasi Reverb (key/host) kosong | Realtime tidak terhubung (status idle) |
| EC-06 | Pengguna logout di perangkat dengan push aktif | Ditentukan BE; subscription perangkat sebaiknya dilepas agar notifikasi tidak muncul untuk akun lain |
| EC-07 | iOS di luar PWA | Push tidak didukung; toggle nonaktif dengan keterangan |
| EC-08 | Pengguna tidak punya akses ke data tujuan | Rute dibuka lalu halaman mengarahkan ke unauthorized |
12. API Contract
| Action | Method | Endpoint | Ref |
|---|---|---|---|
Daftar notifikasi (cursor, cari, unread) | GET | /api/auth/notifications/cursor | US-01, US-02 |
| Jumlah notifikasi (total, belum dibaca) | GET | /api/auth/notifications | AC-01.1 |
| Tandai satu dibaca | PATCH | /api/auth/notifications/:id/read | AC-03.1 |
| Tandai semua dibaca | PATCH | /api/auth/notifications/bulk | AC-02.3 |
| Public key VAPID | GET | /api/auth/notifications/subscriptions | US-05 |
| Daftarkan subscription push | POST | /api/auth/notifications/subscriptions | AC-05.2 |
| Hapus subscription push | DELETE | /api/auth/notifications/subscriptions | AC-05.3 |
| Kirim notifikasi uji | POST | /api/auth/notifications/test | — |
| Channel realtime | WebSocket | private-tenant.users.{userId} (Reverb) | US-04 |
13. Dependencies
PRD terkait
- Purchase Order, Goods Receipt, dan modul lain — sumber kejadian notifikasi.
- Linked Devices — sesi perangkat (push terikat ke browser/perangkat).
Infrastruktur
- Laravel Reverb (WebSocket) dan Laravel Echo di FE.
- Service worker
/sw.jsdan manifest PWA; proxy matcher harus mengecualikansw.jsdan manifest.
Efek ke modul lain
- Menambah modul/resource baru yang mengirim notifikasi wajib menambah baris di tabel pemetaan rute (bagian 7).