# Progres Pengembangan eKoas

Terakhir diperbarui: 2026-09-25

**Posisi saat ini:** seluruh kebutuhan prioritas P1 (MVP) sudah diimplementasikan dan diuji lewat HTTP/otomatis. Langkah berikutnya bukan menambah fitur, melainkan **uji manual di browser & UAT** bersama pengguna nyata (lihat "Berikutnya").

## Ringkasan

| Sprint | Status |
|---|---|
| 0. Fondasi | ✅ Selesai |
| 1. Data master | ✅ Selesai (sisa: lupa kata sandi lewat email — butuh SMTP) |
| 2. Kompetensi & rotasi | ✅ Selesai (kecuali KF-ROT-07 yang memang P2) |
| 3. Logbook | ✅ Selesai (KF-LOG-09/10 offline & QR memang P2/P3) |
| 4. Capaian & penilaian | ✅ Selesai (KF-NILAI-03 CbD & KF-NILAI-07 permintaan penilaian memang P2) |
| 5. Pengumuman & laporan | ✅ Selesai (push notification PWA, laporan PDF sungguhan & Excel .xlsx menyusul) |
| 6. Hardening & pilot | 🟡 Kode selesai; menunggu uji manual/UAT & keputusan penerapan (lihat "Berikutnya") |

## Log

### 2026-09-25 — Tema warna "Almamater FK" (sesuai foto gedung fakultas)
- [x] Warna diambil dengan **menganalisis foto** `docs/Gedung Fakutlas Kedokteran.jpg` (kelompok rona dominan): hijau tua (tiang & kaca), emas `#e8b020` (panel & ornamen), biru kobalt, merah, hijau limau. Rincian pemetaan ke token: [PANDUAN_DESAIN.md](PANDUAN_DESAIN.md)
- [x] Hijau menjadi warna aksi; **emas** menjadi aksen (penanda menu aktif, lencana jumlah, logo, tombol di kartu sambutan, progres rendah/peringatan); biru & merah untuk status informasi & bahaya
- [x] **Pita empat warna** (emas · limau · biru · emas) meniru pita fasad — di tepi atas sidebar, dasar kartu sambutan, dan panel halaman masuk. **Ornamen belah ketupat emas** (SVG buatan sendiri, terinspirasi ukiran fasad) pada kartu sambutan; versi pudar untuk HP agar tidak menimpa teks. **Foto gedung** sebagai latar samar panel halaman masuk
- [x] Semua warna tema kini berupa token (117 pemakaian `var(--…)`); tidak ada sisa warna teal lama. Mode gelap ditata ulang (hijau lebih terang; teks tombol menjadi hijau gelap agar kontras — sebelumnya putih di atas teal terang kurang terbaca). `meta theme-color`, manifest, dan ikon PWA ikut diperbarui; cache service worker dinaikkan ke `v2`
- [x] Diverifikasi dengan potret layar (Edge): login desktop & HP, beranda mahasiswa/admin (terang), beranda & halaman Mahasiswa (gelap), kartu sambutan di HP. Semua 23 halaman utama 200 tanpa galat; 48 uji otomatis lolos; data contoh tidak berubah
- [x] Dua penyesuaian dari hasil potret: ornamen tambahan di halaman masuk dihapus (bertumpuk dengan ornamen asli pada foto, terlihat ramai); ornamen di HP dipindah ke pojok kanan bawah & dipudarkan karena sempat menimpa teks sapaan
- [ ] Belum diminta: nama/logo resmi institusi. Teks di UI tetap generik ("Fakultas Kedokteran & Rumah Sakit Pendidikan"); logo resmi bisa menggantikan tanda plus di logo bila tersedia
- [ ] Warna hasil analisis adalah pendekatan dari satu foto (pencahayaan memengaruhi rona). Bila fakultas punya kode warna resmi, cukup ganti nilai token

