# Fase 1 — Step 4: Device & Ops Monitoring

Dokumen ini merinci implementasi heartbeat, status device, list/detail monitoring, dan KPI dasar admin untuk selesai dari Step 4.

## 1) Tujuan Step 4
- Menyediakan visibilitas operasional untuk device dan transaksi di admin
- Menjadikan heartbeat sebagai sumber status online device
- Menyediakan metrik minimum yang dipakai tim operasi harian
- Menyediakan jalur retry/penelusuran notifikasi pending

## 2) Heartbeat Ingestion

### Endpoint
- `POST /device/heartbeat`

### Request
```json
{
  "device_id": "sbx_001",
  "timestamp": "2026-05-23T10:00:00Z",
  "firmware_version": "1.0.3",
  "network_strength": 78,
  "battery_level": 92,
  "state": "idle"
}
```

### Rules
- Validate token device.
- Simpan ke `device_heartbeats`.
- Update `devices.last_seen_at = timestamp`.
- Jika field missing, simpan `null` dan tetap catat validasi non-kritis:
  - `network_strength` / `battery_level` boleh null
- Return response:
  - `request_id`
  - `device_id`
  - `server_time`

### Status Derivation (Step 4)
- `online`: `last_seen_at >= now - 90 detik`
- `degraded`: `network_strength < 40` **atau** `battery_level < 20`
- `stale`: `last_seen_at < now - 90 detik` dan >= `now - 15 menit`
- `offline`: `last_seen_at < now - 15 menit`
- Kombinasi prioritas: `offline`/`stale`/`degraded`/`online` (offline paling dominan)

## 3) Endpoint Monitoring Dasar

### List Device
- `GET /admin/devices`
- query:
  - `status`
  - `vendor`
  - `communication_mode`
  - `merchant_id`
  - `q` (search)
- response: include:
  - `status`
  - `last_seen_at`
  - `heartbeat_count_24h`
  - binding current summary

### Device Detail
- `GET /admin/devices/{deviceId}`
- response include:
  - metadata device
  - binding aktif (merchant/outlet/terminal)
  - latest heartbeat
  - derived status + device health
  - `notifications` latest

### Heartbeat List
- `GET /admin/devices/{deviceId}/heartbeats`
- filter:
  - `from`, `to`, `state`
- sort: latest first

### Transaction List/Detail (minimal lanjutan Step 4)
- `GET /admin/transactions`
  - filter `status`, `merchant_id`, `from`, `to`, `partner_reference`
- `GET /admin/transactions/{transactionId}`
  - include `transaction_events` timeline

## 4) KPI Dashboard Minimal (admin)

### Endpoint
- `GET /admin/dashboard/summary`

### Metrics
- `transactions_today`
- `success_rate_today` (paid / total attempt)
- `active_devices`
- `pending_notifications`
- `devices_stale`
- `devices_offline`

### Data Source
- transaksi hari ini dari `transactions.created_at`
- device status dari `devices.last_seen_at`
- pending notification dari `notifications.delivery_status in ('queued','retrying')`

## 5) Admin Retry-notification (Step 4)

### Endpoint
- `POST /admin/transactions/{transactionId}/retry-notification`

### Flow
1. validasi transaksi exists dan status `paid`
2. ambil latest notification `delivery_status` != `acknowledged`
3. jika `delivery_status` = `queued/sent/failed/retrying`:
   - trigger publish ulang
   - tambah `retry_count`
4. simpan hasil status setelah publish
5. return:
   - `transaction_id`
   - `notification_id`
   - `delivery_status`
   - `next_retry_at`

## 6) Monitoring Notifikasi Gagal
- endpoint ops:
  - `GET /admin/notifications/failed`
- filter:
  - `device_id`
  - `from`
  - `to`
- response:
  - `notification_id`, `transaction_id`, `device_id`, `delivery_status`, `retry_count`, `reason`

## 7) Query Efficiency (Prioritas)
- buat index:
  - `devices(status, last_seen_at)`
  - `device_heartbeats(device_id, received_at desc)`
  - `transactions(status, created_at)`
  - `notifications(delivery_status, created_at)`

## 8) Acceptance Criteria Step 4
- status device berubah sesuai aturan `online/degraded/stale/offline`
- heartbeat tercatat dan `devices.last_seen_at` terupdate
- dashboard summary menampilkan 5 metrik minimal
- `GET /admin/transactions` dan device/transaction detail menampilkan data yang dibutuhkan
- endpoint retry-notification memicu publish ulang untuk status non-final

## 9) Error Handling
- `DEVICE_NOT_FOUND`
- `INVALID_HEARTBEAT_PAYLOAD`
- `TRANSACTION_NOT_ELIGIBLE_FOR_RETRY`
- `DASHBOARD_CALCULATION_ERROR` (fallback graceful: return nilai default 0 jika query gagal)

## 10) Keluaran Step 4 (End-State)
- operator bisa cek:
  - device aktif/offline
  - transaksi dan status payment
  - kegagalan notifikasi
- sistem tetap bisa operasi manual meski tanpa UI dashboard kompleks
