# Improvement Plan Dokumen ini mencatat pelan pembetulan dan penambahbaikan sistem PRN2026 selepas semakan kod menyeluruh selepas Phase 11 selesai. Setiap fasa mengikut susunan keutamaan: kritikal → prestasi → pengalaman pengguna → pengurusan data. Setiap pembetulan dan perubahan wajib kemaskini: - `docs/progress-log.md` - `docs/changelog.md` - `docs/decision-log.md` jika ada keputusan seni bina, pakej, pangkalan data atau keselamatan yang berubah --- ## Fasa 12: Pembetulan Kritikal dan Keselamatan Status: Belum dimulakan. Skop fasa ini ialah menangani kelemahan yang boleh menyebabkan data tidak konsisten, kawalan akses bocor, atau keperluan edit database secara manual dalam persekitaran produksi. ### 12-A: Admin Settings UI — Toggle Kehadiran dan Override Pendaftaran Masalah semasa: - `election_settings.is_attendance_active` hanya boleh diubah melalui edit database secara terus. - `election_settings.is_registration_open_override` juga tiada UI khusus; bergantung pada pengaturan tarikh semata-mata. - Ini tidak selamat dan tidak praktikal dalam persekitaran produksi semasa hari mengundi. Tugas: - Tambah halaman Admin Settings di bawah `/admin/settings` atau `/admin/setup/settings`. - Paparkan toggle untuk `is_attendance_active` dengan label jelas dan amaran impak. - Paparkan toggle atau dropdown untuk `is_registration_open_override` (null / buka paksa / tutup paksa). - Paparkan tarikh buka dan tarikh tutup pendaftaran semasa sebagai konteks. - Tambah `AdminSettingsController` dan `UpdateElectionSettingsRequest`. - Tambah `ElectionSettingsService` untuk enkapsulasi logik kemaskini. - Rekod perubahan dalam activity log: siapa, nilai lama, nilai baru, masa. - Tambah ujian ciri untuk kemaskini setiap toggle, halaman diakses Admin sahaja. - Tambah pautan ke Admin Settings dari Admin dashboard. Kriteria keluar: - Admin boleh toggle kehadiran dan override pendaftaran dari UI tanpa sentuh database. - Perubahan direkod dalam activity log. - Admin Kewangan, PPM, KTM tidak boleh akses halaman settings. Dokumentasi yang perlu dikemaskini: - `docs/01-development-plan.md` — tambah Fasa 12 dengan semua tugas dan kriteria keluar. - `docs/04-rbac-permission-matrix.md` — tambah permission `manage election settings` untuk Admin. - `docs/05-workflow-design.md` — tambah bahagian pengurusan tetapan pilihan raya. - `docs/progress-log.md` — rekod selepas siap. - `docs/changelog.md` — rekod selepas siap. - `docs/decision-log.md` — rekod keputusan reka bentuk halaman settings. --- ### 12-B: Pembetulan Semakan IC Duplikasi untuk Rekod Soft-Deleted Masalah semasa: - Semakan IC duplikasi dalam `StorePublicApplicationRequest` menapis rekod aktif sahaja, tetapi soft-deleted KTM-created records masih wujud dalam pangkalan data. - Jika KTM delete rekod pemohon (`deleted_by_ktm`), rekod tersebut soft-deleted tetapi IC dalam `applications` masih boleh menyebabkan konflik bergantung kepada cara query dikodkan. - Risiko: pemohon awam mungkin diblock padahal KTM sudah delete rekod mereka. Tugas: - Semak semula query semakan IC duplikasi dalam `StorePublicApplicationRequest` dan mana-mana service yang menjalankan semakan serupa. - Pastikan rekod `deleted_at IS NOT NULL` (soft-deleted) tidak diambil kira sebagai "aktif" dalam semakan duplikasi. - Pastikan `withTrashed()` atau scoped query digunakan secara eksplisit dan konsisten. - Tambah kes ujian: KTM delete rekod → pemohon awam dengan IC sama boleh mohon semula. - Semak `KtmVacancyService` dan `AssignmentVacancyService` juga untuk memastikan tiada pengiraan yang termasuk soft-deleted rows secara tidak sengaja. Kriteria keluar: - Ujian baru lulus: soft-deleted KTM record tidak menghalang permohonan awam baharu. - Semua semakan IC dalam system menggunakan kaedah yang sama dan konsisten. Dokumentasi yang perlu dikemaskini: - `docs/05-workflow-design.md` — perjelas bahawa soft-deleted records dikecualikan dari semakan IC aktif. - `docs/progress-log.md` dan `docs/changelog.md` — rekod selepas siap. --- ### 12-C: Perkukuh Enforcement Nota Catatan Post-Pendaftaran Masalah semasa: - `AdminPostCloseNoteService` menguatkuasakan keperluan `catatan` pada peringkat service layer. - Jika ada controller baru yang lupa panggil service ini, semakan tidak berlaku dan Admin boleh edit rekod tanpa nota selepas pendaftaran ditutup tanpa sebarang amaran. - Enforcement bergantung sepenuhnya pada konvensyen pemanggilan, bukan pada mekanisme framework. Tugas: - Semak semua controller Admin yang boleh mengubah `Application`, `StaffAssignment`, `PoliceEscort`, `KkmRepresentative`, atau `JkmRepresentative` selepas pendaftaran ditutup. - Tambah senarai semak di `AdminPostCloseNoteService` yang boleh dipanggil secara konsisten. - Pertimbangkan untuk tambah `middleware` khusus pada route group Admin management yang secara automatik menjalankan semakan ini, dan reject request tanpa `catatan` apabila pendaftaran ditutup. - Jika middleware digunakan, dokumentasikan dalam `docs/decision-log.md`. - Tambah ujian integrasi untuk setiap route Admin management yang sepatutnya enforce semakan ini. Kriteria keluar: - Semua route management Admin yang mengubah rekod domain enforce catatan secara konsisten apabila pendaftaran ditutup. - Ujian baru mengesahkan enforcement pada setiap route yang berkenaan. - Tiada jalan pintas yang boleh bypass semakan ini tanpa sengaja. Dokumentasi yang perlu dikemaskini: - `docs/05-workflow-design.md` — dokumentasikan mekanisme enforcement yang dipilih. - `docs/decision-log.md` — rekod keputusan sama ada guna middleware atau service pattern. - `docs/progress-log.md` dan `docs/changelog.md` — rekod selepas siap. --- ### 12-D: Pembetulan SampleElectionSeeder dan Konsistensi Nama Jawatan Masalah semasa: - Selepas migrasi Phase 11 menukar `CALON_SIMPANAN` kepada `CALON_TAMBAHAN`, ada kemungkinan `SampleElectionSeeder.php` masih mengandungi rujukan kepada nama atau slug lama. - Jika seeder dijalankan semula (fresh seed untuk UAT atau persekitaran baharu), data yang dijana mungkin tidak konsisten dengan `PositionSeeder`. Tugas: - Buka dan audit `SampleElectionSeeder.php` secara menyeluruh. - Cari semua rujukan kepada `CALON_SIMPANAN` atau string berkaitan dan gantikan dengan `CALON_TAMBAHAN`. - Pastikan semua slug jawatan dalam seeder sepadan tepat dengan apa yang `PositionSeeder` jana. - Jalankan `php artisan migrate:fresh --seed` dan pastikan tiada ralat. - Jalankan `php artisan test` dan pastikan semua 80 ujian lulus. Kriteria keluar: - `php artisan migrate:fresh --seed` selesai tanpa ralat. - `php artisan test` lulus sepenuhnya. - Tiada rujukan kepada `CALON_SIMPANAN` dalam mana-mana seeder. Dokumentasi yang perlu dikemaskini: - `docs/progress-log.md` dan `docs/changelog.md` — rekod selepas siap. --- ### 12-E: Konsistensikan Semakan Jenis Dokumen pada Semua Path Download Masalah semasa: - Admin Kewangan route download secara eksplisit mengehad kepada `bank_statement` sahaja. - Route download PPM, Admin, dan Admin Kewangan masing-masing menggunakan implementasi yang berbeza. - Jika ada ketidakkonsistenan dalam cara jenis dokumen disahkan, pengguna yang dibenarkan mungkin boleh download jenis dokumen yang sepatutnya terhad untuk mereka. Tugas: - Audit semua route download dokumen: PPM, Admin, dan Admin Kewangan. - Cipta satu senarai jenis dokumen yang dibenarkan per peranan (`document_type` allowlist). - Refactor semakan jenis dokumen ke dalam satu tempat — boleh dalam `DocumentDownloadController` atau policy `ApplicationPolicy`. - Tambah ujian untuk setiap peranan mengesahkan mereka: - Boleh download dokumen yang dibenarkan. - Tidak boleh download dokumen di luar skop mereka walaupun ID dokumen diketahui. - Pastikan 403 dikembalikan, bukan 404, untuk download yang diblock (supaya mesej ralat tidak mendedahkan kewujudan dokumen). Kriteria keluar: - Semua path download dokumen menggunakan semakan jenis yang konsisten. - Ujian baru mengesahkan boundary setiap peranan. - Tiada path yang boleh bypass semakan jenis dokumen. Dokumentasi yang perlu dikemaskini: - `docs/04-rbac-permission-matrix.md` — tambah baris untuk akses dokumen per peranan. - `docs/decision-log.md` — rekod keputusan centralize semakan jenis dokumen. - `docs/progress-log.md` dan `docs/changelog.md` — rekod selepas siap. --- ## Fasa 13: Indeks Pangkalan Data dan Prestasi Status: Belum dimulakan. Skop fasa ini ialah menambah composite indexes yang diperlukan sebelum sistem mula menerima data sebenar dalam kuantiti besar. ### 13-A: Tambah Composite Indexes untuk Query Kerap Masalah semasa: - Query senarai Admin global (`/admin/management/applications`) menyaring mengikut `election_id`, `status`, dan `pusat_mengundi_id` tanpa composite index. - Query `AssignmentVacancyService` dan `KtmVacancyService` menyaring `staff_assignments` mengikut `election_id`, `pusat_mengundi_id`, `position_id`, dan `is_active` tanpa composite index. - Untuk pilihan raya dengan 5,000–20,000 permohonan, query ini boleh menjadi lambat secara signifikan. Tugas: - Cipta migration baharu untuk menambah indexes (jangan ubah migration sedia ada). - Tambah pada jadual `applications`: - `(election_id, status)` - `(election_id, pusat_mengundi_id, status)` - `(election_id, ic_number)` — untuk semakan IC duplikasi - Tambah pada jadual `staff_assignments`: - `(election_id, pusat_mengundi_id, position_id, is_active)` - `(election_id, saluran_mengundi_id, position_id, is_active)` - `(reports_to_assignment_id, is_active)` — untuk KtmVacancyService - Tambah pada jadual `bank_verifications`: - `(election_id, status)` - Gunakan nama index yang pendek dan eksplisit (ikut konvensyen sedia ada dalam sistem). - Jalankan `php artisan migrate` dan sahkan indexes wujud. - Jalankan `php artisan test` dan pastikan semua ujian lulus. Kriteria keluar: - Migration berjaya tanpa ralat. - Semua ujian lulus. - Query utama pada senarai admin menggunakan indexes (boleh disahkan dengan `EXPLAIN` dalam MySQL Workbench). Dokumentasi yang perlu dikemaskini: - `docs/03-database-design.md` — tambah bahagian indexes dan justifikasi. - `docs/decision-log.md` — rekod keputusan indexes yang ditambah dan sebab. - `docs/08-deployment-notes.md` — tambah arahan semak indexes semasa deployment. - `docs/progress-log.md` dan `docs/changelog.md` — rekod selepas siap. --- ## Fasa 14: Portal Status Permohonan Pemohon Awam Status: Belum dimulakan. Skop fasa ini ialah memberi pemohon awam cara untuk semak status permohonan mereka tanpa perlu login atau hubungi Admin. ### 14-A: Halaman Status Permohonan via UUID Awam Masalah semasa: - Pemohon awam hanya menerima redirect ke `/permohonan/{uuid}/berjaya` selepas mohon. - Tiada cara untuk semak status kemudian (diluluskan? ditolak? kenapa ditolak?). - Ini menyebabkan beban sokongan kepada Admin dan PPM. Tugas: - Tambah route `GET /permohonan/{application:public_uuid}/status`. - Halaman ini tidak memerlukan login — cukup UUID awam permohonan sebagai pengecam. - Paparkan maklumat terhad: nama pemohon (sebahagian), jawatan dipohon, pusat mengundi, status semasa, tarikh kemaskini terakhir. - Jika status `rejected`, paparkan sebab penolakan jika ada. - Jika status `assigned`, paparkan pengesahan penempatan tanpa mendedahkan butiran dalaman (saluran ID, dsb.). - Jangan paparkan nombor IC penuh, nombor akaun bank, atau data sensitif lain. - Gunakan `SensitiveData` helper untuk mask nama sebahagian jika perlu. - Tambah ujian untuk: permohonan berstatus submitted, approved, assigned, rejected, dan UUID tidak wujud. Kriteria keluar: - Pemohon boleh semak status dengan hanya URL yang mengandungi UUID awam. - Data sensitif tidak didedahkan. - Halaman tidak mendedahkan sama ada UUID wujud atau tidak kepada orang lain (status 200 dengan mesej umum untuk UUID tidak dikenali, bukan 404). Dokumentasi yang perlu dikemaskini: - `docs/05-workflow-design.md` — tambah bahagian portal status pemohon. - `docs/06-ui-ux-plan.md` — tambah reka bentuk halaman status. - `docs/progress-log.md` dan `docs/changelog.md` — rekod selepas siap. - `docs/decision-log.md` — rekod keputusan reka bentuk privacy (status 200 vs 404 untuk UUID tidak dikenali). --- ## Fasa 15: Pengurusan Eksport dan Data Sensitif Status: Belum dimulakan. Skop fasa ini ialah memastikan fail eksport yang mengandungi data sensitif tidak kekal dalam storage tanpa had masa. ### 15-A: Purge Automatik Fail Eksport Lama Masalah semasa: - Fail XLSX eksport kewangan (disimpan di `exports/finance`) dan eksport kehadiran (disimpan di `exports/attendance`) disimpan dalam private storage tanpa had masa. - Fail-fail ini mengandungi data bank, nombor IC, dan maklumat peribadi lain. - Tiada mekanisme untuk padam fail lama secara automatik. Tugas: - Tambah `ExportPurgeCommand` (`php artisan exports:purge`) sebagai Artisan command. - Command menerima parameter `--days=` (default: 30) untuk menentukan tempoh simpanan. - Command akan: - Query `export_logs` untuk rekod lebih lama daripada tempoh yang ditetapkan. - Padam fail dari storage disk yang berkaitan. - Kemaskini `export_logs` dengan `purged_at` dan `purged_by` (system). - Log aktiviti purge. - Daftarkan command dalam `bootstrap/app.php` atau `routes/console.php` sebagai scheduled task (contoh: harian pada tengah malam). - Tambah kolum `purged_at` pada jadual `export_logs` melalui migration baharu. - Tambah ujian untuk: command berjaya padam fail lama, fail baru tidak terpadam, `export_logs` dikemaskini. Kriteria keluar: - Command boleh dijalankan secara manual dan secara scheduled. - Fail lebih lama dari tempoh yang ditetapkan dipadamkan dari storage. - `export_logs` menunjukkan rekod purge. - Fail yang masih dalam tempoh simpanan tidak terpadam. Dokumentasi yang perlu dikemaskini: - `docs/03-database-design.md` — tambah kolum `purged_at` dalam jadual `export_logs`. - `docs/08-deployment-notes.md` — tambah arahan konfigurasi scheduler dan polisi simpanan eksport. - `docs/decision-log.md` — rekod keputusan tempoh simpanan default dan strategi purge. - `docs/progress-log.md` dan `docs/changelog.md` — rekod selepas siap. --- ## Ringkasan Keutamaan | Fasa | Tajuk | Keutamaan | Status | |------|-------|-----------|--------| | 12-A | Admin Settings UI (toggle kehadiran/pendaftaran) | Kritikal | **Selesai 2026-06-02** | | 12-B | Pembetulan semakan IC soft-deleted | Kritikal | **Selesai 2026-06-02** | | 12-C | Perkukuh enforcement nota catatan | Kritikal | **Selesai 2026-06-02** | | 12-D | Pembetulan SampleElectionSeeder | Kritikal | **Selesai 2026-06-02** | | 12-E | Konsistensikan semakan jenis dokumen download | Kritikal | **Selesai 2026-06-02** | | 13-A | Tambah composite indexes pangkalan data | Prestasi | **Selesai 2026-06-02** | | 14-A | Portal status permohonan pemohon awam | UX | **Selesai 2026-06-02** | | 15-A | Purge automatik fail eksport sensitif | Data | **Selesai 2026-06-02** | --- ## Nota Pelaksanaan - Setiap item dalam Fasa 12 boleh dilaksanakan secara bebas dan tidak perlu tunggu item lain selesai. - Fasa 13 patut dilaksanakan sebelum data sebenar mula dimasukkan ke dalam sistem. - Fasa 14 dan 15 boleh dilaksanakan secara selari kerana tidak ada kebergantungan antara satu sama lain. - Setiap pembetulan mesti menjalankan semula suite ujian penuh (`php artisan test`) sebelum dianggap selesai. - Jalankan `vendor\bin\pint.bat --test` dan `vendor\bin\phpstan.bat analyse --memory-limit=1G` selepas setiap fasa.