### 2026-09-25 — Penyegaran tampilan (desain)
- [x] **Sistem desain baru** ([public/assets/app.css](../public/assets/app.css), [app.js](../public/assets/app.js), [app/layout.php](../app/layout.php)); panduan di [PANDUAN_DESAIN.md](PANDUAN_DESAIN.md). Menggantikan gaya minimal yang tertanam di layout
- [x] **Kerangka**: sidebar bergradasi dengan menu terkelompok per peran + ikon + lencana jumlah (antrean verifikasi, notifikasi), topbar dengan breadcrumb/tema/notifikasi/keluar, kartu pengguna berinisial. Di HP: laci geser + menu bawah 5 tombol
- [x] **Mode terang/gelap** (mengikuti sistem, dapat diganti manual & diingat), animasi masuk halus, efek hover/tekan, indikator memuat pada tombol kirim (sekaligus mencegah kirim ganda), menghormati `prefers-reduced-motion`
- [x] **Halaman masuk** dua kolom dengan panel sambutan, tombol lihat/sembunyikan kata sandi; di HP menjadi satu kolom
- [x] **Beranda** dengan sapaan sesuai jam & tanggal berbahasa Indonesia, kartu statistik berikon (admin), kartu stase dengan bar waktu & capaian (mahasiswa), penghitung antrean (pembimbing), keadaan kosong yang ramah
- [x] **Komponen dipakai di seluruh halaman**: lencana status berwarna, bar progres, tab filter, kartu pengumuman, notifikasi belum-dibaca bertitik, toolbar laporan, tanggal berbahasa Indonesia ("25 Sep 2026"), form filter sebaris; gaya sebaris lama dibersihkan
- [x] **Diverifikasi dengan potret layar nyata** (Edge headless): login, beranda (mahasiswa/admin/pembimbing), logbook (daftar & form), verifikasi, rotasi, laporan, nilai — desktop, mode gelap, dan HP (iframe 390 px; **tidak ada halaman yang meluap horizontal**, tabel tergulir di dalam kartunya). Semua 23 halaman utama tetap 200 tanpa galat PHP; 48 uji otomatis tetap lolos; data contoh tidak berubah
- [x] Dua bug ditemukan lewat potret dan diperbaiki: (1) ikon di dalam konten tanpa ukuran dasar membengkak memenuhi kartu; (2) skrip penutup-otomatis pemberitahuan ikut menghapus kotak hasil nilai ("Nilai akhir: … Lulus") — kini hanya berlaku untuk notifikasi kilat (`.alert.flash`). Urutan komponen nilai di halaman mahasiswa juga dibakukan (kolom JSON MySQL mengacak kunci)
- [ ] Belum diuji di perangkat sungguhan (Android/iPhone) maupun Safari/Firefox — hanya Edge (Chromium). Uji juga pengetikan pada form panjang di HP dan sentuhan pada menu bawah
- [ ] Halaman formulir panjang (logbook baru, penilaian) dan halaman admin belum dipotret satu per satu; struktur & komponennya sama dengan yang sudah diverifikasi

