✅ 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:
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
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
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:
5. Code Review Checklist
General
Vue 3 + TypeScript
Nuxt 3 Specific
Pinia Store
WebSocket
6. Standar Kode
Naming Convention
| Tipe |
Konvensi |
Contoh (Aktual) |
| Page (Vue) |
PascalCase |
Dashboard.vue, AdminLoket.vue |
| Component |
PascalCase |
PatientCard.vue, QueueActionsCard.vue |
| Composable |
camelCase + use prefix |
useWebSocket.ts, useQueue.js |
| Store (Pinia) |
camelCase + Store suffix |
queueStore.js, clinicStore.js |
| Middleware |
camelCase |
auth.ts, permissions.ts |
| Type/Interface |
PascalCase |
User, Permission, ApiResponse<T> |
| Constants |
SCREAMING_SNAKE |
API_BASE_URL, WS_API_URL |
| CSS Class |
kebab-case |
.patient-card, .queue-actions |
| Server API |
[resource].[method].ts |
permission.get.ts, validate-token.post.ts |
| Server Proxy Route |
[...].ts di folder prefix |
server/routes/visit-api/[...].ts |
File Organization Rules
Code Pattern — Composable
7. CI/CD Quality Gates
Catatan: CI/CD belum diimplementasi. Berikut rencana pipeline saat siap.
Manual Quality Gate (Saat Ini)
Sebelum merge / deploy, lakukan checklist manual berikut:
8. Bug Severity Matrix
| Level |
Deskripsi |
Contoh di Web Antrean |
SLA Fix |
| 🔴 Critical |
App crash / data loss / security breach |
WebSocket down total → antrean tidak sync, Keycloak auth bypass, pasien kehilangan antrean |
< 4 jam |
| 🟠 High |
Fitur utama tidak bisa dipakai |
Tombol panggil pasien tidak berfungsi, anjungan tidak bisa generate antrean, QR scanner error |
< 1 hari |
| 🟡 Medium |
Fitur minor terganggu, ada workaround |
Thermal print gagal (pasien masih bisa lihat di layar), statistik dashboard delayed |
< 3 hari |
| 🟢 Low |
UI/kosmetik, tidak mengganggu fungsi |
Alignment card tidak rapi, warna badge sedikit off, tooltip tidak muncul |
Backlog |
Known Issues & Mitigasi
| Issue |
Severity |
Mitigasi Saat Ini |
| WebSocket disconnect saat jaringan LAN tidak stabil |
🔴 |
Auto-reconnect + polling fallback 30 detik |
| Endpoint 500 menyebabkan request spam |
🟠 |
Blacklist endpoint gagal di doctorStore.js |
console.log verbose di WebSocket handler |
🟢 |
Dibersihkan di high-frequency path |
| Race condition antar loket |
🟠 |
State isolasi per loketId + unique storage key |
Mixed JS/TS — beberapa store masih .js |
🟢 |
Migrasi bertahap ke .ts |
9. Technical Debt Tracker
| Item |
Impact |
Priority |
Plan |
Store files masih .js (queueStore, clinicStore, dll) |
Type safety rendah |
🟡 Medium |
Migrasi bertahap ke TypeScript |
queueStore.js terlalu besar (141KB) |
Sulit maintain & test |
🟠 High |
Pecah menjadi sub-stores per concern |
| Tidak ada test coverage saat ini |
Regresi tidak terdeteksi |
🟠 High |
Mulai dari composable kritis |
| CI/CD belum ada |
Manual quality gate |
🟡 Medium |
Setup GitHub Actions |
Beberapa file backup (.txt, old_*.vue) masih ada |
Noise di codebase |
🟢 Low |
Cleanup & gitignore |
10. Changelog
| Versi |
Tanggal |
Author |
Perubahan |
| 1.0.0 |
2026-05-25 |
Akbar |
Initial QMD — dibuat berdasarkan kondisi project aktual |