update skill dan docs

This commit is contained in:
Fanrouver
2026-07-10 11:14:36 +07:00
parent d0eee7d062
commit bbcaf9826c
5 changed files with 584 additions and 26 deletions
+304
View File
@@ -0,0 +1,304 @@
# 📋 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.md` atau 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
```javascript
// ✅ 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-standards` untuk 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
1. **Antrian API** (`verificationApiBaseUrl`) — Go backend
- `GET /klinik/reguler` — Fetch daftar klinik reguler
- `GET /loket/ruang` — Fetch daftar ruangan per klinik
- `GET /loket/{id}` — Fetch pasien per loket
- `GET /dokter/{id}` — Fetch data dokter per klinik
- `POST /tiket/generate` — Generate tiket antrian
- `POST /tiket/checkin` — Check-in pasien
- `GET /permission` — Fetch permission/hak akses
2. **Visit API** (`externalApiBaseUrl`) — Visit/kunjungan
- `GET /visit?klinik_id={id}` — Fetch data pasien per klinik
- `POST /external/validate-token` — Validate JWT token
3. **WebSocket** (`wsBaseUrl`)
- Real-time queue updates, connected via `useWebSocket.ts`
> **PENTING**: Semua kode menggunakan `config.public.verificationApiBaseUrl` dengan fallback hardcoded. Saat ganti IP, ubah di `.env` lalu **restart dev server**. Nuxt hanya membaca `.env` saat 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.vue` manages `STORE_SCHEMA_VERSION` (currently `3`)
- Saat versi tidak cocok, semua localStorage Pinia di-clear
- **Naikkan versi** saat ada perubahan struktur state
---
## 🔐 Authentication Flow
1. **Login**: User klik login → `keycloak-login.ts` → redirect ke Keycloak
2. **Callback**: Keycloak redirect back → `keycloak-callback.get.ts` → exchange code for token → create session cookie
3. **Session**: `session.get.ts` validates cookie → returns user data
4. **Middleware**: `auth.ts` checks session on every protected route
5. **User Sync**: `userSync.ts` syncs Keycloak users to local SQLite DB
---
## ⚠️ Gotchas & Known Issues (HARUS DIBACA SEBELUM DEBUG)
1. **ENV reload**: Nuxt hanya membaca `.env` saat startup. Setelah ubah `.env`, HARUS restart dev server (`Ctrl+C``npm run dev`).
2. **Hardcoded fallback IPs**: Banyak file masih punya fallback IP lama. Saat ganti IP, ubah `.env` + restart server. JANGAN cuma ubah satu file.
3. **`totalQuota === 0` filter di ruangStore**: Klinik dengan `totalQuota: 0` diskip dari Admin Klinik Ruang. Ini menyembunyikan klinik yang valid tapi belum dikonfigurasi kuotanya. Trade-off yang disengaja.
4. **masterStore adalah proxy**: Jangan langsung tulis data ke masterStore. Selalu gunakan store yang sesuai (clinicStore, loketStore, ruangStore, penunjangStore).
5. **File besar** (hati-hati saat edit):
- `CheckInPasien/checkIn.vue` (~230KB)
- `queueStore.ts` (~136KB)
- `AdminKlinikRuang/[kodeKlinik].vue` (~111KB)
6. **SQLite DB path**: `data/users.db` — digunakan untuk konfigurasi device & user sync. Di Docker, di-mount sebagai volume.
7. **WebSocket auto-upgrade**: `useWebSocket.ts` otomatis upgrade `ws://` ke `wss://` jika halaman diakses via HTTPS.
8. **Pinia persist `paths` type mismatch**: Gunakan `// @ts-ignore` untuk properti `paths` karena 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
```bash
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
```
@@ -0,0 +1,173 @@
---
name: web-antrean-coding-standards
description: Aturan dasar pengkodean dan konvensi untuk project web-antrean berbasis Nuxt 3, Vue 3, TypeScript, Pinia, dan Vuetify.
---
# 📜 Web Antrean Coding Standards
Skill ini berisi standar pengkodean wajib yang harus diikuti saat memodifikasi atau membuat kode baru di project `web-antrean`.
## 1. Komentar & Dokumentasi (WAJIB)
- **Tiap Fungsi/Method/Computed/Watcher HARUS dikomentari.**
- Gunakan JSDoc (`/** ... */`) untuk mendeskripsikan tujuan fungsi.
- Jika fungsi kompleks atau memiliki parameter spesifik, gunakan tag `@param`, `@returns`.
- Berikan komentar singkat (`//`) di dalam body fungsi jika ada logika yang tidak langsung jelas (non-obvious).
```typescript
// ✅ CONTOH BENAR
/**
* Menghitung total antrean aktif untuk loket tertentu.
* @param {string} loketId - ID unik dari loket.
* @returns {number} Jumlah antrean berstatus 'menunggu'.
*/
const countActiveQueue = (loketId: string): number => {
// Hanya hitung pasien yang belum dipanggil atau di-skip
return allPatients.value.filter(p => p.loketId === loketId && p.status === 'menunggu').length;
};
```
## 2. Struktur Komponen (Vue 3 / Nuxt 3)
- Gunakan `<script setup lang="ts">`. Sebisa mungkin gunakan TypeScript.
- **Urutan blok dalam Vue SFC (Single File Component):**
1. `<template>`
2. `<script setup lang="ts">`
3. `<style scoped>` (Lebih disukai `<style scoped lang="scss">`)
- **Organisasi dalam `<script setup>`:**
1. `imports` (Vue, composables, stores, types)
2. `defineProps`, `defineEmits`, `defineExpose`
3. State variables (`ref`, `reactive`)
4. Computed properties (`computed`)
5. Watchers (`watch`, `watchEffect`)
6. Functions / Methods
7. Lifecycle hooks (`onMounted`, `onUnmounted`)
## 3. Composables (`composables/`)
- Nama file dan nama fungsi harus diawali dengan `use` (contoh: `useQueueSync.ts`, `export const useQueueSync = () => {}`).
- Fokuskan composable pada satu fitur spesifik (contoh: `useThermalPrint` khusus print, `useWebSocket` khusus WS).
- Jika mengembalikan state reaktif, kembalikan objek berisi `ref` atau `computed`.
## 4. Pinia Stores (`stores/`)
- Gunakan format Setup Store (seperti composable) alih-alih Option Store.
- Berikan tipe eksplisit (TypeScript) untuk state array/object yang kompleks.
- Jangan melakukan mutasi data store lain secara langsung, gunakan actions.
- **PENTING:** Jika ada store baru, daftarkan di `PINIA_STORE_KEYS` di `app.vue` jika perlu di-persist dan bersihkan localStorage jika `STORE_SCHEMA_VERSION` naik.
```typescript
// ✅ CONTOH SETUP STORE
import { defineStore } from 'pinia';
import { ref, computed } from 'vue';
import type { QueuePatient } from '~/types/queue';
export const useMyStore = defineStore('myStore', () => {
// State
const patients = ref<QueuePatient[]>([]);
// Computed
const activePatients = computed(() => patients.value.filter(p => p.status === 'menunggu'));
/**
* Action untuk menambah pasien
* @param {QueuePatient} newPatient
*/
const addPatient = (newPatient: QueuePatient) => {
patients.value.push(newPatient);
};
return { patients, activePatients, addPatient };
});
```
## 5. Integrasi API & Error Handling
- Gunakan `useRuntimeConfig().public` untuk base URL (contoh: `verificationApiBaseUrl`).
- **JANGAN** hardcode IP address (seperti `10.10.123.140`) di dalam kode komponen atau composable. Selalu ambil dari config.
- Gunakan composable wrapper atau `useFetch`/`$fetch` dari Nuxt.
- Harus ada blok `try...catch` untuk setiap pemanggilan API, dengan logging error yang jelas (minimal `console.error`).
## 6. Styling
- Gunakan class Vuetify sebanyak mungkin (`d-flex`, `mt-4`, `text-h5`, `text-primary`).
- Jika butuh custom style, gunakan `<style scoped lang="scss">` dan manfaatkan variabel dari `assets/scss/_colors.scss` atau `_variables.scss` jika memungkinkan.
## 7. Naming Conventions
- **Komponen:** PascalCase (contoh: `PatientCard.vue`, `AdminKlinik.vue`).
- **File/Folder (selain komponen):** camelCase atau kebab-case tergantung standar folder (Nuxt standard: pages biasanya kebab-case atau PascalCase jika spesifik view).
- **Fungsi/Variabel:** camelCase (contoh: `fetchPatients`, `isActive`).
- **Tipe Data (Types/Interfaces):** PascalCase (contoh: `QueuePatient`).
## 8. Aturan Refactoring (Refactoring Rules)
Saat melakukan refactoring (terutama mengkonversi `.js` lama ke `.ts` atau memecah file besar), ikuti aturan wajib berikut:
- **Incremental Refactoring (Bertahap):** Jangan merombak seluruh file raksasa (seperti `queueStore` atau `checkIn.vue`) sekaligus. Pisahkan sebagian logika (contoh: pisahkan API call ke `useQueueAPI`, WS ke `useQueueSync`) secara bertahap untuk meminimalisasi *blast radius* (kerusakan beruntun).
- **Isolasi Logika (Separation of Concerns):** Komponen `.vue` hanya boleh berisi logika UI (presentational). Logika bisnis berat harus dipindah ke `composables/` atau `stores/`.
- **Backward Compatibility (Kompabilitas Mundur):** Jika mengubah struktur *store* yang banyak dipakai (contoh: `masterStore`), jangan langsung menghapus properti lama. Buat *proxy/delegate* ke store baru sampai semua komponen selesai di-update.
- **No Implicit `any`:** Saat memigrasi `.js` ke `.ts`, WAJIB mendefinisikan tipe data/interface yang jelas di direktori `types/`. Sebisa mungkin hindari penggunaan tipe `any`.
- **Pertahankan Business Logic:** Refactoring HANYA mengubah struktur/kebersihan kode, **BUKAN** mengubah alur bisnis kecuali diminta secara spesifik. Pastikan fitur safety seperti *polling fallback 30s* atau *auto-reconnect WS* tidak terhapus tanpa sengaja.
- **Dokumentasikan Perubahan:** Jika refactor mengubah alur arsitektur secara signifikan, selalu catat di `docs/DEVLOG.md` dan perbarui `AGENTS.md`.
## 9. Reusability & Prinsip DRY (Don't Repeat Yourself)
- Jika suatu fungsi, blok UI, atau logika API dipakai di lebih dari dua tempat, **wajib** diekstrak menjadi `Composable` (untuk logika), `Component` (untuk UI), atau file utility di `utils/`.
- Jangan melakukan copy-paste kode panjang antar halaman.
## 10. Penggunaan State (Lokal vs Global)
- **Lokal (`ref` / `reactive`):** Gunakan untuk state yang hanya hidup di satu komponen (contoh: status loading tombol, form input sementara, toggle modal).
- **Global (Pinia):** Gunakan HANYA untuk state yang perlu dibagikan lintas halaman/komponen (contoh: data pasien antrean berjalan, data user login, master data klinik).
## 11. Props & Emits (Komunikasi Antar Komponen)
- Definisikan `props` secara eksplisit menggunakan `defineProps<{ ... }>()` dengan tipe data yang ketat.
- Gunakan `defineEmits<{ ... }>()` untuk event child-to-parent. Hindari memanipulasi prop secara langsung dari child komponen (mutate prop mutation).
## 12. Manajemen Siklus Hidup (Lifecycle & Cleanup)
- Jika menginisiasi *event listener* global (`window.addEventListener`), *timer* (`setInterval`), atau *WebSocket subscription* di `onMounted`, Anda **WAJIB** membersihkannya di `onUnmounted`.
- Kegagalan melakukan *cleanup* akan menyebabkan kebocoran memori (memory leak) terutama di aplikasi SPA (Single Page Application).
## 13. Navigasi & Routing (Nuxt 3)
- Gunakan `<NuxtLink>` untuk navigasi internal di template. JANGAN menggunakan tag `<a>` biasa karena akan memicu *full page reload*.
- Untuk navigasi terprogram (programmatic) di dalam script, gunakan `navigateTo()` atau `useRouter().push()`.
## 14. Keamanan Dasar (Security Practices)
- **JANGAN PERNAH** meletakkan token JWT, password, atau secret key secara hardcode di sisi klien.
- Baca variabel sensitif melalui `useRuntimeConfig()` yang disuplai dari `.env`.
- Selalu percayakan validasi otorisasi di sisi *server* (middleware/Nitro), jangan hanya menyembunyikan tombol di UI.
## 15. Penanganan Feedback UI (Error & Success Boundaries)
- Jangan biarkan error API tertelan diam-diam (`swallowed error`).
- Selalu tampilkan umpan balik ke pengguna jika terjadi kegagalan (misalnya menggunakan komponen `AppSnackbar` yang sudah ada).
- Berikan indikator visual (spinner/loading state) saat memanggil API.
## 16. Magic Numbers & Magic Strings
- Hindari hardcode angka atau string spesifik yang memiliki arti logika bisnis di tengah komponen (contoh: `if (status === 3)` atau `if (role === 'superadmin')`).
- Pindahkan ke file konstan di `constants/` atau jadikan `Enum` di direktori `types/`.
## 17. Penggunaan Proxy API (Bypass CORS)
- Untuk endpoint eksternal yang terhalang CORS (seperti API Visit atau API Antrian asli), panggil selalu via *Proxy Route* bawaan Nuxt Nitro (contoh: panggil `/visit-api/...` atau `/klinik-api/...`).
- Jangan mencoba menebak atau merubah setting header CORS di sisi *client* Vue.
## 18. Konsistensi Design System
- DILARANG melakukan *hardcode* warna HEX/RGB di tag `<style>` (contoh: `color: #ff0000;`).
- Selalu gunakan SCSS variables dari `assets/scss/_colors.scss` (contoh: `color: var(--color-primary);`) atau gunakan *utility classes* bawaan Vuetify.
## 19. Optimasi Performa Vue (v-memo, v-once, Lazy)
- Untuk *list rendering* yang sangat panjang (ratusan pasien), pertimbangkan penggunaan pagination, infinite scroll, atau virtual scrolling.
- Gunakan `LazyComponent` (prefix `Lazy` di Nuxt) untuk modal atau komponen berat yang tidak langsung muncul di layar.
## 20. Penanganan Koneksi Real-time (WebSocket)
- Pastikan ada mekanisme **Auto-Reconnect** dengan *backoff delay*.
- Selalu miliki **Polling Fallback**. Jika WS mati total, sistem harus fallback mengambil data via HTTP `setInterval` setiap 30 detik agar layar antrean tidak *stuck*.
- Cegah duplikasi data pesan (implementasi *deduplication logic* berdasarkan ID unik pesan).
## 21. Isolasi State per Entitas (Loket / Ruang)
- Jangan gunakan variabel state tunggal untuk sesuatu yang berjalan paralel.
- Contoh buruk: `currentPatient` (berisiko loket A tertukar pasien dengan loket B).
- Contoh benar: `currentPatientPerLoket: Record<string, Patient>` (diakses dengan ID loket).
## 22. Format Koding & Tanda Baca
- Ikuti standar *formatting* yang ada: indentasi 2 spasi, gunakan *single quotes* (`'`) untuk string JS/TS, dan selalu gunakan tanda titik koma (`;`) di akhir *statement* script.
## 23. Standar Pengujian (Testing Readiness)
- Setiap logika kalkulasi yang rumit (contoh: perhitungan estimasi waktu tunggu, filter spesialisasi) harus ditulis murni (pure function) agar mudah di-unit test nantinya (Vitest). Jangan mencampur logika ini dengan DOM manipulation.
## 24. Git Workflow & Commit Messages
- Tulis pesan *commit* yang jelas dan bermakna mengikuti pola *Conventional Commits*:
- `feat: ...` (fitur baru)
- `fix: ...` (perbaikan bug)
- `refactor: ...` (perubahan struktur tanpa ubah fitur)
- `docs: ...` (pembaruan dokumentasi)
- Satu *commit* sebaiknya fokus pada satu perubahan logika/fitur saja.
+71 -10
View File
@@ -63,6 +63,66 @@ Format output:
<!-- Tambahkan entry baru di bawah baris ini, urutan terbaru di atas -->
## 2026-07-10 — Migrasi API Endpoint & Project Knowledge Base
**Sprint/Phase:** Phase 7 — Infrastruktur & Dokumentasi
**Durasi:** ~3 jam
**Status:** ✅ Done
### Yang Dikerjakan
- Migrasi endpoint API Antrian dari `10.10.123.140:8089` ke `10.10.150.131:8089` di `.env`
- `VERIFICATION_API_BASE_URL`
- `ANTRIAN_API_URL`
- `PROXY_TARGET_HOST_KLINIK_FALLBACK`
- Pembuatan **Project Knowledge Base** (`AGENTS.md`) di `.agents/` untuk agent AI context
- Dokumentasi lengkap arsitektur, store hierarchy, API endpoints, auth flow, gotchas
- File ini otomatis dimuat sebagai context di setiap session
- Update DEVLOG, DEVPLAN, dan PRD berdasarkan kondisi project terkini
### Keputusan Teknis
> **API endpoint migration**: Backend Antrian API dipindah ke server baru (`10.10.150.131`). Semua konfigurasi ada di `.env` — perubahan `.env` membutuhkan restart dev server karena Nuxt membaca env hanya saat startup. Masih ada technical debt berupa hardcoded fallback IP lama di ~25 file source code.
> **Project Knowledge Base**: Dibuat `.agents/AGENTS.md` sebagai single knowledge document yang mencakup arsitektur, store hierarchy, API config, auth flow, dan known gotchas. Ini mempercepat onboarding dan mengurangi kesalahan saat AI agent bekerja di codebase.
### Masalah & Solusi
| Masalah | Solusi | Referensi |
|---------|--------|-----------|
| API masih connect ke IP lama setelah ubah `.env` | Restart dev server (Ctrl+C → `npm run dev`). Nuxt hanya baca `.env` saat startup | `.env`, `nuxt.config.ts` |
| Hardcoded fallback IP di ~25 file | Documented sebagai tech debt. Ideally semua fallback dihapus, hanya andalkan `.env` | `AGENTS.md` |
| Banyak klinik tidak muncul di Admin Klinik Ruang | Filter `totalQuota === 0` di `ruangStore.js` menyembunyikan klinik dari API yang belum dikonfigurasi | `stores/ruangStore.js` |
### Besok
- [ ] Eliminasi hardcoded fallback IP lama di semua source files
- [ ] Verifikasi koneksi ke endpoint baru (`10.10.150.131:8089`)
- [ ] Investigasi klinik yang hilang dari Admin Klinik Ruang karena filter `totalQuota`
---
## 2026-07-09 — Fix Admin Klinik Ruang Missing Clinics
**Sprint/Phase:** Phase 7 — Bug Fixing
**Durasi:** ~1 jam
**Status:** ✅ Done
### Yang Dikerjakan
- Investigasi bug di halaman Admin Klinik Ruang (`/adminklinikruang`) — hanya 5 klinik muncul dari total ~23 klinik
- Root cause: Filter `totalQuota === 0` di `ruangStore.js` (`fetchRuangFromAPI()`) menyaring klinik yang:
1. Tidak ditemukan di clinicStore (default `totalQuota: 0`)
2. Belum dikonfigurasi kuotanya di seed data
- Fix: Menghapus kedua filter `totalQuota === 0` (line 387-391 dan line 480-483)
- User kemudian me-revert fix ini (mengembalikan filter) — menunjukkan filter ini memang diperlukan untuk business logic tertentu
### Keputusan Teknis
> Filter `totalQuota === 0` ternyata berfungsi ganda: (1) menyembunyikan klinik yang memang tidak aktif, (2) tapi juga menyembunyikan klinik baru dari API yang belum dikonfigurasi. Trade-off ini perlu didiskusikan dengan PO.
### Masalah & Solusi
| Masalah | Solusi | Referensi |
|---------|--------|-----------|
| Admin Klinik Ruang hanya tampil 5 klinik | Ditemukan filter `totalQuota === 0` di `ruangStore.fetchRuangFromAPI()` | `stores/ruangStore.js:387-391, 480-483` |
| Fix di-revert oleh user | Filter diperlukan untuk business logic — perlu pendekatan alternatif (misal: tampilkan tapi tandai sebagai "belum dikonfigurasi") | — |
---
## 2026-06-23 — Refactoring queueStore.js ke TypeScript (Phase 2: WebSocket & Typings)
**Sprint/Phase:** Phase 6 (Verifikasi Akun & Kiosk) / Refactoring Technical Debt
@@ -668,13 +728,14 @@ Format output:
| Metrik | Value |
|--------|-------|
| Total hari dev | ~50+ hari (Jan 2026 — Mei 2026) |
| Fase project | 5 fase (Setup → Fondasi → Hak Akses → Eksekutif → Stabilisasi) |
| Fitur selesai | 8 modul utama (Anjungan, Check-in, Loket, Klinik, Penunjang, Dashboard, Setting, Hak Akses) |
| Total commits | 80+ commits |
| Bug ditemukan | 15+ (WebSocket, loket interference, memory, display sync) |
| Bug diselesaikan | 15+ |
| Halaman dibuat | 28 halaman |
| Composables | 16 composable |
| Pinia Stores | 13 stores |
| Komponen | 20+ komponen |
| Total hari dev | ~60+ hari (Jan 2026 — Juli 2026) |
| Fase project | 7 fase (Setup → Fondasi → Hak Akses → Eksekutif → Stabilisasi → Verifikasi → Infrastruktur) |
| Fitur selesai | 8 modul utama + dokumentasi + migrasi infra |
| Total commits | 90+ commits |
| Bug ditemukan | 18+ (WebSocket, loket interference, memory, display sync, missing clinics, API endpoint) |
| Bug diselesaikan | 18+ |
| Halaman dibuat | 28+ halaman |
| Composables | 18 composable |
| Pinia Stores | 14 stores |
| Komponen | 25+ komponen |
| Dokumentasi | AGENTS.md, DEVLOG.md, DEVPLAN.md, PRD.md, API_ENDPOINTS_CLINIC_DOCTOR.md |
+28 -9
View File
@@ -1,10 +1,10 @@
# 🗺️ DEVPLAN — Development Plan
**Project:** Web Antrean — Sistem Manajemen Antrean Rawat Jalan RSSA
**Version:** 1.0.0
**Version:** 1.1.0
**Author:** Akbar
**Stack:** JavaScript · Vue 3 · TypeScript · Nuxt 3 · Vuetify 3 · Pinia
**Last Updated:** 2026-05-25
**Last Updated:** 2026-07-10
---
@@ -45,8 +45,8 @@ Format dalam tabel Markdown yang terstruktur.
## 1. Project Timeline
```
[Start]──Phase 0──Phase 1──Phase 2──Phase 3──Phase 4──Phase 5──Phase 6──[Launch]
Setup Fondasi Inti API Hak Akses Eksekutif Stabilisasi Verifikasi
[Start]──Phase 0──Phase 1──Phase 2──Phase 3──Phase 4──Phase 5──Phase 6──Phase 7──[Launch]
Setup Fondasi Inti API Hak Akses Eksekutif Stabilisasi Verifikasi Infrastruktur
```
| Fase | Nama | Durasi | Target | Status |
@@ -57,7 +57,8 @@ Format dalam tabel Markdown yang terstruktur.
| Phase 3 | Hak Akses & Keycloak | 2 Minggu | Apr 2026 | ✅ Done |
| Phase 4 | Fitur Eksekutif & Docker | 1 Minggu | Pertengahan Mei | ✅ Done |
| Phase 5 | Stabilisasi & Dokumentasi | 2 Minggu | Akhir Mei 2026 | ✅ Done |
| Phase 6 | Verifikasi Akun & Kiosk | 2 Minggu | Juni 2026 | 🔄 In Progress |
| Phase 6 | Verifikasi Akun & Kiosk | 2 Minggu | Juni 2026 | ✅ Done |
| Phase 7 | Infrastruktur & Dokumentasi | Ongoing | Juli 2026 | 🔄 In Progress |
---
@@ -145,6 +146,19 @@ Format dalam tabel Markdown yang terstruktur.
| Fitur pindah klinik pada dashboard admin | 8 jam | Phase 2 | ✅ Done |
| Halaman Detail Akun Verifikasi | 4 jam | Phase 3 | ✅ Done |
| Implementasi Proxy Routes (CORS) | 8 jam | Phase 2 | ✅ Done |
| Refactoring queueStore.js ke TypeScript | 8 jam | Phase 2 | ✅ Done |
| Ekstraksi useQueueSync composable | 4 jam | Phase 2 | ✅ Done |
### Phase 7 — Infrastruktur & Dokumentasi
| Task | Estimasi | Dependencies | Status |
|------|----------|--------------|--------|
| Migrasi API endpoint (123.140 → 150.131) | 2 jam | — | ✅ Done |
| Pembuatan Project Knowledge Base (AGENTS.md) | 3 jam | — | ✅ Done |
| Update DEVLOG, DEVPLAN, PRD | 2 jam | — | ✅ Done |
| Fix Admin Klinik Ruang missing clinics | 1 jam | Phase 2 | ✅ Done |
| Eliminasi hardcoded fallback IP di source files | 4 jam | Task 1 | ⏳ Pending |
| SQLite config → External API migration | 8 jam | Phase 2 | ⏳ Pending |
| Production deployment & monitoring | 8 jam | All | ⏳ Pending |
---
@@ -157,12 +171,12 @@ Nuxt 3 + TypeScript
├── Vuetify 3 (UI Framework)
│ └── Material Design Icons
├── Nuxt Nitro (Server Engine)
│ └── Server Routes (CORS Proxy API)
│ └── Server API Routes + SQLite (better-sqlite3)
├── Auth Layer
│ └── Keycloak SSO (OIDC/OAuth 2.0)
├── API Layer
│ ├── Visit API (10.10.123.135:8084)
│ └── Antrian API (10.10.123.140:8089)
│ └── Antrian API (10.10.150.131:8089) ← UPDATED
└── Real-time Layer
└── Native Browser WebSocket
```
@@ -194,10 +208,12 @@ npm run _command_dev
AUTH_ORIGIN="http://10.10.150.175:3000"
KEYCLOAK_CLIENT_ID="akbar-test"
KEYCLOAK_ISSUER="https://auth.rssa.top/realms/sandbox"
ANTRIAN_API_URL="http://10.10.123.140:8089/api/v1"
ANTRIAN_API_URL="http://10.10.150.131:8089/api/v1" # UPDATED Juli 2026
VERIFICATION_API_BASE_URL="http://10.10.150.131:8089/api/v1" # UPDATED Juli 2026
VISIT_API_URL="http://10.10.123.135:8084/api/v1"
WS_API_URL="ws://10.10.123.135:8084/api/v1/ws"
PROXY_CLIENT_ORIGIN="http://10.10.150.175:3000"
PROXY_TARGET_HOST_KLINIK_FALLBACK="10.10.150.131:8089" # UPDATED Juli 2026
```
---
@@ -232,7 +248,9 @@ docs: update DEVPLAN
| 🔐 Auth & Roles | Keycloak jalan, routing terlindungi middleware | Apr 2026 | ✅ Done |
| 🏥 Anjungan Ready | Pasien bisa check-in & ambil tiket lancar | Pertengahan Mei | ✅ Done |
| 🛡️ Stability Pass | Tidak ada leak, isolasi loket aman, no WS drift | Akhir Mei 2026 | ✅ Done |
| 🚀 Production Go-Live | Deployment docker di server production | Q2/Q3 2026 | 🔄 Pending |
| 🔄 TypeScript Migration | queueStore refactored ke TS, composable extracted | Juni 2026 | ✅ Done |
| 📡 API Endpoint Migration | Antrian API pindah ke server baru (150.131) | Juli 2026 | ✅ Done |
| 🚀 Production Go-Live | Deployment docker di server production | Q3 2026 | 🔄 Pending |
---
@@ -240,4 +258,5 @@ docs: update DEVPLAN
| Versi | Tanggal | Author | Perubahan |
|-------|---------|--------|-----------|
| 1.1.0 | 2026-07-10 | Akbar | Phase 7: migrasi API, knowledge base, update docs |
| 1.0.0 | 2026-05-25 | Akbar | Initial plan — direkonstruksi berdasarkan timeline aktual |
+8 -7
View File
@@ -1,11 +1,11 @@
# 📋 PRD — Product Requirements Document
**Project:** Web Antrean — Sistem Manajemen Antrean Rawat Jalan RSSA
**Version:** 1.0.0
**Status:** `In Review`
**Version:** 1.1.0
**Status:** `In Progress`
**Author:** Akbar
**Stack:** JavaScript · Vue 3 · TypeScript · Nuxt 3 · Vuetify 3 · Pinia
**Last Updated:** 2026-05-25
**Last Updated:** 2026-07-10
---
@@ -195,7 +195,7 @@ Rumah Sakit RSSA menghadapi masalah antrean rawat jalan yang tidak terstruktur:
| Service | Base URL | Keterangan |
|---------|----------|------------|
| Visit API | `http://10.10.123.135:8084/api/v1` | Data kunjungan & antrean utama |
| Antrian API (Klinik) | `http://10.10.123.140:8089/api/v1` | Verifikasi & data klinik/dokter |
| Antrian API (Klinik) | `http://10.10.150.131:8089/api/v1` | Verifikasi & data klinik/dokter |
| WebSocket | `ws://10.10.123.135:8084/api/v1/ws` | Real-time queue update |
### 7.3 Arsitektur Sistem
@@ -211,8 +211,8 @@ Rumah Sakit RSSA menghadapi masalah antrean rawat jalan yang tidak terstruktur:
┌──────────▼──────────┐ ┌────▼───────────────┐
│ Nuxt Server (Nitro) │ │ WebSocket Server │
│ server/api/ │ │ ws://10.10.123. │
server/routes/ │ │ 135:8084/api/v1/ws│
│ (Proxy + API layer) │ └────────────────────┘
SQLite (users.db) │ │ 135:8084/api/v1/ws│
│ (Config + Users) │ └────────────────────┘
└──────────┬──────────┘
│ HTTP Proxy (CORS bypass)
┌──────────▼──────────────────────────────────┐
@@ -227,7 +227,7 @@ Rumah Sakit RSSA menghadapi masalah antrean rawat jalan yang tidak terstruktur:
| Proxy Path | Target Backend | Keterangan |
|------------|---------------|------------|
| `/visit-api/**` | `http://10.10.123.135:8084/api/v1/**` | Data kunjungan pasien |
| `/klinik-api/**` | `http://10.10.123.140:8089/api/v1/**` | Data klinik & dokter |
| `/klinik-api/**` | `http://10.10.150.131:8089/api/v1/**` | Data klinik & dokter |
| `/stats-api/**` | `http://10.10.123.135:8084/api/v1/**` | Statistik dashboard |
### 7.5 Struktur Folder
@@ -405,4 +405,5 @@ export interface ApiResponse<T> {
| Versi | Tanggal | Author | Perubahan |
|-------|---------|--------|-----------|
| 1.1.0 | 2026-07-10 | Akbar | Update API endpoints (150.131), arsitektur diagram, proxy routes, Phase 7 |
| 1.0.0 | 2026-05-25 | Akbar | Initial PRD — dibuat berdasarkan kondisi project aktual |