### 2026-09-25 — Sprint 6 (hardening)
- [x] **Header keamanan** ([app/security.php](../app/security.php)): Content-Security-Policy (sumber luar diblokir, `frame-ancestors 'none'`, `form-action 'self'`), X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy; HSTS dan cookie sesi `Secure` otomatis saat HTTPS. CSP masih memakai `'unsafe-inline'` karena halaman memakai gaya/skrip sebaris
- [x] **Paksa ganti sandi**: kolom `users.must_change_password` (ditambahkan installer). Akun baru (manual/impor) dan hasil reset oleh super_admin wajib mengganti sandi sebelum memakai fitur lain; hanya profil dan logout yang terbuka. Sandi baru harus berbeda dari lama. Akun contoh **tidak** dipaksa (agar uji coba lancar)
- [x] **Pembatasan login** menggantikan penghitung per-sesi (mudah dilewati): tabel `login_attempts`, blokir 15 menit setelah 5 gagal (akun+IP), 15 gagal (satu akun dari banyak IP), atau 20 gagal (satu IP ke banyak akun); sandi benar pun ditolak selama diblokir; berhasil login menghapus catatan
- [x] **Periode & kelompok dapat diubah/dihapus** (`admin/periods.php`). Dilindungi: periode yang masih punya kelompok, dan kelompok yang sudah punya rotasi, tidak bisa dihapus (penghapusan akan menghapus berantai data rotasi mahasiswa)
- [x] **Paginasi** ([app/paginate.php](../app/paginate.php)) 25/halaman untuk daftar mahasiswa (plus pencarian NIM/nama) dan notifikasi
- [x] **PWA dasar** (KNF-05): `manifest.webmanifest`, `sw.js`, `offline.html`, ikon 192/512/maskable/apple-touch dibuat oleh [database/make_icons.php](../database/make_icons.php). Service worker sengaja **tidak menyimpan halaman/respons aplikasi** (berisi data pengguna); hanya kerangka statis dan halaman offline. Mode offline logbook penuh tetap Fase 2
- [x] **Uji otomatis** [tests/run.php](../tests/run.php) (`php tests/run.php`, 48 pemeriksaan lolos): skor penilaian, huruf mutu, validasi rotasi (bentrok & kapasitas), capaian kompetensi (aturan keterlibatan/status/hapus), bobot & nilai akhir, penerima pengumuman, pembatasan login, paginasi. Berjalan dalam transaksi yang di-rollback sehingga data contoh tidak tersentuh (diverifikasi: jumlah data sama sebelum dan sesudah)
- [x] **User MySQL berhak minimal** [database/create_app_user.php](../database/create_app_user.php): `ekoas_app` hanya SELECT/INSERT/UPDATE/DELETE pada `db_koas`. Diuji: aplikasi (login + 4 halaman) berjalan dengan user ini; `DROP TABLE`, `CREATE TABLE`, akses `mysql.user`, dan `GRANT` ditolak. **Belum diterapkan** ke `.env` Anda — user uji sudah dihapus lagi; `.env` tetap memakai root. Skrip tidak mengubah `.env`; ia hanya mencetak baris yang perlu Anda salin
- [x] Perbaikan kecil: urutan komponen bobot nilai kini konsisten (kolom JSON MySQL menyusun ulang kunci); `validate_rotation` dipindah ke `services.php` agar dapat diuji
- [x] Diuji end-to-end (HTTP): header muncul; manifest valid dan semua berkas PWA 200 dengan tipe benar; alur akun baru → paksa ganti sandi → normal; 6× salah → diblokir; alur periode (buat/ubah/tanggal tidak valid/hapus terlindungi); Kelompok A & periode contoh tidak bisa terhapus; pencarian & paginasi. Data uji dihapus; data contoh utuh (18 akun, 8 mahasiswa, 23 logbook)
- [ ] Belum diuji: tombol "Reset sandi" super_admin via HTTP (SQL-nya hanya menambah `must_change_password=1`), instalasi PWA sesungguhnya di Android/iPhone (butuh HTTPS), tampilan di browser
- [ ] **Setelah `git pull`/salin versi ini jalankan `php database/install.php` sekali** — kode kini membaca kolom `must_change_password`, sehingga aplikasi error bila skema belum diperbarui

