14 KiB
📋 Project Knowledge — Web Antrean (Sistem Antrian Rumah Sakit)
Dokumen ini berisi knowledge base lengkap, aturan pengkodean, dan workflow wajib untuk project web-antrean. WAJIB DIBACA sebelum melakukan task apapun.
🚨 ATURAN WAJIB (MANDATORY RULES)
Rule 1: Selalu Buat Implementation Plan Sebelum Eksekusi
- SEBELUM menulis kode apapun, buat implementation plan di
docs/DEVPLAN.mdatau artifact - Plan harus mencakup: file yang akan diubah, perubahan spesifik, dan alasan
- Tunggu persetujuan user sebelum eksekusi (kecuali fix minor/typo)
Rule 2: Selalu Tambahkan Komentar di Setiap Fungsi
- Setiap function, method, computed, dan watcher HARUS punya komentar JSDoc/TSDoc
- Format minimum:
/** Deskripsi singkat fungsi ini */ - Untuk fungsi kompleks, tambahkan
@param,@returns,@example - Komentar inline untuk logika yang tidak obvious
// ✅ BENAR
/**
* Mengambil data pasien dari API berdasarkan ID loket
* @param {string} loketId - ID loket yang akan di-fetch
* @returns {Promise<QueuePatient[]>} Daftar pasien dalam antrian
*/
const fetchPatientsForLoket = async (loketId) => { ... }
// ❌ SALAH — tanpa komentar
const fetchPatientsForLoket = async (loketId) => { ... }
Rule 3: Selalu Update Dokumentasi Setelah Perubahan
- DEVLOG.md: Tambahkan entry untuk setiap perubahan signifikan
- DEVPLAN.md: Update status task yang sudah selesai
- PRD.md: Update jika ada perubahan requirements/API/arsitektur
- AGENTS.md: Update jika ada knowledge baru yang penting
Rule 4: Selalu Baca AGENTS.md dan Skills Sebelum Eksekusi
- Baca file ini SEBELUM mulai task apapun
- Baca skill
web-antrean-coding-standardsuntuk konvensi kode - Jangan mengulang kesalahan yang sudah tercatat di bagian Gotchas
Rule 5: Jangan Mengulang Kesalahan yang Sudah Diketahui
- Cek bagian ⚠️ Gotchas & Known Issues sebelum debug
- Cek DEVLOG.md untuk masalah serupa yang pernah diselesaikan
- Jika menemukan masalah baru, catat di DEVLOG dan Gotchas
🏗️ Arsitektur & Tech Stack
| Layer | Teknologi |
|---|---|
| Framework | Nuxt 3 (^3.17.7) dengan SSR |
| UI Library | Vuetify 3 (^3.9.3) + Material Design Icons (@mdi/font) |
| State Management | Pinia (^3.0.3) + pinia-plugin-persistedstate |
| Styling | SCSS (sass-embedded), design tokens di assets/scss/ |
| Auth | Keycloak OAuth2 (custom server-side implementation, bukan nuxt-auth) |
| Database (Server) | SQLite via better-sqlite3 — untuk konfigurasi device & user sync |
| Charting | Chart.js + vue-chartjs + nuxt-charts |
| QR Code | html5-qrcode (scanner) + qrcode.vue / nuxt-qrcode (generator) |
| WebSocket | Custom composable (useWebSocket.ts) ke backend Go |
| Deployment | Docker + docker-compose |
| Testing | Vitest (unit) + Cypress (E2E) |
| Font | Google Fonts (Inter 400-700) |
📁 Struktur Direktori
web-antrean/
├── app.vue # Entry point — store schema migration + loading overlay
├── nuxt.config.ts # Konfigurasi Nuxt, Vuetify, runtime config, proxy
├── .env # Environment variables (API URLs, auth, proxy)
├── docker-compose.yml # Docker deployment config
│
├── .agents/ # Agent rules & skills
│ ├── AGENTS.md # FILE INI — rules & knowledge base
│ └── skills/ # Coding standards & workflow skills
│
├── docs/ # Dokumentasi project
│ ├── DEVLOG.md # Development log (kronologis)
│ ├── DEVPLAN.md # Development plan (task breakdown)
│ └── PRD.md # Product Requirements Document
│
├── assets/scss/ # Design system
│ ├── _colors.scss # Color tokens (CSS variables)
│ ├── _variables.scss # Spacing, breakpoints, etc.
│ ├── _typography.scss # Font styles
│ └── main.scss # Global imports
│
├── components/
│ ├── common/ # Shared: PageHeader, Avatar, AppSnackbar, SelectionDialog
│ ├── layout/ # SideBar, ProfileMenu, ProfilePopup
│ ├── features/ # Feature-specific (antrean, master, monitoring, queue)
│ ├── AdminKlinik/ # Komponen admin klinik eksekutif
│ ├── GrandPaviliun/ # Komponen Grand Paviliun (Gp*)
│ ├── HakAkses/ # Komponen manajemen hak akses
│ ├── MonitorPasien/ # Komponen monitoring pasien
│ ├── checkin/ # Komponen check-in
│ ├── verification/ # Komponen verifikasi akun
│ └── preview/ # Komponen preview
│
├── composables/
│ ├── useAuth.ts # Auth state & session management
│ ├── useWebSocket.ts # WebSocket client dengan auto-reconnect
│ ├── useQueueAPI.ts # API wrapper untuk antrian (verificationApiBaseUrl)
│ ├── useVisitAPI.ts # API wrapper untuk visit (externalApiBaseUrl)
│ ├── useQueueSync.ts # Sinkronisasi antrian antar client
│ ├── useCheckIn.ts # Logika check-in pasien
│ ├── useCheckInHistory.ts # Riwayat check-in
│ ├── useClinicAPI.ts # API wrapper klinik
│ ├── useGrandPaviliun.ts # Logika Grand Paviliun
│ ├── useHakAkses.ts # Manajemen hak akses
│ ├── usePermissions.ts # Permission check helper
│ ├── useQRGenerator.ts # QR code generation
│ ├── useQRScanner.ts # QR code scanning (html5-qrcode)
│ ├── useThermalPrint.ts # Thermal printer (tiket antrian)
│ ├── useSnackbar.ts # Toast notification
│ └── useInfiniteScroll.ts # Infinite scroll pagination
│
├── layouts/
│ ├── default.vue # Main layout — SideBar + middleware auth + checkPageAccess
│ └── empty.vue # Empty layout (untuk halaman tanpa sidebar)
│
├── middleware/
│ ├── auth.ts # Auth check → redirect ke /LoginPage jika belum login
│ ├── guest.ts # Untuk halaman publik
│ ├── checkPageAccess.ts # Cek akses halaman berdasarkan hak akses
│ └── permissions.ts # Auto-sync permissions dari backend (DISABLED)
│
├── pages/ # Semua halaman (lihat detail di PRD.md section 8.1)
│ ├── AdminKlinikRuang/ # [kodeKlinik].vue (~111KB)
│ ├── AdminLoket/ # [id].vue (~58KB)
│ ├── CheckInPasien/ # checkIn.vue (~230KB, LARGEST)
│ ├── Anjungan/ # Display anjungan (kiosk)
│ ├── Setting/ # Master data & konfigurasi
│ └── ...
│
├── server/
│ ├── api/auth/ # Auth endpoints (Keycloak OAuth flow)
│ ├── api/users/ # User management (SQLite-backed)
│ ├── api/config/ # Device configuration (SQLite-backed)
│ ├── api/hak-akses/ # Hak akses management
│ └── utils/ # configDb.ts, sessionStore.ts, userSync.ts
│
├── stores/ # Pinia stores (Single Source of Truth)
│ ├── clinicStore.js # Master data klinik (~1007 lines)
│ ├── queueStore.ts # Antrian pasien (~3302 lines, LARGEST)
│ ├── loketStore.js # Data loket (~549 lines)
│ ├── ruangStore.js # Data ruang klinik (~558 lines)
│ ├── masterStore.js # BACKWARD COMPAT LAYER (jangan tulis langsung!)
│ ├── penunjangStore.js # Data penunjang medis
│ ├── doctorStore.js # Data dokter (fetched from API)
│ └── ... # anjunganStore, screenStore, navItems1, dll
│
├── types/ # TypeScript interfaces & types
│ ├── auth.ts, queue.ts, checkin.ts, setting.ts
│
└── data/
└── users.db # SQLite database (user sync + device config)
🔌 API Endpoints & External Services
Environment Variables (.env)
| Variable | Deskripsi | Value (Juli 2026) |
|---|---|---|
ANTRIAN_API_URL |
API antrian utama (Go backend) | http://10.10.150.131:8089/api/v1 |
VERIFICATION_API_BASE_URL |
Alias untuk ANTRIAN_API_URL | (same) |
VISIT_API_URL |
API visit/kunjungan pasien | http://10.10.123.135:8084/api/v1 |
WS_API_URL |
WebSocket URL | ws://10.10.123.135:8084/api/v1/ws |
EXTERNAL_API_BASE_URL |
External API (JWT validation) | http://10.10.123.135:8084 |
KEYCLOAK_ISSUER |
Keycloak realm URL | https://auth.rssa.top/realms/sandbox |
AUTH_ORIGIN |
Aplikasi origin URL | http://10.10.150.175:3000 |
HOST |
Dev server host | http://10.10.150.175:3000 |
Runtime Config (nuxt.config.ts)
runtimeConfig.public.verificationApiBaseUrl → ANTRIAN_API_URL (antrian API)
runtimeConfig.public.externalApiBaseUrl → VISIT_API_URL (visit API)
runtimeConfig.public.wsBaseUrl → WS_API_URL (WebSocket)
External Backend APIs
-
Antrian API (
verificationApiBaseUrl) — Go backendGET /klinik/reguler— Fetch daftar klinik regulerGET /loket/ruang— Fetch daftar ruangan per klinikGET /loket/{id}— Fetch pasien per loketGET /dokter/{id}— Fetch data dokter per klinikPOST /tiket/generate— Generate tiket antrianPOST /tiket/checkin— Check-in pasienGET /permission— Fetch permission/hak akses
-
Visit API (
externalApiBaseUrl) — Visit/kunjunganGET /visit?klinik_id={id}— Fetch data pasien per klinikPOST /external/validate-token— Validate JWT token
-
WebSocket (
wsBaseUrl)- Real-time queue updates, connected via
useWebSocket.ts
- Real-time queue updates, connected via
PENTING: Semua kode menggunakan
config.public.verificationApiBaseUrldengan fallback hardcoded. Saat ganti IP, ubah di.envlalu restart dev server. Nuxt hanya membaca.envsaat startup!
🗄️ Store Architecture
Hirarki Store
masterStore (BACKWARD COMPAT LAYER — JANGAN TULIS LANGSUNG)
├── clinicStore → Single source of truth untuk data KLINIK
├── loketStore → Data LOKET (counter antrian)
├── ruangStore → Data RUANG per klinik
└── penunjangStore → Data PENUNJANG medis
queueStore → Data ANTRIAN PASIEN (terbesar, 136KB)
doctorStore → Data DOKTER (fetched per klinik)
anjunganStore → Config ANJUNGAN (kiosk)
screenStore → Config SCREEN display
antreanMasukScreenStore → Config screen antrian masuk
navItems1 → Navigation items + hak akses filter
permissionStore → Permission data
verificationStore → Verifikasi akun
Store Schema Migration
app.vuemanagesSTORE_SCHEMA_VERSION(currently3)- Saat versi tidak cocok, semua localStorage Pinia di-clear
- Naikkan versi saat ada perubahan struktur state
🔐 Authentication Flow
- Login: User klik login →
keycloak-login.ts→ redirect ke Keycloak - Callback: Keycloak redirect back →
keycloak-callback.get.ts→ exchange code for token → create session cookie - Session:
session.get.tsvalidates cookie → returns user data - Middleware:
auth.tschecks session on every protected route - User Sync:
userSync.tssyncs Keycloak users to local SQLite DB
⚠️ Gotchas & Known Issues (HARUS DIBACA SEBELUM DEBUG)
-
ENV reload: Nuxt hanya membaca
.envsaat startup. Setelah ubah.env, HARUS restart dev server (Ctrl+C→npm run dev). -
Hardcoded fallback IPs: Banyak file masih punya fallback IP lama. Saat ganti IP, ubah
.env+ restart server. JANGAN cuma ubah satu file. -
totalQuota === 0filter di ruangStore: Klinik dengantotalQuota: 0diskip dari Admin Klinik Ruang. Ini menyembunyikan klinik yang valid tapi belum dikonfigurasi kuotanya. Trade-off yang disengaja. -
masterStore adalah proxy: Jangan langsung tulis data ke masterStore. Selalu gunakan store yang sesuai (clinicStore, loketStore, ruangStore, penunjangStore).
-
File besar (hati-hati saat edit):
CheckInPasien/checkIn.vue(~230KB)queueStore.ts(~136KB)AdminKlinikRuang/[kodeKlinik].vue(~111KB)
-
SQLite DB path:
data/users.db— digunakan untuk konfigurasi device & user sync. Di Docker, di-mount sebagai volume. -
WebSocket auto-upgrade:
useWebSocket.tsotomatis upgradews://kewss://jika halaman diakses via HTTPS. -
Pinia persist
pathstype mismatch: Gunakan// @ts-ignoreuntuk propertipathskarena kompatibel runtime tapi melanggar validasi tipe.
🔗 Key File Quick Reference
| Kebutuhan | File |
|---|---|
| Ganti API URL | .env → restart dev server |
| Auth flow | server/api/auth/ |
| Konfigurasi Nuxt | nuxt.config.ts |
| Data klinik | stores/clinicStore.js |
| Data antrian | stores/queueStore.ts |
| Data ruang | stores/ruangStore.js |
| Data loket | stores/loketStore.js |
| Sidebar/Navigation | stores/navItems1.ts + components/layout/SideBar.vue |
| Design tokens | assets/scss/_colors.scss, _variables.scss |
| Database schema | server/utils/configDb.ts |
| User management | server/api/users/ + server/utils/userSync.ts |
| WebSocket | composables/useWebSocket.ts |
| Thermal print | composables/useThermalPrint.ts |
🚀 Development Commands
npm run dev # Start dev server
npm run dev:https # Start with HTTPS + host 0.0.0.0
npm run build # Production build
npm run preview # Preview production build
npm run test # Run Vitest
docker compose up -d # Deploy production