# ✅ QMD — Quality Management Document **Project:** Web Antrean — Sistem Manajemen Antrean Rawat Jalan RSSA **Version:** 1.0.0 **Author:** Akbar **Stack:** JavaScript · Vue 3 · TypeScript · Nuxt 3 · Vuetify 3 · Pinia **Last Updated:** 2026-05-25 --- ## 🧠 AI Prompt — Cara Menggunakan Dokumen Ini > Salin prompt berikut ke Claude untuk membantu QA planning: ``` Kamu adalah QA engineer senior untuk project Nuxt 3 + Vue 3 + TypeScript. Project: Web Antrean — Sistem manajemen antrean rawat jalan RSSA. Fitur utama: - Anjungan mandiri (kiosk registrasi pasien, pilih klinik/subspesialis) - Check-in pasien via QR code - Manajemen antrean loket (panggil, skip, recall, selesai) - Manajemen antrean klinik & penunjang - Real-time sync via WebSocket + polling fallback - Dashboard monitoring & statistik - Setting: master data (klinik, loket, penunjang, screen), hak akses (Keycloak role/group) - Cetak tiket via thermal printer Bantu aku membuat: 1. Test plan lengkap (unit, integration, E2E) 2. Test cases untuk fitur di atas 3. Definition of Done (DoD) per story 4. Checklist code review untuk Vue 3 + TypeScript 5. Standar kualitas kode (naming, linting, typing) Format dalam tabel Markdown. Tool: Vitest, Cypress, Vue Test Utils, happy-dom. ``` --- ## 1. Quality Objectives | Objektif | Target | Cara Ukur | |----------|--------|-----------| | Test Coverage (Unit) | > 60% | Vitest coverage report (`npx vitest run --coverage`) | | Bug Rate (prod) | < 5 bug/sprint | Manual tracking / issue log | | Code Review | 100% PR di-review | Git workflow | | TypeScript strict | Minimal `any` type | ESLint + `tsc --noEmit` | | WebSocket Reliability | > 99% message delivery | Monitoring log + polling fallback | | Page Load | < 3 detik | Lighthouse / manual timing di jaringan LAN | --- ## 2. Testing Strategy ### 2.1 Piramida Testing ``` ▲ /E2E\ ← Cypress (browser real) /──────\ / Integ \ ← Vitest + Nuxt Test Utils /──────────\ / Unit Test \ ← Vitest + Vue Test Utils + happy-dom /______________\ ``` ### 2.2 Test Toolchain | Tipe | Tool | Config File | Status | |------|------|-------------|--------| | Unit | Vitest + happy-dom | `vitest.config.ts` | ✅ Terkonfigurasi | | Component | Vue Test Utils (`@vue/test-utils`) | — | ✅ Terinstal | | E2E | Cypress | `cypress.config.ts` | ✅ Terkonfigurasi | | Component (Cypress) | Cypress Component Testing | `cypress.config.ts` → `component` | ✅ Terkonfigurasi | | Linting | ESLint (Nuxt preset) | `eslint.config.mjs` | ✅ Terkonfigurasi | | Type Check | TypeScript (via Nuxt) | `tsconfig.json` → extends `.nuxt/tsconfig.json` | ✅ | | Test Environment | happy-dom | `vitest.config.ts` → `environment: 'happy-dom'` | ✅ | ### 2.3 Test Commands ```bash # Unit & Component Tests npm run test # vitest (watch mode) npm run test:ui # vitest --ui (browser UI) # E2E Tests npm run cypress:open # Cypress interactive npm run cypress:run # Cypress headless # Linting npx eslint . # Type Check npx nuxi typecheck ``` --- ## 3. Test Cases ### 3.1 Unit Tests — Composables | ID | Modul | Test Case | Expected | Status | |----|-------|-----------|----------|--------| | UT-001 | `useAuth.ts` | Login — mengembalikan user data setelah Keycloak auth | `user.value` tidak null, memiliki `id`, `roles`, `groups` | `Todo` | | UT-002 | `useAuth.ts` | Logout — session di-clear dan redirect ke login page | `user.value` menjadi null, navigasi ke `/LoginPage` | `Todo` | | UT-003 | `useQueue.js` | `processNextQueue()` — mengambil pasien berikutnya sesuai loketId | Return pasien dengan status `menunggu` dan `loketId` yang cocok | `Todo` | | UT-004 | `useQueue.js` | `processNextQueue()` — skip pasien dari loket lain | Pasien dari loket lain tidak terproses | `Todo` | | UT-005 | `useWebSocket.ts` | Koneksi sukses — state connected | `isConnected.value === true` setelah open event | `Todo` | | UT-006 | `useWebSocket.ts` | Auto-reconnect setelah disconnect | Reconnect attempt dalam < 5 detik | `Todo` | | UT-007 | `useCheckIn.ts` | Check-in valid QR — update status pasien | Status pasien berubah ke `hadir`, return success | `Todo` | | UT-008 | `useCheckIn.ts` | Check-in invalid QR — error handling | Return error message, status tidak berubah | `Todo` | | UT-009 | `useQRScanner.ts` | Inisialisasi scanner — kamera aktif | Scanner instance terbuat tanpa error | `Todo` | | UT-010 | `useHakAkses.ts` | Fetch permissions — mapping role ke menu | Menu permissions sesuai dengan role & group user | `Todo` | | UT-011 | `useThermalPrint.ts` | Generate tiket — format nomor antrean benar | Output mengandung kode klinik + nomor urut | `Todo` | | UT-012 | `useClinicAPI.ts` | Fetch daftar klinik — return data klinik aktif | Array klinik tidak kosong, setiap item punya `id` & `nama` | `Todo` | ### 3.2 Unit Tests — Stores (Pinia) | ID | Modul | Test Case | Expected | Status | |----|-------|-----------|----------|--------| | UT-013 | `queueStore.js` | `allPatients` — menyimpan & mengembalikan daftar pasien | State `allPatients` terisi array setelah fetch | `Todo` | | UT-014 | `queueStore.js` | `currentProcessingPatient` — isolasi per loket | Setiap loket punya key unik di persisted state | `Todo` | | UT-015 | `clinicStore.js` | Fetch daftar klinik dari API | `clinics` terisi data dari klinik-api | `Todo` | | UT-016 | `doctorStore.js` | Blacklist endpoint gagal | Endpoint yang 500 di-blacklist, tidak di-retry spam | `Todo` | | UT-017 | `loketStore.js` | State loket terisolasi antar loket | Operasi di loket A tidak mempengaruhi loket B | `Todo` | | UT-018 | `masterStore.js` | CRUD master klinik | Create, read, update, delete berjalan tanpa error | `Todo` | | UT-019 | `permissionStore.ts` | Load permission sesuai role | Permission loaded dan accessible via getter | `Todo` | ### 3.3 Unit Tests — Middleware | ID | Modul | Test Case | Expected | Status | |----|-------|-----------|----------|--------| | UT-020 | `auth.ts` | User belum login → redirect ke `/LoginPage` | `navigateTo('/LoginPage')` dipanggil | `Todo` | | UT-021 | `auth.ts` | User sudah login → lanjut ke halaman tujuan | Tidak ada redirect | `Todo` | | UT-022 | `guest.ts` | User sudah login akses `/LoginPage` → redirect ke `/dashboard` | `navigateTo('/dashboard')` dipanggil | `Todo` | | UT-023 | `permissions.ts` | User tanpa akses ke halaman → redirect/block | Akses ditolak, redirect ke halaman authorized | `Todo` | | UT-024 | `checkPageAccess.ts` | Validasi hak akses per halaman berdasarkan group | Halaman hanya bisa diakses sesuai permission | `Todo` | ### 3.4 Component Tests | ID | Komponen | Skenario | Expected | Status | |----|----------|----------|----------|--------| | CT-001 | `PatientCard.vue` | Render data pasien lengkap | Nama, noRM, nomor antrean, status, subspesialis tampil | `Todo` | | CT-002 | `PatientCard.vue` | Status badge warna sesuai status | `menunggu` = kuning, `dipanggil` = biru, `selesai` = hijau | `Todo` | | CT-003 | `CurrentPatientCard.vue` | Tampilkan pasien yang sedang diproses | Data pasien aktif tampil dengan aksi (selesai, skip) | `Todo` | | CT-004 | `QueueActionsCard.vue` | Tombol aksi antrean (panggil, skip, recall) | Semua tombol render dan emit event yang benar | `Todo` | | CT-005 | `TabelPatientData.vue` | Render tabel daftar pasien | Kolom: nama, noRM, antrean, status, aksi tampil benar | `Todo` | | CT-006 | `SideBar.vue` | Menu render sesuai hak akses user | Menu yang tidak diizinkan tidak tampil | `Todo` | | CT-007 | `PageHeader.vue` | Render judul halaman dan breadcrumb | Judul dan navigasi sesuai route aktif | `Todo` | | CT-008 | `AppSnackbar.vue` | Notifikasi muncul dan auto-dismiss | Snackbar tampil 3 detik lalu hilang | `Todo` | | CT-009 | `SelectionDialog.vue` | Dialog pilihan dengan konfirmasi | Pilihan terseleksi, emit event saat konfirmasi | `Todo` | | CT-010 | `ProfileMenu.vue` | Tampil info user dan tombol logout | Nama user tampil, klik logout memanggil `useAuth().logout()` | `Todo` | ### 3.5 E2E Tests (Cypress) | ID | Flow | Steps | Expected | Status | |----|------|-------|----------|--------| | E2E-001 | Login | 1. Buka `/` 2. Redirect ke `/LoginPage` 3. Klik login Keycloak 4. Isi credentials | Redirect ke `/dashboard`, user session aktif | `Skeleton` | | E2E-002 | Anjungan — Ambil Antrean | 1. Buka `/anjungan` 2. Pilih klinik 3. Konfirmasi | Nomor antrean di-generate, tiket tampil | `Todo` | | E2E-003 | Anjungan Eksekutif — Pilih Subspesialis | 1. Buka `/anjungan` 2. Pilih klinik eksekutif 3. Pilih subspesialis 4. Konfirmasi | Antrean tercipta dengan subspesialis terpilih | `Todo` | | E2E-004 | Check-in QR | 1. Buka `/check-in-pasien/check-in` 2. Scan QR valid | Status pasien update ke "hadir", notifikasi sukses | `Todo` | | E2E-005 | Loket — Panggil Pasien | 1. Login sebagai admin loket 2. Buka `/admin-loket` 3. Klik "Panggil Berikutnya" | Pasien berikutnya tampil di current patient card | `Todo` | | E2E-006 | Loket — Skip & Recall | 1. Panggil pasien 2. Klik skip 3. Klik recall | Pasien di-skip lalu bisa di-recall kembali | `Todo` | | E2E-007 | Klinik — Lihat Daftar Pasien | 1. Login sebagai admin klinik 2. Buka `/admin-klinik` | Daftar pasien klinik tampil sesuai klinik user | `Todo` | | E2E-008 | Dashboard — Statistik | 1. Login sebagai superadmin 2. Buka `/dashboard` | Chart statistik dan data antrean tampil | `Todo` | | E2E-009 | Setting — CRUD Master Klinik | 1. Buka `/setting/master-klinik` 2. Tambah klinik 3. Edit 4. Hapus | Data klinik berhasil CRUD tanpa error | `Todo` | | E2E-010 | Setting — Hak Akses | 1. Buka `/setting/hak-akses` 2. Pilih role & group 3. Set permission 4. Simpan | Hak akses tersimpan dan efektif | `Todo` | | E2E-011 | WebSocket Sync | 1. Buka admin loket di tab A 2. Buka display screen di tab B 3. Panggil pasien di tab A | Tab B menampilkan nomor panggil dalam < 2 detik | `Todo` | | E2E-012 | Auth Guard | 1. Tanpa login, akses `/dashboard` | Redirect ke `/LoginPage` | `Todo` | --- ## 4. Definition of Done (DoD) Sebuah task/story dianggap **Done** jika: - [ ] Code sudah diimplementasi dan berjalan di dev server - [ ] Unit test ditulis untuk logic kritis (composable, store) - [ ] TypeScript: tidak ada error pada `npx nuxi typecheck` - [ ] ESLint: tidak ada error (`npx eslint .`) - [ ] Code review dilakukan minimal 1 orang - [ ] Tested manual di browser Chrome (target utama) - [ ] WebSocket sync diverifikasi antar device (jika fitur terkait real-time) - [ ] Responsive layout dicek untuk tablet (anjungan) dan desktop (admin) - [ ] Tidak ada `console.log` debugging yang tertinggal di production path - [ ] State antrean terisolasi per loket (jika fitur terkait loket) - [ ] Polling fallback 30 detik berfungsi sebagai safety net --- ## 5. Code Review Checklist ### General - [ ] Logic mudah dibaca dan dipahami - [ ] Tidak ada dead code atau file `.txt` backup yang tersisa - [ ] Error handling ada di semua `$fetch` / `useFetch` call - [ ] Tidak ada hardcoded IP/URL (gunakan `.env` + `runtimeConfig`) - [ ] Tidak ada `console.log` di high-frequency path (WebSocket handler, polling loop) ### Vue 3 + TypeScript - [ ] `