### 2026-09-25 — Sprint 5 (pengumuman, notifikasi, laporan, pengaturan, backup)
- [x] Skema [database/schema_sprint5.sql](../database/schema_sprint5.sql): `announcements`, `notifications`, `settings`
- [x] Pengaturan sistem `admin/settings.php` (KF-ADM-03): batas lulus, syarat logbook wajib, ambang peringatan. Menggantikan konstanta `PASS_SCORE`/`PASS_LOGBOOK`; dibaca lewat `pass_score()`, `pass_logbook()`, `warn_threshold()` di [app/notify.php](../app/notify.php)
- [x] Notifikasi dalam aplikasi (KF-NOTIF-02): `notifications.php` + jumlah belum dibaca di menu. Dikirim otomatis saat: logbook diajukan (ke pembimbing), disetujui/ditolak (ke mahasiswa), penilaian baru, nilai stase terbit, pengumuman baru. Membuka notifikasi menandainya dibaca; notifikasi milik pengguna lain tidak bisa dibuka
- [x] Pengumuman bertarget (KF-NOTIF-01) `announcements.php`: semua / periode / stase / kelompok. Admin ke mana saja; koordinator hanya ke stasenya sendiri; mahasiswa dan pembimbing hanya membaca (403 bila mencoba membuat). Penerima dihitung dari keanggotaan kelompok/rotasi/pembimbing stase
- [x] Rekap nilai `reports/grades.php` (KF-LAP-01): filter periode & stase, unduh CSV (UTF-8 + BOM, terbaca Excel), cetak/simpan PDF lewat browser. Koordinator otomatis dibatasi stasenya
- [x] Backup [database/backup.php](../database/backup.php) (KF-ADM-04): dump SQL terkompres ke `storage/backups/`, retensi `--keep=N` hari (bawaan 30). **Uji pemulihan berhasil** (dimuat ke database sementara, jumlah baris tabel sama). Penjadwalan harian: Windows Task Scheduler menjalankan `php database/backup.php`
- [x] Dashboard per peran: mahasiswa (rotasi aktif, capaian wajib, hitungan logbook), pembimbing (antrean verifikasi, bimbingan), koordinator (mahasiswa berjalan, belum difinalisasi), admin (ringkasan), pengumuman terbaru
- [x] **Data contoh permanen** [database/seed_demo.php](../database/seed_demo.php): 18 akun, 2 RS, 3 stase, 14 kompetensi + target, 1 periode, 2 kelompok, 4 rotasi, 23 entri logbook (berbagai status), 17 penilaian, 4 nilai final (1 remedial), 3 pengumuman. Idempoten dan **tidak dihapus**. Daftar akun & kata sandi: [AKUN_CONTOH.md](AKUN_CONTOH.md) (masuk `.gitignore` agar kata sandi tidak ikut repositori)
- [x] **Bug Sprint 3 diperbaiki**: tombol "Ajukan" cepat di daftar logbook menerima draf tanpa kompetensi SKDI (melewati validasi formulir). Kini ditolak dengan pesan
- [x] Diuji end-to-end memakai akun contoh (lalu data direset ke kondisi awal): semua halaman 200 tanpa warning untuk 7 peran; notifikasi terkirim ke penerima yang benar dan tidak ke kelompok lain; pengumuman kelompok hanya terlihat anggota kelompok itu; koordinator ditolak menyasar stase lain; 403 untuk mahasiswa→laporan dan pembimbing→pengaturan; nilai pengaturan invalid ditolak; CSV koordinator hanya berisi stasenya; ambang peringatan mengikuti pengaturan
- [ ] Belum diuji di browser (tampilan, dropdown target pengumuman dinamis, tombol cetak)
- [ ] Belum ada: penjadwalan backup otomatis di sisi OS, backup ke lokasi terpisah/terenkripsi (KNF-10), paginasi notifikasi/pengumuman, PDF & Excel `.xlsx` sungguhan (butuh pustaka), push notification (Fase 2)

