# Rancangan Sistem eKoas
## Aplikasi Pengelolaan Kepaniteraan Klinik Fakultas Kedokteran & Rumah Sakit Pendidikan

| Keterangan | Isi |
|---|---|
| Nama sistem | eKoas (nama kerja, dapat diganti) |
| Jenis | Aplikasi web berbasis Progressive Web App (PWA) |
| Pengguna | Mahasiswa profesi dokter, pembimbing klinik, koordinator stase, admin fakultas, admin RS |
| Versi dokumen | 1.0 (draf rancangan awal) |

admin|65d4f2ed4cd2
---

## Daftar Isi

1. [Latar Belakang](#1-latar-belakang)
2. [Tujuan dan Ruang Lingkup](#2-tujuan-dan-ruang-lingkup)
3. [Aktor dan Hak Akses](#3-aktor-dan-hak-akses)
4. [Arsitektur Sistem](#4-arsitektur-sistem)
5. [Modul dan Kebutuhan Fungsional](#5-modul-dan-kebutuhan-fungsional)
6. [Alur Proses Bisnis](#6-alur-proses-bisnis)
7. [Rancangan Database](#7-rancangan-database)
8. [Rancangan API](#8-rancangan-api)
9. [Rancangan Antarmuka](#9-rancangan-antarmuka)
10. [Kebutuhan Non-Fungsional](#10-kebutuhan-non-fungsional)
11. [Keamanan dan Pelindungan Data](#11-keamanan-dan-pelindungan-data)
12. [Teknologi dan Lingkungan](#12-teknologi-dan-lingkungan)
13. [Tahapan Pengembangan](#13-tahapan-pengembangan)
14. [Risiko dan Mitigasi](#14-risiko-dan-mitigasi)

---

## 1. Latar Belakang

Program profesi dokter (Kepaniteraan Klinik) mewajibkan mahasiswa menjalani rotasi di berbagai bagian (stase) Rumah Sakit Pendidikan. Selama rotasi, mahasiswa harus mencatat kasus dan tindakan, mendapatkan verifikasi pembimbing, menjalani penilaian berbasis kerja, serta memenuhi target kompetensi sesuai Standar Kompetensi Dokter Indonesia (SKDI).

Permasalahan yang umum terjadi saat ini:

- Logbook masih berupa buku fisik atau formulir daring yang terpisah-pisah.
- Tanda tangan dan verifikasi pembimbing dikejar secara manual.
- Nilai tersebar di kertas dan berbagai berkas, sehingga rekap memakan waktu.
- Fakultas sulit memantau capaian kompetensi mahasiswa secara *real-time*.
- Rumah sakit tidak memiliki gambaran pasti jumlah dan identitas mahasiswa yang bertugas di tiap bagian pada hari tertentu.

## 2. Tujuan dan Ruang Lingkup

### 2.1 Tujuan

1. Mendigitalisasi seluruh siklus kepaniteraan klinik: rotasi, jadwal, presensi, logbook, penilaian, dan pelaporan.
2. Mempercepat verifikasi dan penilaian oleh pembimbing klinik melalui perangkat mobile.
3. Menyediakan pemantauan capaian kompetensi SKDI secara *real-time* bagi mahasiswa dan fakultas.
4. Menyediakan data yang akurat untuk evaluasi pendidikan dan akreditasi.

### 2.2 Ruang Lingkup (Termasuk)

- Manajemen data master (mahasiswa, pembimbing, stase, kompetensi SKDI).
- Manajemen rotasi stase dan kelompok mahasiswa.
- Jadwal jaga dan presensi (QR code dan geolokasi).
- Logbook kasus dan tindakan dengan verifikasi pembimbing.
- Penilaian berbasis kerja (Mini-CEX, DOPS, CbD, penilaian profesionalisme, ujian akhir stase).
- Refleksi dan umpan balik dua arah.
- Pengumuman dan notifikasi.
- Dashboard dan laporan.

### 2.3 Di Luar Ruang Lingkup (Versi 1)

- Integrasi langsung dengan SIMRS dan SIAKAD (direncanakan di fase berikutnya).
- Modul e-learning dan bank soal.
- Aplikasi native di Play Store / App Store (dapat menyusul melalui Capacitor).

---

## 3. Aktor dan Hak Akses

| Aktor | Deskripsi | Hak Akses Utama |
|---|---|---|
| **Mahasiswa** (dokter muda) | Mahasiswa yang menjalani kepaniteraan | Melihat jadwal & rotasi, presensi, mengisi logbook, melihat nilai & capaian, menulis refleksi, memberi umpan balik stase |
| **Pembimbing Klinik** (preseptor) | Dokter/dokter spesialis RS yang membimbing | Memverifikasi logbook, mengisi penilaian, memberi umpan balik, melihat mahasiswa bimbingannya |
| **Koordinator Stase** | Kepala/koordinator pendidikan di tiap bagian | Mengatur jadwal jaga, menetapkan pembimbing, memantau mahasiswa di bagiannya, input nilai ujian akhir stase |
| **Admin Fakultas** | Bagian pendidikan profesi FK | Mengelola data master, menyusun rotasi, rekap nilai, laporan, pengumuman |
| **Admin RS** | Komkordik / bagian diklat RS | Melihat kapasitas bagian, data mahasiswa aktif, laporan presensi |
| **Super Admin** | Tim TI | Manajemen pengguna, peran, konfigurasi sistem, audit log |

### 3.1 Matriks Hak Akses Ringkas

| Fitur | Mahasiswa | Pembimbing | Koord. Stase | Admin FK | Admin RS |
|---|:-:|:-:|:-:|:-:|:-:|
| Data master | – | – | Lihat | Kelola | Lihat |
| Rotasi stase | Lihat (milik sendiri) | Lihat | Lihat (bagiannya) | Kelola | Lihat |
| Jadwal jaga | Lihat | Lihat | Kelola | Lihat | Lihat |
| Presensi | Isi | Lihat | Lihat & koreksi | Lihat | Lihat |
| Logbook | Isi | Verifikasi | Lihat | Lihat | – |
| Penilaian | Lihat (milik sendiri) | Isi | Isi & lihat | Lihat & rekap | – |
| Umpan balik stase | Isi | – | Lihat (anonim) | Lihat (anonim) | – |
| Laporan | Portofolio sendiri | Mahasiswa bimbingan | Bagiannya | Semua | Presensi & kapasitas |

---

## 4. Arsitektur Sistem

### 4.1 Gambaran Umum

Sistem menggunakan arsitektur *client–server* dengan pemisahan frontend dan backend:

- **Frontend**: Single Page Application yang dibangun dengan Vite, dipasang sebagai PWA agar dapat di-install di Android dan iPhone.
- **Backend**: REST API berbasis PHP (Laravel).
- **Database**: MySQL/MariaDB.
- **Layanan pendukung**: penyimpanan berkas, antrean (*queue*) untuk notifikasi, dan layanan push notification.

```mermaid
flowchart LR
    subgraph Klien
        A[Browser / PWA<br/>Android]
        B[Browser / PWA<br/>iPhone]
        C[Browser<br/>Desktop]
    end

    subgraph Server
        D[Nginx + HTTPS]
        E[Frontend Statis<br/>Hasil build Vite]
        F[Backend API<br/>Laravel]
        G[(MySQL / MariaDB)]
        H[Queue Worker<br/>Notifikasi & Laporan]
        I[(Penyimpanan Berkas)]
        J[(Redis<br/>Cache & Queue)]
    end

    A & B & C -->|HTTPS| D
    D --> E
    D -->|/api| F
    F --> G
    F --> I
    F --> J
    J --> H
    H -->|Web Push| A & B
```

### 4.2 Arsitektur Frontend

| Komponen | Pilihan |
|---|---|
| Build tool | Vite |
| Framework | Vue 3 (Composition API) atau React |
| Styling | Tailwind CSS |
| State management | Pinia (Vue) / Zustand (React) |
| HTTP client | Axios |
| PWA | `vite-plugin-pwa` (Workbox) |
| Penyimpanan offline | IndexedDB (melalui library seperti Dexie.js) |
| Pemindai QR | `html5-qrcode` atau sejenis |

### 4.3 Arsitektur Backend

| Komponen | Pilihan |
|---|---|
| Framework | Laravel (versi LTS/stabil terbaru) |
| Autentikasi | Laravel Sanctum (token) |
| Otorisasi | Role & permission (misalnya `spatie/laravel-permission`) |
| Queue | Redis + Laravel Queue |
| Notifikasi push | Web Push (VAPID) |
| Ekspor laporan | PDF (DomPDF/Snappy), Excel (Laravel Excel) |
| Audit log | `spatie/laravel-activitylog` atau tabel audit khusus |

---

## 5. Modul dan Kebutuhan Fungsional

Kode kebutuhan: **KF-[modul]-[nomor]**. Prioritas: **P1** (MVP), **P2** (fase 2), **P3** (fase 3).

### 5.1 Modul Autentikasi & Profil (AUTH)

| Kode | Kebutuhan | Prioritas |
|---|---|:-:|
| KF-AUTH-01 | Pengguna dapat login menggunakan NIM/NIP/email dan kata sandi | P1 |
| KF-AUTH-02 | Sistem mengarahkan pengguna ke dashboard sesuai perannya | P1 |
| KF-AUTH-03 | Pengguna dapat mengubah kata sandi dan memperbarui profil | P1 |
| KF-AUTH-04 | Fitur lupa kata sandi melalui email | P1 |
| KF-AUTH-05 | Satu akun dapat memiliki lebih dari satu peran (misal pembimbing sekaligus koordinator) | P1 |
| KF-AUTH-06 | Autentikasi dua faktor (2FA) untuk admin | P2 |
| KF-AUTH-07 | Login SSO dengan akun universitas | P3 |

### 5.2 Modul Data Master (MSTR)

| Kode | Kebutuhan | Prioritas |
|---|---|:-:|
| KF-MSTR-01 | Admin FK mengelola data mahasiswa (impor massal dari Excel) | P1 |
| KF-MSTR-02 | Admin FK mengelola data pembimbing klinik | P1 |
| KF-MSTR-03 | Admin FK mengelola data stase/bagian (nama, durasi, kapasitas, lokasi) | P1 |
| KF-MSTR-04 | Admin FK mengelola daftar kompetensi SKDI (penyakit & keterampilan beserta levelnya) | P1 |
| KF-MSTR-05 | Admin FK menetapkan target kompetensi per stase | P1 |
| KF-MSTR-06 | Admin FK mengelola data rumah sakit/wahana (RS utama & RS jejaring) | P1 |
| KF-MSTR-07 | Admin FK mengelola templat formulir penilaian | P2 |

### 5.3 Modul Rotasi Stase (ROT)

| Kode | Kebutuhan | Prioritas |
|---|---|:-:|
| KF-ROT-01 | Admin FK membuat angkatan/periode kepaniteraan | P1 |
| KF-ROT-02 | Admin FK membentuk kelompok mahasiswa | P1 |
| KF-ROT-03 | Admin FK menyusun jadwal rotasi (kelompok → stase → tanggal mulai/selesai) | P1 |
| KF-ROT-04 | Sistem memvalidasi bentrok jadwal dan kapasitas stase | P1 |
| KF-ROT-05 | Koordinator stase menetapkan pembimbing untuk tiap mahasiswa | P1 |
| KF-ROT-06 | Mahasiswa melihat rotasi dirinya (stase aktif, berikutnya, dan yang telah selesai) | P1 |
| KF-ROT-07 | Pencatatan cuti, sakit, atau pengulangan stase | P2 |
| KF-ROT-08 | Generator rotasi otomatis berdasarkan jumlah kelompok dan stase | P3 |

### 5.4 Modul Jadwal Jaga & Presensi (JDW)

| Kode | Kebutuhan | Prioritas |
|---|---|:-:|
| KF-JDW-01 | Koordinator stase menyusun jadwal jaga (pagi/sore/malam) per mahasiswa | P2 |
| KF-JDW-02 | Mahasiswa melihat jadwal jaga di kalender | P2 |
| KF-JDW-03 | Presensi masuk/pulang dengan memindai QR code lokasi | P2 |
| KF-JDW-04 | Validasi geolokasi (radius area RS) saat presensi | P2 |
| KF-JDW-05 | QR code lokasi bersifat dinamis (berganti berkala) untuk mencegah pemalsuan | P2 |
| KF-JDW-06 | Pengajuan izin/sakit beserta lampiran, disetujui koordinator | P2 |
| KF-JDW-07 | Rekap kehadiran dan keterlambatan otomatis | P2 |
| KF-JDW-08 | Permintaan tukar jadwal jaga antar-mahasiswa dengan persetujuan koordinator | P3 |

### 5.5 Modul Logbook (LOG)

| Kode | Kebutuhan | Prioritas |
|---|---|:-:|
| KF-LOG-01 | Mahasiswa mencatat **kasus**: tanggal, lokasi (poli/bangsal/IGD/OK), identitas pasien anonim (inisial, usia, jenis kelamin), diagnosis, kompetensi SKDI terkait, tingkat keterlibatan | P1 |
| KF-LOG-02 | Mahasiswa mencatat **tindakan/keterampilan**: jenis tindakan, kompetensi SKDI terkait, tingkat keterlibatan | P1 |
| KF-LOG-03 | Tingkat keterlibatan: *Observasi*, *Membantu*, *Melakukan di bawah supervisi*, *Melakukan mandiri* | P1 |
| KF-LOG-04 | Mahasiswa memilih pembimbing yang memverifikasi entri | P1 |
| KF-LOG-05 | Pembimbing memverifikasi atau menolak entri (dengan alasan) | P1 |
| KF-LOG-06 | Verifikasi massal: pembimbing dapat menyetujui beberapa entri sekaligus | P1 |
| KF-LOG-07 | Entri yang sudah terverifikasi tidak dapat diubah mahasiswa | P1 |
| KF-LOG-08 | Pencarian kompetensi SKDI dengan fitur *autocomplete* | P1 |
| KF-LOG-09 | Logbook dapat diisi saat offline dan tersinkron otomatis saat online | P2 |
| KF-LOG-10 | Verifikasi melalui QR: mahasiswa menampilkan QR entri, pembimbing memindai dan menyetujui | P3 |

### 5.6 Modul Capaian Kompetensi (KOMP)

| Kode | Kebutuhan | Prioritas |
|---|---|:-:|
| KF-KOMP-01 | Sistem menghitung capaian kompetensi dari entri logbook terverifikasi | P1 |
| KF-KOMP-02 | Mahasiswa melihat progres per stase: target vs. tercapai | P1 |
| KF-KOMP-03 | Admin FK & koordinator melihat capaian seluruh mahasiswa (tabel & grafik) | P1 |
| KF-KOMP-04 | Peringatan dini: mahasiswa dengan capaian < ambang batas pada pertengahan stase | P2 |
| KF-KOMP-05 | Peta capaian SKDI kumulatif selama seluruh kepaniteraan | P2 |

### 5.7 Modul Penilaian (NILAI)

| Kode | Kebutuhan | Prioritas |
|---|---|:-:|
| KF-NILAI-01 | Formulir **Mini-CEX** digital | P1 |
| KF-NILAI-02 | Formulir **DOPS** digital | P1 |
| KF-NILAI-03 | Formulir **Case-based Discussion (CbD)** digital | P2 |
| KF-NILAI-04 | Penilaian **profesionalisme/sikap** | P1 |
| KF-NILAI-05 | Input nilai **ujian akhir stase** (ujian kasus/OSCE/tulis) oleh koordinator | P1 |
| KF-NILAI-06 | Sistem menghitung nilai akhir stase berdasarkan bobot yang dapat dikonfigurasi | P1 |
| KF-NILAI-07 | Mahasiswa dapat meminta penilaian (*request*) kepada pembimbing | P2 |
| KF-NILAI-08 | Mahasiswa melihat nilai dan umpan balik setelah dipublikasikan | P1 |
| KF-NILAI-09 | Penguncian nilai setelah finalisasi oleh koordinator | P1 |

### 5.8 Modul Refleksi & Umpan Balik (FDBK)

| Kode | Kebutuhan | Prioritas |
|---|---|:-:|
| KF-FDBK-01 | Mahasiswa menulis refleksi kasus/pengalaman belajar | P2 |
| KF-FDBK-02 | Pembimbing memberi komentar pada refleksi | P2 |
| KF-FDBK-03 | Mahasiswa mengisi evaluasi stase dan pembimbing di akhir rotasi (anonim) | P2 |
| KF-FDBK-04 | Rekap evaluasi stase untuk koordinator dan admin FK | P2 |

### 5.9 Modul Pengumuman & Notifikasi (NOTIF)

| Kode | Kebutuhan | Prioritas |
|---|---|:-:|
| KF-NOTIF-01 | Admin/koordinator membuat pengumuman dengan target (semua, angkatan, stase, kelompok) | P1 |
| KF-NOTIF-02 | Notifikasi di dalam aplikasi (ikon lonceng) | P1 |
| KF-NOTIF-03 | Push notification PWA (Android & iPhone yang telah meng-install aplikasi) | P2 |
| KF-NOTIF-04 | Notifikasi otomatis: entri menunggu verifikasi, jadwal jaga besok, nilai terbit | P2 |
| KF-NOTIF-05 | Pengingat harian kepada pembimbing yang memiliki antrean verifikasi | P2 |

### 5.10 Modul Laporan (LAP)

| Kode | Kebutuhan | Prioritas |
|---|---|:-:|
| KF-LAP-01 | Rekap nilai per stase dan per angkatan (Excel/PDF) | P1 |
| KF-LAP-02 | Portofolio mahasiswa (logbook, capaian, nilai) dalam PDF | P2 |
| KF-LAP-03 | Laporan kehadiran per periode | P2 |
| KF-LAP-04 | Laporan beban bimbingan per pembimbing | P2 |
| KF-LAP-05 | Laporan pendukung akreditasi | P3 |

### 5.11 Modul Administrasi Sistem (ADM)

| Kode | Kebutuhan | Prioritas |
|---|---|:-:|
| KF-ADM-01 | Manajemen pengguna, peran, dan izin | P1 |
| KF-ADM-02 | Audit log seluruh aktivitas penting (login, ubah nilai, verifikasi, akses data) | P1 |
| KF-ADM-03 | Pengaturan sistem (bobot nilai default, radius geolokasi, dsb.) | P1 |
| KF-ADM-04 | Pencadangan (*backup*) terjadwal | P1 |

---

## 6. Alur Proses Bisnis

### 6.1 Alur Besar Kepaniteraan

```mermaid
flowchart TD
    A[Admin FK membuat periode & angkatan] --> B[Impor data mahasiswa]
    B --> C[Bentuk kelompok]
    C --> D[Susun rotasi stase]
    D --> E{Validasi bentrok<br/>& kapasitas}
    E -- Tidak valid --> D
    E -- Valid --> F[Publikasi rotasi]
    F --> G[Koordinator stase menetapkan pembimbing]
    G --> H[Koordinator menyusun jadwal jaga]
    H --> I[Mahasiswa menjalani stase:<br/>presensi, logbook, penilaian]
    I --> J[Ujian akhir stase]
    J --> K[Finalisasi nilai stase]
    K --> L{Masih ada stase?}
    L -- Ya --> I
    L -- Tidak --> M[Rekap akhir & portofolio]
```

### 6.2 Alur Logbook dan Verifikasi

```mermaid
sequenceDiagram
    actor M as Mahasiswa
    participant S as Sistem eKoas
    actor P as Pembimbing

    M->>S: Isi entri logbook (kasus/tindakan)
    S->>S: Simpan status "Menunggu Verifikasi"
    S-->>P: Notifikasi entri baru
    P->>S: Buka antrean verifikasi
    alt Disetujui
        P->>S: Setujui (satu per satu / massal)
        S->>S: Status "Terverifikasi", hitung ulang capaian SKDI
        S-->>M: Notifikasi disetujui
    else Ditolak
        P->>S: Tolak + alasan
        S->>S: Status "Ditolak"
        S-->>M: Notifikasi ditolak beserta alasan
        M->>S: Perbaiki dan ajukan ulang
    end
```

Status entri logbook:

```mermaid
stateDiagram-v2
    [*] --> Draf
    Draf --> MenungguVerifikasi: Ajukan
    MenungguVerifikasi --> Terverifikasi: Disetujui pembimbing
    MenungguVerifikasi --> Ditolak: Ditolak pembimbing
    Ditolak --> MenungguVerifikasi: Diperbaiki & diajukan ulang
    Draf --> [*]: Dihapus
    Terverifikasi --> [*]
```

### 6.3 Alur Presensi

```mermaid
flowchart TD
    A[Mahasiswa membuka menu Presensi] --> B[Pindai QR code lokasi]
    B --> C{QR valid &<br/>belum kedaluwarsa?}
    C -- Tidak --> X[Tolak presensi]
    C -- Ya --> D[Ambil lokasi GPS]
    D --> E{Dalam radius RS?}
    E -- Tidak --> X
    E -- Ya --> F{Sesuai jadwal jaga?}
    F -- Tidak --> G[Catat sebagai presensi di luar jadwal<br/>perlu konfirmasi koordinator]
    F -- Ya --> H{Tepat waktu?}
    H -- Ya --> I[Catat Hadir]
    H -- Tidak --> J[Catat Terlambat]
```

### 6.4 Alur Penilaian Berbasis Kerja (Mini-CEX / DOPS)

```mermaid
sequenceDiagram
    actor M as Mahasiswa
    participant S as Sistem eKoas
    actor P as Pembimbing

    opt Diminta mahasiswa
        M->>S: Ajukan permintaan penilaian
        S-->>P: Notifikasi permintaan
    end
    P->>P: Mengobservasi mahasiswa menangani pasien / tindakan
    P->>S: Isi formulir penilaian + umpan balik
    S->>S: Simpan nilai (status: Draf)
    P->>S: Kirim
    S-->>M: Notifikasi nilai & umpan balik
    Note over S: Nilai masuk ke komponen nilai akhir stase
```

### 6.5 Alur Finalisasi Nilai Stase

```mermaid
flowchart LR
    A[Nilai WPBA] --> D[Kalkulasi nilai akhir<br/>berdasarkan bobot]
    B[Nilai profesionalisme] --> D
    C[Nilai ujian akhir stase] --> D
    E[Kelengkapan logbook<br/>& kehadiran] --> F{Syarat terpenuhi?}
    D --> F
    F -- Ya --> G[Koordinator finalisasi & kunci nilai]
    F -- Tidak --> H[Status: Belum Lulus / Remedial]
    G --> I[Nilai terbit ke mahasiswa & Admin FK]
```

Contoh bobot nilai akhir stase (dapat dikonfigurasi per stase):

| Komponen | Bobot |
|---|:-:|
| Rata-rata Mini-CEX | 20% |
| Rata-rata DOPS | 15% |
| Case-based Discussion | 10% |
| Profesionalisme | 15% |
| Ujian akhir stase | 40% |

Syarat kelulusan stase (contoh): kehadiran ≥ 90%, capaian logbook ≥ 100% target wajib, dan nilai akhir ≥ batas lulus yang ditetapkan fakultas.

---

## 7. Rancangan Database

### 7.1 Diagram Relasi Entitas (ERD)

```mermaid
erDiagram
    USERS ||--o| STUDENTS : "memiliki profil"
    USERS ||--o| SUPERVISORS : "memiliki profil"
    USERS }o--o{ ROLES : "memiliki"

    HOSPITALS ||--o{ DEPARTMENTS : "memiliki"
    DEPARTMENTS ||--o{ ATTENDANCE_LOCATIONS : "memiliki"
    DEPARTMENTS ||--o{ SUPERVISORS : "menaungi"

    PERIODS ||--o{ STUDENT_GROUPS : "memiliki"
    STUDENT_GROUPS ||--o{ GROUP_MEMBERS : "beranggotakan"
    STUDENTS ||--o{ GROUP_MEMBERS : "tergabung"

    STUDENT_GROUPS ||--o{ ROTATIONS : "menjalani"
    DEPARTMENTS ||--o{ ROTATIONS : "ditempati"
    ROTATIONS ||--o{ STUDENT_ROTATIONS : "dirinci per mahasiswa"
    STUDENTS ||--o{ STUDENT_ROTATIONS : "menjalani"
    SUPERVISORS ||--o{ STUDENT_ROTATIONS : "membimbing"

    STUDENT_ROTATIONS ||--o{ DUTY_SCHEDULES : "memiliki"
    STUDENT_ROTATIONS ||--o{ ATTENDANCES : "memiliki"
    STUDENT_ROTATIONS ||--o{ LEAVE_REQUESTS : "memiliki"
    STUDENT_ROTATIONS ||--o{ LOGBOOK_ENTRIES : "memiliki"
    STUDENT_ROTATIONS ||--o{ ASSESSMENTS : "memiliki"
    STUDENT_ROTATIONS ||--o| FINAL_GRADES : "menghasilkan"
    STUDENT_ROTATIONS ||--o{ REFLECTIONS : "memiliki"

    COMPETENCIES ||--o{ DEPARTMENT_TARGETS : "ditargetkan"
    DEPARTMENTS ||--o{ DEPARTMENT_TARGETS : "menetapkan"
    LOGBOOK_ENTRIES }o--o{ COMPETENCIES : "memenuhi"
    SUPERVISORS ||--o{ LOGBOOK_ENTRIES : "memverifikasi"

    ASSESSMENT_FORMS ||--o{ ASSESSMENT_FORM_ITEMS : "berisi"
    ASSESSMENT_FORMS ||--o{ ASSESSMENTS : "digunakan"
    ASSESSMENTS ||--o{ ASSESSMENT_SCORES : "berisi"
    SUPERVISORS ||--o{ ASSESSMENTS : "menilai"

    USERS ||--o{ NOTIFICATIONS : "menerima"
    USERS ||--o{ AUDIT_LOGS : "melakukan"
```

### 7.2 Spesifikasi Tabel

Semua tabel memiliki kolom `id` (BIGINT, PK, auto increment), `created_at`, dan `updated_at` kecuali disebutkan lain. Tabel data penting menggunakan *soft delete* (`deleted_at`).

#### Pengguna dan Peran

**users**
| Kolom | Tipe | Keterangan |
|---|---|---|
| name | VARCHAR(150) | Nama lengkap |
| email | VARCHAR(150) UNIQUE | |
| username | VARCHAR(50) UNIQUE | NIM/NIP |
| password | VARCHAR(255) | Hash bcrypt/argon2 |
| phone | VARCHAR(20) NULL | |
| photo_path | VARCHAR(255) NULL | |
| is_active | BOOLEAN | Default `true` |
| last_login_at | TIMESTAMP NULL | |

**roles**, **permissions**, **model_has_roles**, **role_has_permissions** – mengikuti struktur paket `spatie/laravel-permission`. Peran: `mahasiswa`, `pembimbing`, `koordinator_stase`, `admin_fk`, `admin_rs`, `super_admin`.

**students**
| Kolom | Tipe | Keterangan |
|---|---|---|
| user_id | FK → users | UNIQUE |
| nim | VARCHAR(20) UNIQUE | |
| cohort_year | YEAR | Angkatan |
| gender | ENUM('L','P') | |
| status | ENUM('aktif','cuti','lulus','nonaktif') | |

**supervisors**
| Kolom | Tipe | Keterangan |
|---|---|---|
| user_id | FK → users | UNIQUE |
| nip | VARCHAR(30) NULL | |
| department_id | FK → departments | Bagian utama |
| title | VARCHAR(100) | Gelar, misal "dr., Sp.PD" |
| is_coordinator | BOOLEAN | Koordinator stase |

#### Rumah Sakit dan Stase

**hospitals**
| Kolom | Tipe | Keterangan |
|---|---|---|
| name | VARCHAR(150) | |
| type | ENUM('utama','jejaring') | |
| address | TEXT | |
| latitude, longitude | DECIMAL(10,7) | Titik pusat RS |
| geofence_radius_m | INT | Radius presensi (meter) |

**departments** (stase/bagian)
| Kolom | Tipe | Keterangan |
|---|---|---|
| hospital_id | FK → hospitals | |
| code | VARCHAR(20) UNIQUE | Misal `IPD`, `BDH` |
| name | VARCHAR(100) | Misal "Ilmu Penyakit Dalam" |
| duration_weeks | TINYINT | Lama stase |
| capacity | SMALLINT | Maksimal mahasiswa bersamaan |
| grade_weights | JSON | Bobot komponen nilai |

**attendance_locations**
| Kolom | Tipe | Keterangan |
|---|---|---|
| department_id | FK → departments | |
| name | VARCHAR(100) | Misal "Bangsal Interna Lt. 2", "IGD" |
| qr_secret | VARCHAR(64) | Kunci pembangkit QR dinamis |

#### Periode, Kelompok, dan Rotasi

**periods**
| Kolom | Tipe | Keterangan |
|---|---|---|
| name | VARCHAR(100) | Misal "Kepaniteraan Angkatan 2026" |
| start_date, end_date | DATE | |
| is_active | BOOLEAN | |

**student_groups**
| Kolom | Tipe | Keterangan |
|---|---|---|
| period_id | FK → periods | |
| name | VARCHAR(50) | Misal "Kelompok A" |

**group_members**
| Kolom | Tipe | Keterangan |
|---|---|---|
| student_group_id | FK → student_groups | |
| student_id | FK → students | UNIQUE (student_group_id, student_id) |

**rotations**
| Kolom | Tipe | Keterangan |
|---|---|---|
| student_group_id | FK → student_groups | |
| department_id | FK → departments | |
| start_date, end_date | DATE | |
| status | ENUM('draf','terbit','berjalan','selesai') | |

**student_rotations** (tabel inti; hampir semua aktivitas mengacu ke sini)
| Kolom | Tipe | Keterangan |
|---|---|---|
| rotation_id | FK → rotations | |
| student_id | FK → students | |
| supervisor_id | FK → supervisors NULL | Pembimbing utama |
| status | ENUM('berjalan','lulus','remedial','tidak_lulus','cuti') | |
| notes | TEXT NULL | |

#### Jadwal dan Presensi

**duty_schedules**
| Kolom | Tipe | Keterangan |
|---|---|---|
| student_rotation_id | FK | |
| attendance_location_id | FK | |
| date | DATE | |
| shift | ENUM('pagi','sore','malam') | |
| start_time, end_time | TIME | |

**attendances**
| Kolom | Tipe | Keterangan |
|---|---|---|
| student_rotation_id | FK | |
| duty_schedule_id | FK NULL | Null jika di luar jadwal |
| attendance_location_id | FK | |
| check_in_at, check_out_at | DATETIME NULL | |
| check_in_lat, check_in_lng | DECIMAL(10,7) | |
| status | ENUM('hadir','terlambat','izin','sakit','alpa','luar_jadwal') | |
| verified_by | FK → users NULL | Untuk koreksi koordinator |

**leave_requests**
| Kolom | Tipe | Keterangan |
|---|---|---|
| student_rotation_id | FK | |
| type | ENUM('izin','sakit') | |
| start_date, end_date | DATE | |
| reason | TEXT | |
| attachment_path | VARCHAR(255) NULL | |
| status | ENUM('diajukan','disetujui','ditolak') | |
| reviewed_by | FK → users NULL | |

#### Kompetensi dan Logbook

**competencies** (daftar SKDI)
| Kolom | Tipe | Keterangan |
|---|---|---|
| code | VARCHAR(20) UNIQUE | Kode internal |
| type | ENUM('penyakit','keterampilan') | |
| name | VARCHAR(255) | |
| organ_system | VARCHAR(100) | Sistem organ / kelompok |
| skdi_level | ENUM('1','2','3A','3B','4A') | |

**department_targets**
| Kolom | Tipe | Keterangan |
|---|---|---|
| department_id | FK | |
| competency_id | FK | |
| min_count | TINYINT | Jumlah minimal |
| min_involvement | ENUM('observasi','membantu','supervisi','mandiri') | Tingkat keterlibatan minimal |
| is_mandatory | BOOLEAN | |

**logbook_entries**
| Kolom | Tipe | Keterangan |
|---|---|---|
| student_rotation_id | FK | |
| entry_type | ENUM('kasus','tindakan') | |
| activity_date | DATE | |
| setting | ENUM('poli','bangsal','igd','ok','vk','icu','lainnya') | |
| patient_initials | VARCHAR(5) | Tanpa nama lengkap |
| patient_age | SMALLINT | |
| patient_age_unit | ENUM('hari','bulan','tahun') | |
| patient_gender | ENUM('L','P') | |
| diagnosis_text | VARCHAR(255) | |
| involvement | ENUM('observasi','membantu','supervisi','mandiri') | |
| description | TEXT NULL | |
| supervisor_id | FK → supervisors | Pemverifikasi |
| status | ENUM('draf','menunggu','terverifikasi','ditolak') | |
| rejection_reason | TEXT NULL | |
| verified_at | DATETIME NULL | |
| client_uuid | CHAR(36) UNIQUE | Untuk sinkronisasi offline (mencegah duplikasi) |

**logbook_entry_competency** (pivot)
| Kolom | Tipe | Keterangan |
|---|---|---|
| logbook_entry_id | FK | |
| competency_id | FK | |

#### Penilaian

**assessment_forms**
| Kolom | Tipe | Keterangan |
|---|---|---|
| code | ENUM('minicex','dops','cbd','profesionalisme','ujian') | |
| name | VARCHAR(100) | |
| scale_min, scale_max | TINYINT | Misal 1–9 |
| is_active | BOOLEAN | |

**assessment_form_items**
| Kolom | Tipe | Keterangan |
|---|---|---|
| assessment_form_id | FK | |
| order | TINYINT | |
| label | VARCHAR(255) | Misal "Anamnesis", "Pemeriksaan fisik" |
| weight | DECIMAL(5,2) | |

**assessments**
| Kolom | Tipe | Keterangan |
|---|---|---|
| student_rotation_id | FK | |
| assessment_form_id | FK | |
| supervisor_id | FK → supervisors | |
| assessed_at | DATE | |
| case_summary | VARCHAR(255) NULL | |
| total_score | DECIMAL(5,2) | Dihitung sistem |
| strengths | TEXT NULL | Umpan balik: hal yang baik |
| improvements | TEXT NULL | Umpan balik: yang perlu ditingkatkan |
| status | ENUM('diminta','draf','terkirim') | |

**assessment_scores**
| Kolom | Tipe | Keterangan |
|---|---|---|
| assessment_id | FK | |
| assessment_form_item_id | FK | |
| score | DECIMAL(4,2) NULL | Null = tidak dinilai |

**final_grades**
| Kolom | Tipe | Keterangan |
|---|---|---|
| student_rotation_id | FK UNIQUE | |
| component_scores | JSON | Rincian per komponen |
| final_score | DECIMAL(5,2) | |
| letter_grade | VARCHAR(2) | |
| attendance_pct | DECIMAL(5,2) | |
| logbook_completion_pct | DECIMAL(5,2) | |
| is_passed | BOOLEAN | |
| finalized_by | FK → users | |
| finalized_at | DATETIME | |

#### Refleksi, Evaluasi, dan Notifikasi

**reflections**
| Kolom | Tipe | Keterangan |
|---|---|---|
| student_rotation_id | FK | |
| title | VARCHAR(150) | |
| content | TEXT | |
| supervisor_comment | TEXT NULL | |
| commented_at | DATETIME NULL | |

**rotation_evaluations** (evaluasi stase oleh mahasiswa, anonim di laporan)
| Kolom | Tipe | Keterangan |
|---|---|---|
| student_rotation_id | FK UNIQUE | Disimpan untuk mencegah pengisian ganda, tidak ditampilkan di laporan |
| answers | JSON | Skor per pertanyaan |
| comment | TEXT NULL | |

**announcements**
| Kolom | Tipe | Keterangan |
|---|---|---|
| title | VARCHAR(150) | |
| body | TEXT | |
| target_type | ENUM('semua','periode','stase','kelompok') | |
| target_id | BIGINT NULL | |
| published_at | DATETIME | |
| created_by | FK → users | |

**notifications** – menggunakan tabel bawaan Laravel Notifications.

**push_subscriptions**
| Kolom | Tipe | Keterangan |
|---|---|---|
| user_id | FK | |
| endpoint | TEXT | |
| public_key, auth_token | VARCHAR(255) | |

**audit_logs**
| Kolom | Tipe | Keterangan |
|---|---|---|
| user_id | FK NULL | |
| action | VARCHAR(50) | Misal `login`, `verify_logbook`, `update_grade` |
| subject_type, subject_id | VARCHAR / BIGINT | Objek yang diubah |
| old_values, new_values | JSON NULL | |
| ip_address | VARCHAR(45) | |
| user_agent | VARCHAR(255) | |

### 7.3 Indeks Penting

- `logbook_entries (supervisor_id, status)` – antrean verifikasi pembimbing.
- `logbook_entries (student_rotation_id, status)` – perhitungan capaian.
- `attendances (student_rotation_id, check_in_at)` – rekap kehadiran.
- `duty_schedules (date, attendance_location_id)` – jadwal harian per lokasi.
- `rotations (department_id, start_date, end_date)` – validasi kapasitas.

---

## 8. Rancangan API

### 8.1 Konvensi

- Base URL: `https://ekoas.<domain>/api/v1`
- Format: JSON, autentikasi `Authorization: Bearer <token>` (Laravel Sanctum).
- Paginasi: `?page=1&per_page=20`; filter: `?filter[status]=menunggu`.
- Format respons standar:

```json
{
  "success": true,
  "message": "Data berhasil diambil",
  "data": { },
  "meta": { "page": 1, "per_page": 20, "total": 134 }
}
```

- Kode status: `200` OK, `201` dibuat, `401` belum login, `403` tidak berhak, `404` tidak ditemukan, `409` konflik (misal bentrok jadwal), `422` validasi gagal.

### 8.2 Daftar Endpoint Utama

**Autentikasi**
| Metode | Endpoint | Keterangan |
|---|---|---|
| POST | `/auth/login` | Login, mengembalikan token & data peran |
| POST | `/auth/logout` | Mencabut token |
| GET | `/auth/me` | Profil pengguna aktif |
| POST | `/auth/forgot-password` | Kirim tautan reset |
| PUT | `/auth/password` | Ubah kata sandi |

**Data Master** (admin)
| Metode | Endpoint | Keterangan |
|---|---|---|
| GET/POST | `/students` | Daftar / tambah mahasiswa |
| POST | `/students/import` | Impor Excel |
| GET/POST | `/supervisors` | Daftar / tambah pembimbing |
| GET/POST | `/departments` | Daftar / tambah stase |
| GET | `/competencies?search=` | Pencarian kompetensi SKDI (*autocomplete*) |
| GET/PUT | `/departments/{id}/targets` | Target kompetensi stase |

**Rotasi**
| Metode | Endpoint | Keterangan |
|---|---|---|
| GET/POST | `/periods` | Periode kepaniteraan |
| GET/POST | `/periods/{id}/groups` | Kelompok mahasiswa |
| GET/POST | `/rotations` | Rotasi; POST memvalidasi bentrok & kapasitas |
| POST | `/rotations/{id}/publish` | Terbitkan rotasi |
| PUT | `/student-rotations/{id}/supervisor` | Tetapkan pembimbing |
| GET | `/me/rotations` | Rotasi milik mahasiswa login |

**Jadwal & Presensi**
| Metode | Endpoint | Keterangan |
|---|---|---|
| GET/POST | `/duty-schedules` | Jadwal jaga |
| GET | `/me/duty-schedules?month=2026-10` | Jadwal jaga pribadi |
| GET | `/attendance-locations/{id}/qr` | QR dinamis (untuk layar di lokasi) |
| POST | `/attendances/check-in` | Body: `qr_token`, `lat`, `lng` |
| POST | `/attendances/check-out` | |
| GET/POST | `/leave-requests` | Pengajuan izin/sakit |
| PUT | `/leave-requests/{id}/review` | Setujui/tolak |

**Logbook**
| Metode | Endpoint | Keterangan |
|---|---|---|
| GET | `/me/logbook` | Logbook mahasiswa |
| POST | `/logbook` | Tambah entri |
| POST | `/logbook/sync` | Sinkronisasi massal entri offline (berdasarkan `client_uuid`) |
| PUT | `/logbook/{id}` | Ubah entri (hanya status draf/ditolak) |
| POST | `/logbook/{id}/submit` | Ajukan verifikasi |
| GET | `/verifications/pending` | Antrean verifikasi pembimbing |
| POST | `/verifications/approve` | Body: `entry_ids[]` (mendukung massal) |
| POST | `/verifications/{id}/reject` | Body: `reason` |

**Capaian Kompetensi**
| Metode | Endpoint | Keterangan |
|---|---|---|
| GET | `/me/competency-progress` | Progres mahasiswa |
| GET | `/student-rotations/{id}/competency-progress` | Progres per stase |
| GET | `/departments/{id}/competency-summary` | Ringkasan seluruh mahasiswa di stase |

**Penilaian**
| Metode | Endpoint | Keterangan |
|---|---|---|
| GET | `/assessment-forms` | Daftar formulir & butir |
| POST | `/assessments/request` | Mahasiswa meminta penilaian |
| POST | `/assessments` | Pembimbing mengisi penilaian |
| GET | `/me/assessments` | Nilai & umpan balik mahasiswa |
| GET | `/student-rotations/{id}/final-grade/preview` | Pratinjau kalkulasi nilai akhir |
| POST | `/student-rotations/{id}/final-grade` | Finalisasi & kunci nilai |

**Umpan Balik, Pengumuman, Notifikasi, Laporan**
| Metode | Endpoint | Keterangan |
|---|---|---|
| GET/POST | `/reflections` | Refleksi |
| PUT | `/reflections/{id}/comment` | Komentar pembimbing |
| POST | `/rotation-evaluations` | Evaluasi stase |
| GET/POST | `/announcements` | Pengumuman |
| GET | `/notifications` | Notifikasi pengguna |
| POST | `/push-subscriptions` | Daftarkan perangkat untuk push notification |
| GET | `/reports/grades?period_id=&format=xlsx` | Rekap nilai |
| GET | `/reports/attendance?...` | Rekap kehadiran |
| GET | `/students/{id}/portfolio.pdf` | Portofolio mahasiswa |

### 8.3 Contoh Payload: Membuat Entri Logbook

```json
POST /api/v1/logbook
{
  "client_uuid": "7d3b2c1e-4f5a-4b6c-9d8e-1a2b3c4d5e6f",
  "student_rotation_id": 412,
  "entry_type": "kasus",
  "activity_date": "2026-10-05",
  "setting": "bangsal",
  "patient_initials": "AS",
  "patient_age": 54,
  "patient_age_unit": "tahun",
  "patient_gender": "L",
  "diagnosis_text": "Diabetes melitus tipe 2 dengan ulkus kaki",
  "competency_ids": [118, 245],
  "involvement": "supervisi",
  "supervisor_id": 37,
  "description": "Melakukan anamnesis dan pemeriksaan fisik, menyusun rencana tata laksana.",
  "submit": true
}
```

---

## 9. Rancangan Antarmuka

### 9.1 Prinsip Desain

- **Mobile-first**: sebagian besar interaksi mahasiswa dan pembimbing terjadi di HP.
- **Verifikasi secepat mungkin**: pembimbing harus bisa menyetujui entri dalam 1–2 ketukan.
- **Navigasi bawah** (*bottom navigation*) di mobile, *sidebar* di desktop untuk admin.
- Mendukung mode terang dan gelap, kontras teks sesuai standar aksesibilitas.

### 9.2 Daftar Halaman per Peran

**Mahasiswa** (navigasi bawah: Beranda · Logbook · Presensi · Nilai · Profil)
| Halaman | Isi |
|---|---|
| Beranda | Stase aktif, jadwal jaga hari ini, ringkasan capaian, pengumuman terbaru |
| Logbook | Daftar entri dengan filter status; tombol tambah (+) |
| Form Logbook | Formulir singkat dengan *autocomplete* SKDI dan pilihan pembimbing |
| Presensi | Tombol pindai QR, riwayat kehadiran, pengajuan izin |
| Jadwal | Kalender rotasi dan jadwal jaga |
| Capaian | Progres kompetensi per stase (bar progres per kompetensi) |
| Nilai | Daftar penilaian WPBA, umpan balik, nilai akhir stase |
| Refleksi | Tulis dan baca refleksi beserta komentar pembimbing |

**Pembimbing** (navigasi bawah: Beranda · Verifikasi · Nilai · Mahasiswa · Profil)
| Halaman | Isi |
|---|---|
| Beranda | Jumlah antrean verifikasi, permintaan penilaian, mahasiswa bimbingan aktif |
| Verifikasi | Daftar entri menunggu; ceklis untuk setuju massal; geser/tombol tolak |
| Penilaian | Pilih mahasiswa → pilih formulir (Mini-CEX/DOPS/CbD) → isi skor & umpan balik |
| Mahasiswa | Daftar mahasiswa bimbingan beserta capaian dan nilainya |

**Koordinator Stase** (tambahan menu di atas peran pembimbing)
| Halaman | Isi |
|---|---|
| Dashboard Stase | Jumlah mahasiswa aktif, kehadiran hari ini, mahasiswa berisiko |
| Jadwal Jaga | Editor jadwal (tampilan kalender/grid) |
| Penetapan Pembimbing | Menetapkan pembimbing per mahasiswa |
| Izin | Persetujuan izin/sakit |
| Finalisasi Nilai | Pratinjau nilai akhir, kunci nilai |

**Admin FK** (desktop, sidebar)
| Halaman | Isi |
|---|---|
| Dashboard | Statistik angkatan, capaian rata-rata per stase, peringatan |
| Data Master | Mahasiswa, pembimbing, RS, stase, SKDI, target, formulir penilaian |
| Rotasi | Periode, kelompok, penyusun rotasi (tampilan Gantt/tabel) |
| Pengumuman | Buat dan kelola pengumuman |
| Laporan | Rekap nilai, kehadiran, portofolio, evaluasi stase |
| Pengguna | Akun dan peran |

**Admin RS**
| Halaman | Isi |
|---|---|
| Dashboard | Mahasiswa aktif per bagian hari ini, kapasitas |
| Laporan | Kehadiran dan distribusi mahasiswa |
| Lokasi Presensi | Kelola titik presensi dan tampilan QR dinamis |

### 9.3 Sketsa Tata Letak (Mahasiswa – Beranda)

```
┌─────────────────────────────┐
│  eKoas              🔔  (A) │
├─────────────────────────────┤
│  Stase aktif                │
│  Ilmu Penyakit Dalam        │
│  Minggu 4 dari 10           │
│  Pembimbing: dr. X, Sp.PD   │
├─────────────────────────────┤
│  Jaga hari ini              │
│  Sore · Bangsal Lt. 2       │
│  14.00 – 21.00  [Presensi]  │
├─────────────────────────────┤
│  Capaian kompetensi         │
│  ███████████░░░░  68%       │
│  3 entri menunggu verifikasi│
├─────────────────────────────┤
│  Pengumuman                 │
│  • Ujian stase 12 Okt       │
├─────────────────────────────┤
│  🏠   📒   📍   📊   👤     │
└─────────────────────────────┘
```

### 9.4 Sketsa Tata Letak (Pembimbing – Verifikasi)

```
┌─────────────────────────────┐
│  ← Verifikasi (8)           │
├─────────────────────────────┤
│  [✓] Pilih semua            │
├─────────────────────────────┤
│  [✓] Budi S. · 5 Okt        │
│      Kasus · DM tipe 2      │
│      Supervisi · Bangsal    │
├─────────────────────────────┤
│  [✓] Sari W. · 5 Okt        │
│      Tindakan · Pasang infus│
│      Mandiri · IGD          │
├─────────────────────────────┤
│  [ ] Andi P. · 4 Okt   ...  │
├─────────────────────────────┤
│  [ Tolak ]   [ Setujui (2) ]│
└─────────────────────────────┘
```

---

## 10. Kebutuhan Non-Fungsional

| Kode | Aspek | Kebutuhan |
|---|---|---|
| KNF-01 | Kinerja | Waktu muat halaman awal ≤ 3 detik pada jaringan 4G; respons API ≤ 500 ms untuk 95% permintaan |
| KNF-02 | Kapasitas | Mendukung ≥ 1.000 pengguna aktif dan ≥ 300 pengguna bersamaan |
| KNF-03 | Ketersediaan | *Uptime* ≥ 99% di luar jadwal pemeliharaan |
| KNF-04 | Kompatibilitas | Chrome/Edge/Firefox/Safari dua versi terakhir; Android 10+; iOS 16.4+ (untuk push notification) |
| KNF-05 | PWA | Dapat di-install di Android dan iPhone; skor Lighthouse PWA lulus seluruh kriteria *installable* |
| KNF-06 | Offline | Halaman utama dan formulir logbook dapat dibuka tanpa koneksi; entri tersinkron otomatis |
| KNF-07 | Kegunaan | Pengisian satu entri logbook ≤ 60 detik; verifikasi satu entri ≤ 5 detik |
| KNF-08 | Aksesibilitas | Mengacu WCAG 2.1 level AA untuk kontras dan navigasi |
| KNF-09 | Pemeliharaan | Kode mengikuti standar PSR-12 (PHP) dan ESLint/Prettier (frontend); cakupan pengujian otomatis logika inti ≥ 70% |
| KNF-10 | Pencadangan | Backup database harian (simpan 30 hari) dan mingguan (simpan 3 bulan), disimpan di lokasi terpisah |
| KNF-11 | Bahasa | Antarmuka berbahasa Indonesia |

---

## 11. Keamanan dan Pelindungan Data

Sistem memproses data pribadi mahasiswa dan informasi klinis pasien, sehingga harus mematuhi **UU No. 27 Tahun 2022 tentang Pelindungan Data Pribadi (UU PDP)** serta ketentuan kerahasiaan medis.

### 11.1 Minimalisasi Data Pasien

- Logbook **hanya** menyimpan inisial, usia, dan jenis kelamin pasien.
- **Tidak** menyimpan nama lengkap, nomor rekam medis, NIK, alamat, atau foto pasien.
- Validasi di sisi server menolak input inisial lebih dari 5 karakter.
- Tampilkan pengingat etika di formulir logbook.

### 11.2 Kontrol Teknis

| Aspek | Penerapan |
|---|---|
| Transport | HTTPS wajib (TLS 1.2+), HSTS aktif |
| Kata sandi | Hash argon2id/bcrypt, kebijakan panjang minimal 8 karakter, pembatasan percobaan login (*rate limiting*) |
| Token | Token Sanctum dengan masa berlaku; dicabut saat logout atau ganti kata sandi |
| Otorisasi | Pemeriksaan kebijakan (*Policy*) di setiap endpoint; mahasiswa hanya dapat mengakses data miliknya, pembimbing hanya mahasiswa bimbingannya |
| Input | Validasi server-side untuk semua masukan; perlindungan SQL injection (ORM) dan XSS (escaping) |
| Berkas | Unggahan (misal surat sakit) disimpan di luar *web root*, diakses melalui URL bertanda tangan dengan masa berlaku |
| Presensi | QR dinamis bertanda tangan (HMAC) dengan masa berlaku singkat; validasi geolokasi di server |
| Audit | Semua aksi penting dicatat di `audit_logs` dan tidak dapat diubah dari aplikasi |
| Enkripsi | Enkripsi kolom sensitif tertentu; backup dienkripsi |
| Header keamanan | Content-Security-Policy, X-Frame-Options, X-Content-Type-Options |

### 11.3 Tata Kelola

- Perjanjian kerja sama FK–RS yang mengatur kepemilikan, akses, dan retensi data.
- Penunjukan penanggung jawab pelindungan data.
- Kebijakan retensi: data logbook dan nilai disimpan sesuai ketentuan akademik; akun mahasiswa yang lulus dinonaktifkan setelah periode tertentu.
- Prosedur penanganan insiden kebocoran data (pemberitahuan sesuai UU PDP).
- Persetujuan penggunaan data (termasuk lokasi GPS untuk presensi) saat pertama kali login.

---

## 12. Teknologi dan Lingkungan

### 12.1 Ringkasan Tumpukan Teknologi

| Lapisan | Teknologi |
|---|---|
| Frontend | Vite, Vue 3 (atau React), Tailwind CSS, vite-plugin-pwa, Dexie.js |
| Backend | PHP 8.x, Laravel, Sanctum, Spatie Permission |
| Database | MySQL 8 / MariaDB 10.11+ |
| Cache & Queue | Redis |
| Web server | Nginx + PHP-FPM |
| Sertifikat | Let's Encrypt (Certbot) |
| Kontrol versi | Git (GitHub/GitLab) |
| CI/CD | GitHub Actions / GitLab CI (uji otomatis & deploy) |
| Pemantauan | Log Laravel, Uptime monitor, Sentry (opsional) |

### 12.2 Lingkungan

| Lingkungan | Tujuan |
|---|---|
| Development | Komputer pengembang (Windows dengan Laragon/WSL2, atau Linux) |
| Staging | Server uji dengan HTTPS untuk pengujian PWA di Android & iPhone serta UAT |
| Production | Server utama (VPS/on-premise RS atau universitas) |

### 12.3 Spesifikasi Server Minimal (Production)

| Komponen | Spesifikasi |
|---|---|
| CPU | 4 vCPU |
| RAM | 8 GB |
| Penyimpanan | 100 GB SSD |
| OS | Ubuntu Server LTS |
| Jaringan | IP publik, domain, dan akses HTTPS |

### 12.4 Struktur Repositori (Usulan)

```
ekoas/
├── backend/                 # Laravel API
│   ├── app/
│   │   ├── Http/Controllers/Api/V1/
│   │   ├── Models/
│   │   ├── Policies/
│   │   ├── Services/        # Logika: kalkulasi nilai, capaian, validasi rotasi
│   │   └── Notifications/
│   ├── database/migrations/
│   ├── database/seeders/    # Data SKDI, peran, stase contoh
│   └── tests/
└── frontend/                # Vite PWA
    ├── public/
    │   ├── icons/           # 192, 512, apple-touch-icon 180
    │   └── ...
    ├── src/
    │   ├── api/             # Klien Axios per modul
    │   ├── components/
    │   ├── layouts/         # MobileLayout, AdminLayout
    │   ├── pages/
    │   │   ├── mahasiswa/
    │   │   ├── pembimbing/
    │   │   ├── koordinator/
    │   │   └── admin/
    │   ├── stores/
    │   ├── offline/         # IndexedDB & antrean sinkronisasi
    │   └── router/
    └── vite.config.js
```

---

## 13. Tahapan Pengembangan

### 13.1 Fase dan Cakupan

| Fase | Cakupan | Perkiraan Durasi |
|---|---|:-:|
| **0. Persiapan** | Validasi kebutuhan dengan FK & RS, pengumpulan data SKDI, formulir penilaian, dan daftar stase; desain UI/UX | 3–4 minggu |
| **1. MVP (P1)** | Autentikasi, data master, rotasi stase, logbook + verifikasi, capaian SKDI, penilaian dasar (Mini-CEX, DOPS, profesionalisme, ujian), finalisasi nilai, pengumuman, rekap nilai, PWA dasar | 10–12 minggu |
| **2. Penguatan (P2)** | Jadwal jaga & presensi QR + geolokasi, izin, CbD, refleksi, evaluasi stase, push notification, logbook offline, peringatan dini, portofolio PDF, 2FA admin | 8–10 minggu |
| **3. Integrasi (P3)** | SSO universitas, integrasi SIAKAD/SIMRS, generator rotasi otomatis, laporan akreditasi, aplikasi Play Store/App Store via Capacitor | Menyesuaikan |

Perkiraan durasi mengasumsikan tim kecil (1 analis/PM, 1–2 pengembang backend, 1–2 pengembang frontend, 1 penguji) dan dapat berubah sesuai kondisi.

### 13.2 Rencana Uji Coba

1. **Uji internal** di lingkungan staging oleh tim pengembang.
2. **UAT (User Acceptance Test)** bersama perwakilan admin FK, satu koordinator stase, beberapa pembimbing, dan mahasiswa.
3. **Pilot** pada satu stase (misalnya Ilmu Penyakit Dalam) selama satu siklus rotasi, berjalan paralel dengan logbook lama.
4. Evaluasi pilot, perbaikan, lalu **perluasan bertahap** ke seluruh stase.

### 13.3 Kriteria Keberhasilan

- ≥ 90% mahasiswa pilot mengisi logbook melalui aplikasi.
- Rata-rata waktu verifikasi pembimbing < 48 jam sejak entri diajukan.
- Rekap nilai akhir stase tersedia ≤ 3 hari kerja setelah stase berakhir.
- Kepuasan pengguna (survei) ≥ 4 dari 5.

---

## 14. Risiko dan Mitigasi

| Risiko | Dampak | Mitigasi |
|---|---|---|
| Pembimbing enggan/tidak sempat memverifikasi | Logbook menumpuk, data capaian tidak akurat | Verifikasi massal 1 ketukan, pengingat harian, laporan beban bimbingan ke koordinator, sosialisasi dan dukungan pimpinan |
| Sinyal lemah di area RS | Gagal presensi atau input | Mode offline dan sinkronisasi; titik Wi-Fi di lokasi presensi |
| Kecurangan presensi (titip absen, lokasi palsu) | Data kehadiran tidak valid | QR dinamis + geolokasi + deteksi pola janggal; verifikasi acak oleh koordinator |
| Kebocoran data pasien | Pelanggaran hukum & etika | Minimalisasi data, kontrol akses ketat, audit log, pelatihan etika |
| Perubahan kurikulum/formulir penilaian | Sistem perlu disesuaikan | Formulir, bobot nilai, dan target kompetensi dibuat dapat dikonfigurasi |
| Keterbatasan PWA di iPhone | Push notification tidak diterima pengguna yang belum meng-install | Panduan instalasi di aplikasi, notifikasi tetap tersedia di dalam aplikasi, opsi email |
| Ketergantungan pada satu pengembang | Pemeliharaan terhambat | Dokumentasi kode & API, repositori terpusat, serah terima pengetahuan |
| Resistensi terhadap perubahan dari cara manual | Adopsi rendah | Pilot bertahap, pelatihan singkat, *champion* di tiap bagian |

---

*Dokumen ini merupakan rancangan awal dan perlu divalidasi bersama pihak Fakultas Kedokteran dan Rumah Sakit Pendidikan, terutama terkait daftar stase, formulir penilaian, bobot nilai, dan target kompetensi yang berlaku di institusi.*
