# Notifikasi inbox & stream (WorkPulse API)

Dokumen referensi kontrak **HTTP + SSE** untuk pusat notifikasi di FE (`pages/notifications.vue`, `composables/useWorkpulseNotifications.ts`). Path grup: `/api/v1`, semua rute di bawah **`authMiddleware`** (Bearer atau cookie access token).

---

## Daftar notifikasi

### `GET /api/v1/notifications`

- Mengembalikan hingga **100** baris terbaru untuk `user_id` dari token.
- Respons envelope: `{ "ok": true, "data": [ ... ] }` — **`data` adalah array** (bukan objek dengan properti `items`).
- Setiap elemen (JSON):

| Field       | Tipe     | Keterangan                          |
|------------|----------|-------------------------------------|
| `id`       | number   | ID notifikasi                       |
| `title`    | string   |                                     |
| `body`     | string   | Isi / deskripsi                     |
| `createdAt`| string   | ISO8601                             |
| `read`     | boolean  | `true` jika `read_at` terisi        |
| `readAt`   | string?  | ISO8601, hanya jika sudah dibaca    |

---

## Menandai dibaca

### `PATCH /api/v1/notifications/read`

- Menandai **semua** notifikasi user yang belum punya `read_at`.
- Respons: `{ "ok": true, "data": { "ok": true } }` (bentuk data mengikuti implementasi saat ini).

### `PATCH /api/v1/notifications/:id/read` *(ditambahkan untuk FE)*

- Menandai **satu** baris: `UPDATE ... SET read_at = NOW() WHERE id = $1 AND user_id = $2 AND read_at IS NULL`.
- Respons: `{ "ok": true, "data": { "updated": true|false } }` — `updated` false jika sudah dibaca atau bukan milik user.

---

## Stream (SSE)

### `GET /api/v1/stream/notifications`

- `Content-Type: text/event-stream`
- Event `unread` dengan payload angka jumlah notifikasi belum dibaca.
- **Catatan FE:** `EventSource` di browser **tidak** mengirim header `Authorization`. Stream ini hanya cocok jika token juga dikirim lewat cookie access token yang sama seperti `authMiddleware`, atau lewat pola lain (mis. query — **tidak** direkomendasikan tanpa hardening). Saat ini FE memakai **polling** ringan (mis. ±45 detik di halaman notifikasi) + `GET /api/v1/me/summary` untuk badge unread di layout.

---

## Badge unread di layout

- FE memakai `notificationsUnread` dari **`GET /api/v1/me/summary`** (`period=month`) agar konsisten dengan dashboard profil.

---

## Status & file kode

| Bagian            | Lokasi (BE)                          | Status |
|-------------------|--------------------------------------|--------|
| List + mark all   | `internal/api/rest.go`              | **Ada** |
| Mark satu         | `internal/api/rest.go` + `router.go` | **Ada** (`PATCH /notifications/:id/read`) |
| SSE               | `internal/api/sse.go`               | **Ada** |

**BE (salinan kontrak):** [`../BE/docs/BE_SPEC_NOTIFICATIONS_INBOX_AND_STREAM.md`](../BE/docs/BE_SPEC_NOTIFICATIONS_INBOX_AND_STREAM.md)

**FE:** `docs/BE_SPEC_NOTIFICATIONS_INBOX_AND_STREAM.md` (file ini).

Setelah deploy BE: `go build -o bin/api ./cmd/api/` lalu restart PM2 `workpulse-api` (atau `delete` + `start` bila mengubah `.env`).