### 2026-09-25 — Sprint 4 (capaian & penilaian)
- [x] Skema [database/schema_sprint4.sql](../database/schema_sprint4.sql): `assessment_forms`, `assessment_form_items`, `assessments`, `assessment_scores`, `final_grades`. Installer menyemai 4 formulir bawaan (Mini-CEX, DOPS, Profesionalisme skala 1–9; Ujian akhir stase skala 0–100) beserta butirnya; aman dijalankan ulang.
- [x] Logika bisnis di [app/services.php](../app/services.php): `competency_progress`, `assessment_total`, `letter_grade`, `grade_preview`, `department_weights`, `coordinator_dept`
- [x] Capaian kompetensi (KF-KOMP-01..03): mahasiswa `student/progress.php` (bar progres per kompetensi, target wajib vs seluruh target); koordinator/admin `coordinator/progress.php` (rekap semua mahasiswa per stase, merah bila capaian wajib < 50% pada rotasi berjalan)
- [x] Penilaian pembimbing `supervisor/assess.php` (KF-NILAI-01/02/04): Mini-CEX, DOPS, profesionalisme; skor dan tanggal divalidasi server; hanya untuk mahasiswa bimbingannya; ditolak bila nilai stase sudah dikunci
- [x] Nilai & umpan balik mahasiswa `student/grades.php` (KF-NILAI-08): nilai akhir + rincian komponen, skor dan umpan balik tiap penilaian
- [x] Finalisasi `coordinator/finalize.php` (KF-NILAI-05/06/09): input nilai ujian, pratinjau, finalisasi & kunci; dihitung ulang di server dan ditolak bila ada komponen berbobot tanpa data; status rotasi menjadi `lulus`/`remedial`
- [x] Bobot nilai per stase dapat diatur di halaman Stase (harus total 100%); bawaan Mini-CEX 25 / DOPS 20 / Profesionalisme 15 / Ujian 40
- [x] **Perbaikan zona waktu**: PHP default UTC sedangkan MySQL/pengguna memakai WIB, sehingga tanggal "hari ini" bisa mundur sehari pada dini hari (tanggal penilaian valid ditolak). Kini `Asia/Jakarta` (bisa diubah lewat `APP_TZ` di `.env`) dan sesi MySQL disamakan
- [x] Diuji end-to-end (data uji sudah dihapus): validasi skor/tanggal; pembimbing lain ditolak; finalisasi ditolak saat komponen belum lengkap; mahasiswa dan koordinator mendapat 403 di halaman di luar hak akses; bobot ≠ 100% ditolak; perhitungan nilai (25/20/15/40 → 57.89, 30/20/20/30 → 66.33) sesuai hitungan manual; setelah final, penilaian baru/ubah ujian/finalisasi ulang ditolak; mahasiswa melihat nilai dan umpan balik. Jalur "lulus" (nilai 90.33, A, logbook 100%) diuji lewat pemanggilan fungsi langsung
- [ ] Belum diuji di browser (tampilan bar progres dan formulir)
- [ ] Belum ada: kehadiran pada syarat lulus (`attendance_pct` NULL sampai modul presensi Fase 2), pembukaan kembali nilai yang sudah dikunci, CbD, permintaan penilaian oleh mahasiswa

### 2026-09-24 — Sprint 3 (logbook)
- [x] Skema [database/schema_sprint3.sql](../database/schema_sprint3.sql): `logbook_entries` (indeks antrean verifikasi & capaian, `client_uuid` unik untuk sinkronisasi offline nanti), `logbook_entry_competency`
- [x] Autocomplete kompetensi SKDI: `public/api/competencies.php` (butuh login, min. 2 huruf, maks. 15 hasil) (KF-LOG-08)
- [x] Logbook mahasiswa — `public/student/logbook.php`: entri kasus/tindakan, filter status, ubah, hapus draf, ajukan; pemilihan kompetensi berupa chip; pembimbing difilter sesuai bagian rotasi (KF-LOG-01..04)
- [x] Antrean verifikasi pembimbing — `public/supervisor/verify.php`: setujui satu/massal (pilih semua), tolak wajib beserta alasan (KF-LOG-05/06)
- [x] Entri terverifikasi terkunci; hanya draf/ditolak yang bisa diubah; entri ditolak dapat diperbaiki dan diajukan ulang (KF-LOG-07)
- [x] Validasi server: inisial pasien 1–5 huruf saja, tanggal dalam rentang rotasi dan tidak di masa depan, minimal satu kompetensi, pembimbing harus dari bagian stase yang sama, rotasi harus milik mahasiswa dan sudah terbit; pengingat etika data pasien di formulir (README bagian 11.1)
- [x] Otorisasi: pembimbing hanya dapat memproses entri yang ditujukan kepadanya (diuji: pembimbing lain mendapat 0 entri diverifikasi)
- [x] Diuji end-to-end (server PHP + curl, data uji sudah dihapus): semua validasi menolak input buruk; draf → ajukan; setujui massal; tolak dengan alasan; entri terverifikasi tidak bisa dibuka untuk ubah; alasan penolakan tampil ke mahasiswa
- [ ] Belum diuji di browser: JavaScript autocomplete/chip, filter pembimbing, pilih-semua (hanya markup dan endpoint yang diuji)
- [ ] Belum ada notifikasi ke pembimbing/mahasiswa (masuk Sprint 5)

