# Fase 1 — Step 3: Notifikasi MQTT Dasar (Static Payment)

Dokumen ini memandu implementasi notifikasi success payment ke device berbasis event transaksi `paid`.

## 1) Tujuan Step 3
- Memastikan setiap transaksi `paid` memicu notifikasi sukses ke device yang valid
- Menyimpan status delivery dan retry agar operasional bisa dipantau
- Menyediakan endpoint admin untuk retry manual

## 2) Event Source
- Trigger dari Step 2: event internal `transaction.paid`
- Sumber wajib: event bus internal / service method call dari transaction service (untuk fase awal)

## 3) Mapping Notifikasi
- Input: `transaction_id`, `merchant_id`, `device_id`, `amount`, `currency`, `paid_at`, `reference`
- Output: payload MQTT `payment_success` ke topik:
  - `devices/{deviceId}/downlink/payment/success`
- Hanya kirim jika device memiliki binding aktif (`device_bindings.active_flag = true`)

## 4) Tabel dan Status

### `notifications`
Kolom inti:
- `id`
- `transaction_id`
- `device_id`
- `delivery_channel` = `mqtt`
- `payload_type` = `payment_success`
- `delivery_status`: `queued | sent | acknowledged | failed | retrying`
- `retry_count`
- `ack_status`: `pending | received | not_supported | not_needed`
- `sent_at`
- `ack_at`

Status transisi:
- dibuat -> `queued`
- publish sukses -> `sent`
- no ack handler tersedia pada fase awal -> `acknowledged` otomatis atau `failed` sesuai konfigurasi broker
- publish gagal -> `retrying`
- retry 3x gagal -> `failed`

## 5) Payload Kontrak MQTT (Step 3)
```json
{
  "message_type": "payment_success",
  "event_id": "evt_123",
  "transaction_id": "tx_123",
  "merchant_name": "Toko Berkah",
  "amount": 50000,
  "currency": "IDR",
  "paid_at": "2026-05-23T10:02:10Z",
  "audio_text": "Pembayaran diterima lima puluh ribu rupiah",
  "display_text": "Pembayaran diterima Rp50.000"
}
```

## 6) Alur Proses Notifikasi
1. Step 2 publish event `transaction.paid`
2. Notification Orchestrator menerima event
3. Validasi `device_id` ada dan memiliki binding aktif
4. Buat record `notifications` dengan status `queued`
5. Publish ke `devices/{deviceId}/downlink/payment/success`
6. Jika sukses, update `sent` dan `sent_at`
7. Jika gagal:
   - hitung retry (exponential/linear simple backoff)
   - update `retrying`
   - lanjut retry maksimum 3x
8. Jika 3x gagal tetap `failed`
9. Return result ke endpoint retry bila dipanggil manual

## 7) Retry Policy Fase 1 (Sederhana)
- max_attempt = 3
- retry_interval_seconds = 15, 30, 60 (tetap untuk fase awal)
- retry_count disimpan di `notifications.retry_count`
- tiap percobaan harus idempotent via `event_id` dan `transaction_id`

## 8) Endpoint Admin
- `POST /admin/transactions/{transactionId}/retry-notification`
  - validasi transaksi status harus `paid`
  - akan membuat attempt publish baru jika `delivery_status` bukan `acknowledged`
  - response:
    - `transaction_id`
    - `notification_id`
    - `delivery_status`
    - `next_retry_at`

## 9) Endpoint Ops Monitoring Minimal
- `GET /admin/devices/{deviceId}/notifications`
  - list notif by device + `delivery_status`
- `GET /admin/transactions/{transactionId}`
  - tampilkan link notification + timeline status

## 10) Idempotency dan De-Dupe
- kombinasi key notifikasi:
  - `transaction_id + event_id`
- jika event duplicate:
  - tidak membuat record baru
  - return existing notif status
- publish duplicate harus ditolak di orchestrator (guard).

## 11) Error Code (saran)
- `NOTIFICATION_DEVICE_UNAVAILABLE`
- `NOTIFICATION_NO_ACTIVE_BINDING`
- `NOTIFICATION_PUBLISH_FAILED`
- `NOTIFICATION_RETRY_EXHAUSTED`

## 12) Acceptance Criteria Step 3
- transaksi `paid` menghasilkan event `payment_success` ke topik device
- notification record terbentuk untuk setiap transaksi `paid`
- perangkat yang tidak terikat aktif tidak dipush (state `failed` dengan reason)
- retry berjalan saat publish gagal
- endpoint retry admin merubah status dari `failed/retrying` menjadi `sent` atau tetap `failed` setelah limit

## 13) Catatan Implementasi Step 3 (Tanpa Design)
- gunakan QoS 1 untuk topic payment success
- hindari retained message untuk event sukses pembayaran
- logging harus menyertakan `transaction_id`, `device_id`, `event_id`, `request_id`
- payload audit (audio/display) boleh berupa default ID locale
