545 lines
18 KiB
Markdown
545 lines
18 KiB
Markdown
# 🚨 EVLOG — Event & Error Log
|
|
|
|
**Project:** Web Antrean — Sistem Manajemen Antrean Rawat Jalan RSSA
|
|
**Author:** Akbar
|
|
**Stack:** JavaScript · Vue 3 · TypeScript · Nuxt 3 · Vuetify 3 · Pinia
|
|
|
|
---
|
|
|
|
## 🧠 AI Prompt — Cara Menggunakan Dokumen Ini
|
|
|
|
> Salin prompt berikut ke Claude untuk menganalisis dan mendokumentasikan error:
|
|
|
|
```
|
|
Kamu adalah senior engineer Nuxt 3 + TypeScript. Aku menemukan error berikut:
|
|
|
|
Error message: [paste error]
|
|
Stack trace: [paste stack trace]
|
|
Context: [dimana terjadi, langkah reproduksi]
|
|
Tech: Nuxt 3, Vue 3, TypeScript, Vuetify 3, Pinia, WebSocket, Keycloak
|
|
|
|
Bantu aku:
|
|
1. Analisis root cause error ini
|
|
2. Berikan solusi step-by-step
|
|
3. Sarankan cara mencegah error serupa
|
|
4. Format hasilnya untuk EVLOG dalam Markdown
|
|
```
|
|
|
|
---
|
|
|
|
## Severity Legend
|
|
|
|
| Level | Icon | Deskripsi | SLA |
|
|
|-------|------|-----------|-----|
|
|
| Critical | 🔴 | App down / data loss / security | < 4 jam |
|
|
| High | 🟠 | Fitur utama break | < 1 hari |
|
|
| Medium | 🟡 | Fitur minor terganggu | < 3 hari |
|
|
| Low | 🟢 | UI/kosmetik | Backlog |
|
|
|
|
---
|
|
|
|
## Format Entry
|
|
|
|
```markdown
|
|
### [EV-XXX] — [Judul Singkat Error/Event]
|
|
|
|
| Field | Value |
|
|
|-------|-------|
|
|
| **ID** | EV-XXX |
|
|
| **Tanggal** | YYYY-MM-DD |
|
|
| **Severity** | 🔴 Critical / 🟠 High / 🟡 Medium / 🟢 Low |
|
|
| **Environment** | Development / Staging / Production |
|
|
| **Status** | 🔍 Investigating / 🔧 In Fix / ✅ Resolved / ⏭ Wontfix |
|
|
| **Reporter** | Akbar |
|
|
|
|
**Error Message:**
|
|
> [paste error message]
|
|
|
|
**Langkah Reproduksi:**
|
|
1. ...
|
|
|
|
**Root Cause:**
|
|
> ...
|
|
|
|
**Solusi / Fix:**
|
|
> ...
|
|
|
|
**Prevention:**
|
|
> ...
|
|
|
|
**Related:** [commit / file]
|
|
```
|
|
|
|
---
|
|
|
|
## Event Log
|
|
|
|
<!-- Tambahkan entry baru di bawah baris ini, urutan terbaru di atas -->
|
|
|
|
---
|
|
|
|
### [EV-012] — Info Klinik Ruang Tidak Muncul di Layar Display
|
|
|
|
| Field | Value |
|
|
|-------|-------|
|
|
| **ID** | EV-012 |
|
|
| **Tanggal** | 2026-05-21 |
|
|
| **Severity** | 🟠 High |
|
|
| **Environment** | Development |
|
|
| **Status** | ✅ Resolved |
|
|
| **Reporter** | Akbar |
|
|
|
|
**Error Message:**
|
|
> Layar informasi klinik ruang menampilkan data kosong — tidak ada info klinik ruang yang muncul.
|
|
|
|
**Langkah Reproduksi:**
|
|
1. Buka halaman display screen klinik ruang
|
|
2. Data klinik ruang seharusnya muncul
|
|
3. Layar kosong — tidak ada informasi tampil
|
|
|
|
**Root Cause:**
|
|
> Data binding untuk info klinik ruang tidak ter-update setelah fetch dari API. Kemungkinan reactive state tidak di-watch dengan benar sehingga UI tidak re-render saat data berubah.
|
|
|
|
**Solusi / Fix:**
|
|
> Perbaikan data binding dan reactive state untuk informasi klinik ruang pada layar display.
|
|
|
|
**Related:** Commit `ec9dac0` — "push perbaikan layar informasi info klinik ruang tidak muncul"
|
|
|
|
---
|
|
|
|
### [EV-011] — Data Antrean Tidak Sinkron Antar Display Screen
|
|
|
|
| Field | Value |
|
|
|-------|-------|
|
|
| **ID** | EV-011 |
|
|
| **Tanggal** | 2026-05-22 |
|
|
| **Severity** | 🔴 Critical |
|
|
| **Environment** | Development |
|
|
| **Status** | ✅ Resolved |
|
|
| **Reporter** | Akbar |
|
|
|
|
**Error Message:**
|
|
> Display screen di lokasi berbeda menampilkan nomor panggil yang berbeda. Admin memanggil pasien tapi layar display tidak update, atau update terlambat > 10 detik.
|
|
|
|
**Langkah Reproduksi:**
|
|
1. Buka admin loket di PC A
|
|
2. Buka display screen di TV/monitor B
|
|
3. Panggil pasien berikutnya di PC A
|
|
4. Display di monitor B tidak menampilkan nomor panggil terbaru
|
|
|
|
**Root Cause:**
|
|
> WebSocket client ID menggunakan random ID, sehingga server tidak bisa menargetkan pesan ke device tertentu secara reliable. Saat koneksi putus lalu reconnect, client ID berubah dan device kehilangan subscription.
|
|
|
|
**Solusi / Fix:**
|
|
```typescript
|
|
// ❌ Before — random client ID
|
|
const clientId = `client_${Math.random().toString(36).substr(2, 9)}`
|
|
|
|
// ✅ After — deterministic client ID berdasarkan page + device
|
|
const clientId = `${pageType}_${loketId || 'global'}_${deviceFingerprint}`
|
|
```
|
|
Ditambahkan juga polling fallback setiap 30 detik sebagai safety net.
|
|
|
|
**Prevention:**
|
|
> Selalu gunakan deterministic identifier untuk WebSocket client. Implementasi polling fallback untuk semua halaman yang bergantung pada real-time data.
|
|
|
|
**Related:** Conversation `6fe234cf` — "Stabilizing WebSocket Queue Synchronization"
|
|
|
|
---
|
|
|
|
### [EV-010] — Cross-Loket Interference pada Patient Processing
|
|
|
|
| Field | Value |
|
|
|-------|-------|
|
|
| **ID** | EV-010 |
|
|
| **Tanggal** | 2026-05-21 |
|
|
| **Severity** | 🔴 Critical |
|
|
| **Environment** | Development |
|
|
| **Status** | ✅ Resolved |
|
|
| **Reporter** | Akbar |
|
|
|
|
**Error Message:**
|
|
> Loket A memproses pasien yang seharusnya milik Loket B. `currentProcessingPatient` menampilkan pasien dari loket yang salah.
|
|
|
|
**Langkah Reproduksi:**
|
|
1. Login sebagai admin loket A di browser tab 1
|
|
2. Login sebagai admin loket B di browser tab 2
|
|
3. Panggil pasien di loket A
|
|
4. Loket B menampilkan pasien yang sama sebagai "sedang diproses"
|
|
|
|
**Root Cause:**
|
|
> `currentProcessingPatient` menggunakan key persisted state yang sama untuk semua loket. Karena `pinia-plugin-persistedstate` menyimpan ke `localStorage` dengan key yang sama, operasi di satu loket menimpa state loket lain.
|
|
|
|
**Solusi / Fix:**
|
|
```javascript
|
|
// ❌ Before — shared key
|
|
persist: { key: 'currentProcessingPatient' }
|
|
|
|
// ✅ After — unique key per loket
|
|
persist: { key: `currentPatient_loket_${loketId}` }
|
|
```
|
|
Ditambahkan juga strict filter di `processNextQueue` dan `callNext` berdasarkan `loketId`, serta guard check di WebSocket event handler.
|
|
|
|
**Prevention:**
|
|
> Setiap state yang bersifat per-instance (per loket, per klinik) HARUS menggunakan unique key. Jangan pernah share persisted state key antar instance.
|
|
|
|
**Related:** Conversation `7a37e693` — "Isolating Loket Queue Operations"
|
|
|
|
---
|
|
|
|
### [EV-009] — Bug Tampilan Loket
|
|
|
|
| Field | Value |
|
|
|-------|-------|
|
|
| **ID** | EV-009 |
|
|
| **Tanggal** | 2026-05-20 |
|
|
| **Severity** | 🟡 Medium |
|
|
| **Environment** | Development |
|
|
| **Status** | ✅ Resolved |
|
|
| **Reporter** | Akbar |
|
|
|
|
**Error Message:**
|
|
> Layout admin loket tidak render dengan benar — elemen UI tumpang tindih atau alignment salah.
|
|
|
|
**Langkah Reproduksi:**
|
|
1. Login sebagai admin loket
|
|
2. Buka halaman `/admin-loket`
|
|
3. Layout tampilan loket tidak sesuai desain
|
|
|
|
**Root Cause:**
|
|
> CSS layout issue dan data binding yang tidak sinkron dengan state loket.
|
|
|
|
**Solusi / Fix:**
|
|
> Perbaikan layout dan data binding di halaman admin loket.
|
|
|
|
**Related:** Commit `f622052` — "perbaikan bug tampilan loket"
|
|
|
|
---
|
|
|
|
### [EV-008] — Memory Leak & Request Spam dari doctorStore
|
|
|
|
| Field | Value |
|
|
|-------|-------|
|
|
| **ID** | EV-008 |
|
|
| **Tanggal** | 2026-05-18 |
|
|
| **Severity** | 🟠 High |
|
|
| **Environment** | Development |
|
|
| **Status** | ✅ Resolved |
|
|
| **Reporter** | Akbar |
|
|
|
|
**Error Message:**
|
|
```
|
|
Internal Server Error (500) — /klinik-api/doctors/...
|
|
```
|
|
Error terjadi berulang-ulang tanpa henti, menyebabkan request spam ke backend.
|
|
|
|
**Langkah Reproduksi:**
|
|
1. Buka halaman yang memuat `doctorStore.js`
|
|
2. Backend endpoint `/doctors` return 500
|
|
3. Store terus retry tanpa batas
|
|
4. Network tab penuh dengan request gagal, memory usage naik terus
|
|
|
|
**Root Cause:**
|
|
> `doctorStore.js` tidak memiliki mekanisme backoff atau blacklist untuk endpoint yang gagal. Setiap kali fetch gagal, store langsung retry tanpa delay, menyebabkan infinite loop request ke server.
|
|
|
|
**Solusi / Fix:**
|
|
```javascript
|
|
// ✅ Implementasi blacklist endpoint gagal
|
|
const blacklistedEndpoints = new Set()
|
|
|
|
async function fetchDoctors(endpoint) {
|
|
if (blacklistedEndpoints.has(endpoint)) {
|
|
return [] // skip, sudah di-blacklist
|
|
}
|
|
try {
|
|
return await $fetch(endpoint)
|
|
} catch (error) {
|
|
if (error.status === 500) {
|
|
blacklistedEndpoints.add(endpoint)
|
|
console.warn(`Endpoint blacklisted: ${endpoint}`)
|
|
}
|
|
return []
|
|
}
|
|
}
|
|
```
|
|
|
|
**Prevention:**
|
|
> Semua API fetch HARUS memiliki: (1) error handling, (2) retry limit atau backoff, (3) blacklist mechanism untuk persistent failures. Jangan pernah retry tanpa batas.
|
|
|
|
**Related:** Conversation `c7502197` — "Optimizing Web Antrean Memory Usage", commit `cb3310b`
|
|
|
|
---
|
|
|
|
### [EV-007] — Console.log Verbose Memperlambat Performa
|
|
|
|
| Field | Value |
|
|
|-------|-------|
|
|
| **ID** | EV-007 |
|
|
| **Tanggal** | 2026-05-18 |
|
|
| **Severity** | 🟢 Low |
|
|
| **Environment** | Development |
|
|
| **Status** | ✅ Resolved |
|
|
| **Reporter** | Akbar |
|
|
|
|
**Error Message:**
|
|
> Tidak ada error message, tapi browser DevTools penuh dengan log output, menyebabkan performa menurun terutama di device yang lebih lambat.
|
|
|
|
**Langkah Reproduksi:**
|
|
1. Buka halaman yang menggunakan WebSocket atau QR scanner
|
|
2. Buka browser DevTools → Console
|
|
3. Log membanjir setiap detik dari `useWebSocket.ts` dan QR scanner di `checkIn.vue`
|
|
|
|
**Root Cause:**
|
|
> `console.log` debugging statements di high-frequency code paths (WebSocket message handler yang dipanggil per-detik, QR scanner frame processing) tidak dihapus setelah debugging selesai.
|
|
|
|
**Solusi / Fix:**
|
|
> Cleanup semua `console.log` di:
|
|
> - `composables/useWebSocket.ts` — WebSocket message handler
|
|
> - `pages/CheckInPasien/checkIn.vue` — QR scanner frame processing
|
|
> Hanya sisakan `console.warn` dan `console.error` untuk kondisi yang benar-benar perlu.
|
|
|
|
**Prevention:**
|
|
> Gunakan convention: `console.log` hanya untuk debugging sementara, `console.warn`/`console.error` untuk production logging. Tambahkan lint rule atau pre-commit hook untuk mendeteksi `console.log` yang tersisa.
|
|
|
|
**Related:** Conversation `c7502197` — "Optimizing Web Antrean Memory Usage"
|
|
|
|
---
|
|
|
|
### [EV-006] — Header Origin/Referer Tidak Konsisten di Proxy Routes
|
|
|
|
| Field | Value |
|
|
|-------|-------|
|
|
| **ID** | EV-006 |
|
|
| **Tanggal** | 2026-05-22 |
|
|
| **Severity** | 🟡 Medium |
|
|
| **Environment** | Development |
|
|
| **Status** | ✅ Resolved |
|
|
| **Reporter** | Akbar |
|
|
|
|
**Error Message:**
|
|
> CORS error atau origin validation failure saat memanggil backend API melalui proxy routes. Beberapa request berhasil, beberapa gagal secara intermittent.
|
|
|
|
**Langkah Reproduksi:**
|
|
1. Panggil API via proxy route `stats-api`, `visit-api`, atau `klinik-api`
|
|
2. Beberapa request gagal dengan CORS error
|
|
3. Request yang sama kadang berhasil, kadang gagal
|
|
|
|
**Root Cause:**
|
|
> Setiap proxy route handler (`server/routes/stats-api/`, `visit-api/`, `klinik-api/`) menggunakan header origin dan referer yang berbeda-beda. Backend melakukan validasi origin, dan header yang tidak konsisten menyebabkan intermittent failure.
|
|
|
|
**Solusi / Fix:**
|
|
> Standardisasi semua proxy route handler agar menggunakan origin dan referer yang sama:
|
|
```typescript
|
|
// ✅ Semua proxy routes menggunakan header yang sama
|
|
headers: {
|
|
'Origin': 'http://10.10.150.175:3000',
|
|
'Referer': 'http://10.10.150.175:3000',
|
|
}
|
|
```
|
|
|
|
**Prevention:**
|
|
> Buat shared utility function untuk proxy header configuration agar semua route handler menggunakan config yang sama. Hindari copy-paste header config per file.
|
|
|
|
**Related:** Conversation `97867794` — "Standardizing Header Configurations Across APIs"
|
|
|
|
---
|
|
|
|
### [EV-005] — Duplikasi Tiket di Admin Klinik Loket
|
|
|
|
| Field | Value |
|
|
|-------|-------|
|
|
| **ID** | EV-005 |
|
|
| **Tanggal** | 2026-02-11 |
|
|
| **Severity** | 🟠 High |
|
|
| **Environment** | Development |
|
|
| **Status** | ✅ Resolved |
|
|
| **Reporter** | Akbar |
|
|
|
|
**Error Message:**
|
|
> Daftar pasien di admin klinik menampilkan tiket yang sama dua kali. Setelah check-in, tiket pasien menghilang dari daftar.
|
|
|
|
**Langkah Reproduksi:**
|
|
1. Pasien ambil antrean di anjungan
|
|
2. Buka admin klinik loket
|
|
3. Pasien yang sama muncul 2x di daftar
|
|
4. Setelah check-in, tiket menghilang dari daftar
|
|
|
|
**Root Cause:**
|
|
> WebSocket event handler menambahkan pasien ke `allPatients` tanpa deduplication check. Saat event masuk bersamaan dari multiple sources (initial load + WebSocket), data terduplikasi. Saat check-in, state update menghapus entry yang salah.
|
|
|
|
**Solusi / Fix:**
|
|
```javascript
|
|
// ✅ Deduplication check sebelum add ke allPatients
|
|
function addPatient(patient) {
|
|
const exists = allPatients.value.find(p => p.nomorAntrean === patient.nomorAntrean)
|
|
if (!exists) {
|
|
allPatients.value.push(patient)
|
|
} else {
|
|
// Update existing instead of duplicate
|
|
Object.assign(exists, patient)
|
|
}
|
|
}
|
|
```
|
|
|
|
**Prevention:**
|
|
> Semua operasi mutasi pada `allPatients` harus melalui function yang melakukan deduplication check. Jangan pernah langsung `push` tanpa cek duplikat.
|
|
|
|
**Related:** Commit `c02905e` — "fix duplication and ticket disappear in adminklinik loket"
|
|
|
|
---
|
|
|
|
### [EV-004] — WebSocket Check-in Tidak Trigger UI Update
|
|
|
|
| Field | Value |
|
|
|-------|-------|
|
|
| **ID** | EV-004 |
|
|
| **Tanggal** | 2026-02-10 |
|
|
| **Severity** | 🟠 High |
|
|
| **Environment** | Development |
|
|
| **Status** | ✅ Resolved |
|
|
| **Reporter** | Akbar |
|
|
|
|
**Error Message:**
|
|
> Pasien check-in via QR berhasil (API return success), tapi status di admin loket tidak berubah. UI tetap menampilkan pasien sebagai "belum hadir".
|
|
|
|
**Langkah Reproduksi:**
|
|
1. Pasien scan QR di halaman check-in
|
|
2. API return success — pasien tercatat hadir
|
|
3. Buka admin loket — status pasien masih "belum hadir"
|
|
4. Perlu manual refresh untuk melihat update
|
|
|
|
**Root Cause:**
|
|
> WebSocket event listener untuk check-in event tidak ter-bind dengan benar. Event `checkin_success` diterima oleh WebSocket, tapi handler tidak melakukan state update ke Pinia store.
|
|
|
|
**Solusi / Fix:**
|
|
> Fix event listener binding di `useWebSocket.ts` — pastikan `checkin_success` event memicu update pada `queueStore.allPatients`.
|
|
|
|
**Prevention:**
|
|
> Setiap WebSocket event type harus memiliki dedicated handler yang ter-test. Buat mapping event → handler yang eksplisit.
|
|
|
|
**Related:** Commits `e686dda`, `b6dc252` — "fix socket checkin", "update bug ws checkin loket"
|
|
|
|
---
|
|
|
|
### [EV-003] — HTTPS Implementation Gagal di Check-in
|
|
|
|
| Field | Value |
|
|
|-------|-------|
|
|
| **ID** | EV-003 |
|
|
| **Tanggal** | 2026-02-02 |
|
|
| **Severity** | 🟡 Medium |
|
|
| **Environment** | Development |
|
|
| **Status** | ✅ Resolved |
|
|
| **Reporter** | Akbar |
|
|
|
|
**Error Message:**
|
|
> Check-in via QR tidak berfungsi saat HTTPS aktif. Kamera QR scanner tidak bisa diakses.
|
|
|
|
**Langkah Reproduksi:**
|
|
1. Aktifkan HTTPS di dev server
|
|
2. Buka halaman check-in
|
|
3. QR scanner gagal — kamera tidak muncul
|
|
|
|
**Root Cause:**
|
|
> Browser memerlukan HTTPS untuk akses kamera (MediaDevices API), tapi mixed content policy memblokir request ke backend HTTP. Konfigurasi HTTPS tidak lengkap — SSL certificate self-signed tidak dipercaya browser.
|
|
|
|
**Solusi / Fix:**
|
|
> Fix implementasi HTTPS menggunakan `@vitejs/plugin-basic-ssl` di `nuxt.config.ts`. Konfigurasi dev server untuk HTTPS dengan self-signed cert yang di-trust browser.
|
|
|
|
**Prevention:**
|
|
> Saat menggunakan Web API yang memerlukan secure context (kamera, geolocation), pastikan HTTPS sudah configured end-to-end termasuk backend.
|
|
|
|
**Related:** Commit `c899a71` — "fix https implementation and checkin"
|
|
|
|
---
|
|
|
|
### [EV-002] — Loop & Duplikasi Data di Fetch API
|
|
|
|
| Field | Value |
|
|
|-------|-------|
|
|
| **ID** | EV-002 |
|
|
| **Tanggal** | 2026-01-29 |
|
|
| **Severity** | 🟠 High |
|
|
| **Environment** | Development |
|
|
| **Status** | ✅ Resolved |
|
|
| **Reporter** | Akbar |
|
|
|
|
**Error Message:**
|
|
> Data pasien terduplikasi di daftar antrean. Fetch API dipanggil berulang-ulang dalam loop.
|
|
|
|
**Langkah Reproduksi:**
|
|
1. Buka halaman yang memuat data antrean
|
|
2. Data pasien muncul berkali-kali
|
|
3. Network tab menunjukkan API dipanggil berulang-ulang
|
|
|
|
**Root Cause:**
|
|
> `watch` atau `computed` yang bergantung pada reactive state memicu re-fetch setiap kali state berubah, dan hasil fetch mengubah state lagi — menyebabkan infinite loop.
|
|
|
|
**Solusi / Fix:**
|
|
> Fix logic watch/computed agar tidak circular. Tambahkan guard condition untuk mencegah re-fetch saat data sudah di-load.
|
|
|
|
**Prevention:**
|
|
> Hindari circular dependency antara watcher dan state mutation. Gunakan flag `isLoading` untuk mencegah concurrent fetch.
|
|
|
|
**Related:** Commit `0bd5311` — "fix loop dan duplicate data"
|
|
|
|
---
|
|
|
|
### [EV-001] — Session & Tampilan Screen Tidak Sinkron
|
|
|
|
| Field | Value |
|
|
|-------|-------|
|
|
| **ID** | EV-001 |
|
|
| **Tanggal** | 2026-01-30 |
|
|
| **Severity** | 🟡 Medium |
|
|
| **Environment** | Development |
|
|
| **Status** | ✅ Resolved |
|
|
| **Reporter** | Akbar |
|
|
|
|
**Error Message:**
|
|
> Display screen menampilkan data lama setelah session expire. Setelah re-login, data tidak refresh otomatis.
|
|
|
|
**Langkah Reproduksi:**
|
|
1. Login dan buka display screen
|
|
2. Tunggu session expire (1 jam)
|
|
3. Re-login
|
|
4. Display masih menampilkan data dari session sebelumnya
|
|
|
|
**Root Cause:**
|
|
> Pinia persisted state menyimpan data lama di `localStorage`. Saat session expire dan user re-login, store tidak di-reset — data lama masih tampil.
|
|
|
|
**Solusi / Fix:**
|
|
> Reset persisted state saat login baru. Pastikan display screen melakukan fresh fetch setelah session recovery.
|
|
|
|
**Prevention:**
|
|
> Implementasi session lifecycle hooks: on session expire → clear stale state, on re-login → fresh fetch semua data.
|
|
|
|
**Related:** Commit `8dd94ed` — "update fix session dan tampilan screen"
|
|
|
|
---
|
|
|
|
## 📊 Error Statistics
|
|
|
|
| Bulan | Critical | High | Medium | Low | Total |
|
|
|-------|---------|------|--------|-----|-------|
|
|
| Jan 2026 | 0 | 1 | 1 | 0 | 2 |
|
|
| Feb 2026 | 0 | 3 | 1 | 0 | 4 |
|
|
| Mar 2026 | 0 | 0 | 0 | 0 | 0 |
|
|
| Apr 2026 | 0 | 0 | 0 | 0 | 0 |
|
|
| Mei 2026 | 2 | 2 | 1 | 1 | 6 |
|
|
| **Total** | **2** | **6** | **3** | **1** | **12** |
|
|
|
|
---
|
|
|
|
## 🔁 Recurring Issues
|
|
|
|
> Daftar error yang muncul lebih dari sekali — kandidat untuk refactor/improvement permanen.
|
|
|
|
| Error Pattern | Frekuensi | Action |
|
|
|---------------|-----------|--------|
|
|
| WebSocket disconnect → data tidak sinkron | 3x (EV-004, EV-011, EV-012) | ✅ Implemented: polling fallback 30 detik + auto-reconnect + deterministic client ID |
|
|
| Duplikasi data pasien di daftar | 2x (EV-002, EV-005) | ✅ Implemented: deduplication check di `allPatients` mutation |
|
|
| Session/state stale setelah reconnect | 2x (EV-001, EV-011) | ✅ Implemented: fresh fetch on reconnect + state reset on re-login |
|
|
| Request spam ke endpoint yang gagal | 1x (EV-008) | ✅ Implemented: blacklist + retry limit. **Monitor untuk recurring** |
|
|
| Cross-instance state conflict (loket) | 1x (EV-010) | ✅ Implemented: unique persisted state key per instance. **Audit untuk klinik/penunjang** |
|