### 2026-09-24 — Sprint 2 (kompetensi & rotasi)
- [x] Skema baru [database/schema_sprint2.sql](../database/schema_sprint2.sql): `competencies`, `department_targets`, `periods`, `student_groups`, `group_members`, `rotations`, `student_rotations`. Installer kini memuat semua `schema*.sql` (aman dijalankan ulang).
- [x] Kompetensi SKDI: tambah, cari, impor CSV — `public/admin/competencies.php` (KF-MSTR-04)
- [x] Target kompetensi per stase (upsert, jumlah minimal, keterlibatan minimal, wajib) — `public/admin/targets.php` (KF-MSTR-05)
- [x] Periode & kelompok, tambah/keluarkan anggota (satu mahasiswa hanya satu kelompok per periode) — `public/admin/periods.php` (KF-ROT-01/02)
- [x] Rotasi: kelompok → stase → tanggal, **validasi bentrok jadwal kelompok dan kapasitas stase**, status draf → terbit — `public/admin/rotations.php` (KF-ROT-03/04). Rincian per mahasiswa (`student_rotations`) dibuat otomatis; anggota yang ditambahkan belakangan ikut masuk rotasi.
- [x] Penetapan pembimbing per mahasiswa; koordinator dibatasi pada bagiannya — `public/coordinator/assign.php` (KF-ROT-05)
- [x] Halaman "Rotasi Saya" (berjalan / akan datang / selesai; rotasi draf disembunyikan) — `public/student/rotations.php` (KF-ROT-06)
- [x] Diuji end-to-end (server PHP + curl, data uji sudah dihapus): kelompok 3 orang pada stase kapasitas 2 ditolak; rotasi valid dibuat; rotasi tumpang tindih ditolak; terbit; pembimbing ditetapkan; mahasiswa melihat rotasinya; mahasiswa mendapat 403 di halaman admin
- [ ] Belum diuji: impor CSV kompetensi, halaman target dengan data, akses koordinator non-admin, tampilan di browser

### 2026-09-24 — Sprint 1 (data master)
- [x] Layout & navigasi per peran; CRUD Rumah Sakit, Stase; Mahasiswa (manual, impor CSV, status); Pembimbing; Pengguna & peran; Profil & ubah sandi; dashboard admin

### 2026-09-24 — Sprint 0
- [x] Rancangan ([RANCANGAN_TAHAP_AWAL.md](RANCANGAN_TAHAP_AWAL.md)), struktur proyek, koneksi MySQL, skema awal, installer, login/logout, audit log

## Berikutnya

**Yang perlu Anda lakukan / putuskan (tidak bisa saya selesaikan sendiri)**
1. **Uji manual di browser** memakai [AKUN_CONTOH.md](AKUN_CONTOH.md) dan catat temuan (tampilan, alur yang janggal, istilah). Ini sumber masukan terpenting sebelum menambah fitur.
2. **Validasi aturan akademik dengan fakultas**: batas lulus (70), syarat logbook wajib (100%), skala huruf mutu, bobot komponen, daftar stase/kompetensi/target, butir formulir Mini-CEX/DOPS. Semuanya sudah dapat diatur (pengaturan & halaman stase/kompetensi), tetapi nilai bawaan adalah asumsi.
3. **Keputusan penerapan**: ganti `.env` ke user `ekoas_app` (`php database/create_app_user.php`), jadwalkan backup harian, siapkan server HTTPS (syarat PWA & cookie `Secure`).
4. **Email/SMTP** bila fitur "lupa kata sandi" (KF-AUTH-04) diperlukan.

**Penjadwalan backup harian (Windows Task Scheduler)** — jalankan sekali di PowerShell sebagai pengguna yang berhak (belum dijalankan oleh saya):
```
schtasks /Create /SC DAILY /ST 02:00 /TN "eKoas Backup" /TR "d:\laragon\bin\php\php-8.2.12-Win32-vs16-x64\php.exe d:\laragon\www\lab\Koas_MU\Koas_MU\database\backup.php"
```
Salin juga isi `storage/backups/` ke lokasi lain (KNF-10 mensyaratkan lokasi terpisah).

**Fase 2 (P2) — bila MVP diterima**
- [ ] Jadwal jaga, presensi QR dinamis + geolokasi, izin/sakit (KF-JDW); kehadiran masuk syarat lulus
- [ ] Mode offline logbook + sinkronisasi (`client_uuid` sudah disiapkan), push notification
- [ ] CbD, permintaan penilaian oleh mahasiswa, refleksi & evaluasi stase, peringatan dini, portofolio PDF, 2FA admin
- [ ] Laporan PDF/Excel `.xlsx` sungguhan (memerlukan pustaka; saat ini CSV + cetak)
- [ ] UI membuka kembali nilai yang sudah dikunci; cuti/pengulangan stase (KF-ROT-07)

## Catatan / Keputusan
- **Kata sandi tidak dapat dilihat di database.** Kolom `users.password` hanya berisi hash satu arah (bcrypt `$2y$…`; akun `admin` Argon2). Kata sandi asli hanya ada di: `DEMO_PASSWORD` pada `database/seed_demo.php` (17 akun contoh: `Demo@2026`), layar sekali-tampil saat installer/pembuatan akun/reset, dan [AKUN_CONTOH.md](AKUN_CONTOH.md). Terverifikasi 2026-09-25: 17 dari 18 akun cocok dengan `Demo@2026`; `admin` masih `65d4f2ed4cd2`. Cara reset dijelaskan di bagian "Di mana kata sandi di database?" pada AKUN_CONTOH.md.
- Data contoh **tidak dihapus** setelah pengujian. Bila uji manual Anda mengubahnya dan ingin kembali ke kondisi awal: kosongkan tabel data contoh lalu jalankan `php database/seed_demo.php` (seeder hanya mengisi bila akun `fk` belum ada).
- Semua uji otomatis lewat curl mengubah data; setelahnya data contoh direset agar tetap seperti dijelaskan di [AKUN_CONTOH.md](AKUN_CONTOH.md).
- Skor penilaian dinormalkan ke 0–100: rata-rata berbobot butir yang dinilai ÷ skala maksimum × 100 (skala 1–9: 9 = 100). Butir dikosongkan = tidak dinilai.
- Nilai akhir = rata-rata berbobot komponen (Mini-CEX, DOPS, Profesionalisme, Ujian). Lulus bila nilai ≥ 70 **dan** capaian logbook wajib = 100%. Huruf mutu: A ≥ 85, B ≥ 70, C ≥ 60, D ≥ 50, E di bawahnya. Ambang ini masih konstanta; perlu divalidasi dengan pihak fakultas.
- Nilai ujian disimpan sebagai `assessments` berformulir `ujian` (satu per rotasi, menimpa yang lama selama belum dikunci).
- Belum ada UI untuk membuka kembali nilai yang sudah dikunci; saat ini hanya lewat database.
- Kapasitas stase dihitung konservatif: total mahasiswa pada rotasi yang tanggalnya beririsan + ukuran kelompok baru tidak boleh melebihi kapasitas.
- Rotasi hanya bisa dihapus saat masih draf. Status `berjalan`/`selesai` belum diotomatiskan; halaman mahasiswa menurunkannya dari tanggal.
- Password awal akun baru dibuat acak dan ditampilkan sekali; tidak ada pengiriman email.
- Halaman `admin/*` untuk `admin_fk` dan `super_admin`; pengguna hanya `super_admin`; penetapan pembimbing juga untuk `koordinator_stase` (dibatasi bagiannya).
- Tahap awal memakai PHP native, bukan Laravel; struktur dijaga agar mudah dimigrasikan.
- Ganti kata sandi `admin` setelah login pertama; ganti akun `root` MySQL dengan user khusus sebelum staging/produksi.
