# Audit Teknikal: Sistem myLesen **Tarikh Audit:** 18 Mac 2026 **Juruaudit:** Claude Code (berdasarkan pembacaan kod semasa) **Skop:** Keseluruhan projek `mylesen` --- ## A. Ringkasan Sistem Semasa ### A1. Maklumat Projek | Butiran | Nilai | |---|---| | Nama Sistem | myLesen — Sistem Pengurusan Lesen Penjaja | | Organisasi | MBIP (Majlis Bandaraya Iskandar Puteri) | | Framework | Laravel 11.9 / PHP 8.2 | | Database Utama | MySQL (`mylesen`) | | Database Kedua | MySQL (`sistemutama`) via `second_mysql` connection — sistem EPBT | | Frontend | Blade + Tailwind CSS + Alpine.js + jQuery | | Penjanaan Dokumen | PHPOffice/PHPWord (output `.docx`, bukan PDF) | | Authentication | Laravel Breeze (session-based) | | API Luar | `http://epbt.mbip.gov.my/...` (jana bil pelbagai) | | API Chrome Extension | **Tiada** — belum dibina | ### A2. Statistik Kod | Komponen | Bilangan | Catatan | |---|---|---| | Controllers (aktif) | 15 | termasuk auth controllers | | Controllers (dalam `asal/`) | 4 | fail backup lama — tidak digunakan | | Models | 38 | 11 EPBT (second_mysql), 4 PbtPay (stub kosong) | | Views (blade) | ~104 | termasuk `asal/`, `-ori.blade.php`, fail ujian | | Migrations | 39 | 1 ada typo nama fail | | Routes (web) | ~71 + auth routes | tiada `routes/api.php` | | Middleware custom | 2 | `AdminMiddleware`, `KakitanganMiddleware` | | Policies | 2 | kebanyakan method masih empty stub | | FormRequest classes | 2 | `ProfileUpdateRequest`, `LoginRequest` sahaja | | Tema Admin dipasang | 4 | AdminLTE, KaiAdmin, Corporate UI, Kapella — hanya 1 digunakan | ### A3. Seni Bina Semasa ``` [Browser] | ↓ HTTP (web.php routes) [Laravel Controllers] | | ↓ ↓ [MySQL: mylesen] [MySQL: sistemutama/EPBT] [HTTP: epbt.mbip.gov.my] (data permohonan) (bil, resit, akaun lesen) (jana bil API) ``` **Autentikasi & Kebenaran:** - `role` column dalam jadual `users` — string (bukan enum) - 2 middleware: `admin` (super sahaja), `kakitangan` (semua staf) - 6 Gate definitions dalam `AppServiceProvider` - 2 Policy classes (mostly stubs) - Tiada konsistensi antara penggunaan Gate vs Policy **Document Streaming:** - Semua dokumen uploaded dilindungi — streaming melalui controller, bukan URL terus ### A4. Aliran Status Semasa (dari pembacaan kod) Status permohonan disimpan dalam `status_progress` (string) dan `status_mesyuarat` (string) dalam jadual `lesen_penjajas`. ``` [PEMOHON HANTAR BORANG] | ↓ hantar_permohonan() ┌─────────────┐ │ BARU │ ← Queue PT (penjaja-baru) └─────────────┘ | ↓ simpanWangProses() — PT masukkan No. Bil EPBT ┌────────────────────────────┐ │ MENUNGGU BAYARAN PROSES │ ← Queue PT (penjaja-proses) └────────────────────────────┘ | ↓ Auto: bila resit ditemui dalam EPBT (EpbtEcasResit) ┌────────────────────────────┐ │ SEMAKAN BAYARAN PROSES │ ← Queue PT (penjaja-bukafail) └────────────────────────────┘ | ↓ hantarPPK() — PT hantar ke IK ┌─────────────────┐ │ LAWATAN TAPAK │ ← Queue IK (penjaja-pemeriksaan) └─────────────────┘ | ↓ simpanUlasan() — IK lengkap borang ulasan ┌─────────────────────┐ │ ULASAN PEGAWAI │ ← Queue PP (penjaja-cadangan) └─────────────────────┘ | ↓ simpan_cadangan() — PP tulis cadangan ┌─────────────────────┐ │ ULASAN PENGARAH │ ← Queue Pengarah (penjaja-ulasan-cadangan) └─────────────────────┘ | ↓ simpan_ulasan_cadangan() — Pengarah setuju bawa ke mesyuarat ┌──────────────────────────────────┐ │ SOKONG DIBAWA KE MESYUARAT │ └──────────────────────────────────┘ | ↓ sahkanSenarai() — PT masukkan dalam agenda mesyuarat ┌────────────────────────────────────────┐ │ MENUNGGU KEPUTUSAN MESYUARAT │ └────────────────────────────────────────┘ | ↓ simpanKeputusanMesyuarat() ┌──────────────────────┐ │ KEPUTUSAN DITERIMA │ └──────────────────────┘ | ├── status_mesyuarat = 'diluluskan' → PT daftar lesen ├── status_mesyuarat = 'ditolak' → Tamat └── status_mesyuarat = 'ditangguhkan' → Tunggu mesyuarat berikutnya ``` **Gap dalam status flow (isu penting):** 1. Tiada status terminal "LESEN DIKELUARKAN" atau "SELESAI" — `status_progress` kekal 'keputusan diperolehi' walaupun lesen sudah dikeluarkan 2. `senarai_pt_daftarlesen` (queue pendaftaran no lesen) menggunakan status `ulasan pegawai/pengarah/sokong` dengan `whereNull('no_akaun_lesen')` — ini adalah aliran berasingan tanpa status dedicated 3. Bayaran lesen (hutang lesen) dikesan melalui `whereNotNull('no_akaun_lesen')->whereNull('lesen_no_resit')` — tiada status formal untuk ini 4. Apabila Pengarah tangguhkan cadangan (bukan ke mesyuarat), status kembali ke 'lawatan tapak' tetapi borang IK baru tidak dicipta secara automatik --- ## B. Modul yang Masih Relevan ### B1. Permohonan Lesen Penjaja (Pemohon/Awam) | | | |---|---| | Controller | `App\Http\Controllers\PenjajaController` | | Routes Utama | `/mohon-penjaja`, `/simpan-mohon-penjaja`, `/mohon_edit/{id}`, `/mohon_hapus/{id}`, `/mohon_papar/{id}`, `/mohon_hantar` | | Views Utama | `penjaja/mohon.blade.php`, `penjaja/mohon_papar.blade.php` | | Dashboard Pemohon | `dashboard.blade.php` (route: `/dashboard`) → `PenjajaController@list` | | Status | AKTIF | ### B2. Permohonan Lesen Penjaja (Admin — Mohon Atas Nama) | | | |---|---| | Controller | `App\Http\Controllers\Admin\PenjajaController` | | Routes Utama | `/mohon-penjaja-admin`, `/simpan-mohon-penjaja-admin` | | Views Utama | `admin/penjaja/mohon_baru.blade.php` | | Catatan | Lompat terus ke status `lawatan tapak` — fast-track untuk admin | | Status | AKTIF | ### B3. PT Workflow (Pembantu Tadbir) | | | |---|---| | Controllers | `Admin\PenjajaController` (senarai), `Admin\PtPenjajaController` (tindakan) | | Queue Screens | `/penjaja-baru` (baru), `/penjaja-proses` (tunggu bayar), `/penjaja-bukafail` (bayar disahkan), `/penjaja-daftarlesen` (daftar lesen) | | Tindakan | Simpan Wang Proses, Simpan No Fail, Hantar ke IK, Urus Mesyuarat, Cetak Lampiran B | | Status | AKTIF | ### B4. IK Workflow (Inspektor Kesihatan) | | | |---|---| | Controller | `Admin\IkPenjajaController` | | Routes | `/penjaja-pemeriksaan`, `/ik-simpan-lokasi`, `/ik-simpan-ulasan` | | Model Utama | `BorangUlasanIk` (30+ fields, 3 foto lawatan tapak) | | Status | AKTIF | ### B5. PP & Pengarah Workflow | | | |---|---| | Controller | `Admin\PegawaiPenjajaController` | | Routes | `/penjaja-cadangan`, `/penjaja-ulasan-cadangan`, `/pegawai-simpan-cadangan`, `/pegawai-simpan-ulasan-cadangan` | | Model Utama | `UlasanPegawai` (gabungkan cadangan PP dan ulasan Pengarah dalam satu model) | | Status | AKTIF | ### B6. Mesyuarat Pelesenan + Lampiran B | | | |---|---| | Controller | `Admin\PtPenjajaController` | | Routes | `/senaraimesyuarat`, `/senaraibawamesyuarat/{id}`, `/simpan_mesyuarat`, `/sahkan_senarai`, `/simpan_keputusan_mesyuarat`, `/cetak_lampiran_b` | | Model Utama | `MesyuaratPelesenan` + pivot `mesyuarat_pelesenan_lesen_penjajas` | | Output | Export landscape `.docx` menggunakan PHPWord, dikelompok mengikut kawasan | | Pivot Data | by_law, kodlesen, kadar_lesen, kadar_sampah, kadar_sewa_petak, kadar_patil, keputusan_mesyuarat | | Status | AKTIF | ### B7. Bil Proses + EPBT Integration (Mode Manual) | | | |---|---| | Controller | `Admin\PtPenjajaController::simpanWangProses()` | | Cara Kerja | PT masukkan No. Bil dari EPBT secara manual → sistem baca dari `second_mysql` untuk dapatkan butiran bil → semak `EpbtEcasResit` untuk resit bayaran | | Model | `BilPelbagai`, `BilPelbagaiItem`, `EpbtBpBil`, `EpbtEcasResit` | | Status | AKTIF (mode manual) | ### B8. Bil Auto-Jana (EPBT API — Mode Automatik) | | | |---|---| | Controller | `BilPelbagaiController::janaBil()` | | Cara Kerja | HTTP POST ke EPBT API → dapat `accountNo` → simpan dalam `BilPelbagaiApi` | | Status Sekarang | **KOD SIAP DITULIS** tetapi **ROUTE DITUKAR KE `doNothing()`** | | Catatan | Logik API lengkap, tetapi dimatikan sengaja — mungkin belum disahkan untuk production | ### B9. Semak Bayaran Lesen (Hutang Lesen) | | | |---|---| | Controller | `Admin\DashboardController::senaraiLesenBelumBayar()` + `semakBayaranLesen()` | | Routes | `/penjaja-hutang-lesen`, `/penjaja-hutang-lesen-semak` | | Model | `GrabResitLesen` (log batch semakan), `EpbtEcasResit` | | Status | AKTIF | ### B10. Dashboard Admin | | | |---|---| | Controller | `Admin\DashboardController::utama()` | | Route | `/dashmin/{ctahun?}` | | Kandungan | Count per status, filter tahun, semakan bayaran inline | | Isu | N+1 query: semua rekod 'menunggu bayaran proses' di-query EPBT setiap page load | | Status | AKTIF (dengan isu prestasi) | ### B11. Cetakan (IK + Cadangan Pegawai) | | | |---|---| | Controller | `Admin\CetakanPenjajaController` | | Routes | `/penjaja-cetak-pemeriksaan/{id}/{ik_id}`, `/penjaja-cetak-cadangan-pegawai/{id}/{ik_id}` | | Output | Download `.docx` menggunakan PHPWord | | Status | AKTIF | ### B12. Pengurusan Admin | | | |---|---| | Controller | `Admin\PengurusanAdminController` | | Routes | `/lantikan_admin`, `/cari_admin`, `/admin/users/{id}/update-role`, `/rem-admin/{nokp}` | | Status | AKTIF | ### B13. Pengumuman & Carousel | | | |---|---| | Controllers | `Admin\PengumumanController`, `Admin\GambarCarouselController` | | Akses | Role `super` sahaja (middleware `admin`) | | Status | AKTIF | ### B14. Profile + Document Streaming | | | |---|---| | Controller | `ProfileController` | | Routes | `/profile`, `/profil/stream/{filename}`, `/dokumen/stream/{id}/{filename}`, `/ik/stream/{id}/{filename}` | | Status | AKTIF | ### B15. Data AJAX (Cascading Dropdowns) | | | |---|---| | Controller | `DataController` | | Routes | `/get_kawasan`, `/get_taman`, `/get_jalan`, `/get_penempatan` | | Status | AKTIF | ### B16. Semakan EPBT Pelanggan | | | |---|---| | Controller | `Admin\PtPenjajaController::searchPelanggan()` | | Route | `/get-bil` | | Model | `EpbtPelanggan` | | Status | AKTIF | --- ## C. Modul/Fail yang Obsolete atau Mencurigakan ### C1. Fail Keselamatan — TINDAKAN SEGERA DIPERLUKAN | Fail | Isu | Tindakan | |---|---|---| | `public/test_curl.php` | Fail ujian dengan IP server terus (`1.9.131.236`), endpoint EPBT nyata, `client_key = 'MPJBT'` hardcoded, dan struktur data pelanggan nyata. Boleh diakses oleh sesiapa tanpa sebarang auth kerana berada dalam folder `public/`. | **PADAM SEGERA** | | `mylesen(2).sql` | Backup database penuh dalam root projek. Mengandungi data sensitif. Boleh terdedah jika repo dikongsi. | **PINDAH KELUAR dari projek** | ### C2. Fail Backup / Lama | Fail/Direktori | Isu | Tindakan | |---|---|---| | `app/Http/Controllers/Admin/asal/` | Mengandungi 4 controllers lama: `DashboardController`, `PenjajaController`, `IkPenjajaController`, `PegawaiPenjajaController`. Tiada routes menuju ke namespace ini. Versi utama sudah jauh lebih lengkap. | Padam | | `routes/asal/web.php` | Route lama sebelum refactor. Tidak dimuatkan oleh Laravel. | Padam | | `resources/views/admin/penjaja/asal/` | Folder views lama dengan ~16 fail. Tiada routes aktif menggunakan views ini. | Padam | | `resources/views/admin/penjaja/papar_permohonan-ori.blade.php` | Versi lama `papar_permohonan.blade.php`. | Padam | | `resources/views/admin/penjaja/partials/dokumen-ori.blade.php` | Versi lama partial. | Padam | | `resources/views/admin/penjaja/partials/ori_dokumen.blade.php` | Versi lama partial (nama berbeza). | Padam | | `resources/views/admin/penjaja/partials/wangproses_nofail-ori.blade.php` | Versi lama partial. | Padam | | `resources/views/layouts/appmin_lama.blade.php` | Layout admin lama. | Padam | | `resources/views/fahmi.blade.php` | Test view. Route `/` mengembalikan ini bukan halaman utama sebenar. `welcome.blade.php` wujud tetapi tidak digunakan. | Padam, tukar route `/` ke view yang betul | ### C3. Modul Stub / Tidak Lengkap | Modul | Fail | Isu | Cadangan | |---|---|---|---| | **PBTPay Payment Gateway** | `PbtpayController.php`, `PbtpayBil.php`, `PbtpayCart.php`, `PbtpayCartItem.php`, `PbtpayTransaksi.php`, `pbtpay/callback.blade.php`, `pbtpay/indirect.blade.php` | Controller `checkout()` tidak siap, tiada return value. 4 models kosong (tiada `$fillable`, tiada relations). Callback view hanya mengandungi teks "test". Routes wujud tetapi tidak berfungsi. | Keputusan diperlukan: implement atau padam semua | | **Bil Auto-Jana** | `BilPelbagaiController.php` | `janaBil()` ditulis lengkap tetapi route (`/pt/jana-bil-automatik`) sengaja ditukar ke `doNothing()` — ini bukan bug, ini keputusan disengajakan. | Aktifkan setelah disahkan dengan MBIP IT | | **Laporan Prestasi** | `Admin\LaporanPrestasiController.php` | Ada syntax error dalam method `utama()` — `->where()` tanpa parameter. Tiada route yang menuju ke controller ini. | Betulkan atau tulis semula | | **LesenPenjajaHistory** | `LesenPenjajaHistory.php` | Model kosong — tiada `$fillable`, tiada relations. Table wujud dalam migration tetapi model tidak digunakan dalam mana-mana controller. | Implement sebagai audit trail atau padam | | **UserPolicies** | `UserPolicies.php`, `LesenPenjajaPolicy.php` | Model `UserPolicies` dan table wujud. Policy class cuba guna model ini untuk semak `akses` tetapi kebanyakan method dalam Policy adalah empty stub. | Implement sepenuhnya atau guna Gate sahaja | | **BilPelbagaiItemController** | `BilPelbagaiItemController.php` | Class wujud tetapi tiada sebarang method. | Implement atau padam | ### C4. Isu Penamaan dan Konsistensi | Isu | Lokasi | Penerangan | |---|---|---| | **Bug: no_akaun_lesen vs no_fail_lesen** | `PtPenjajaController::simpanNoLesen()` baris 155 | Method simpan ke `no_akaun_lesen` dan `kod_lesen`, tetapi success message menyebut `$mohon->no_fail_lesen`. Ini adalah bug sebenar — nama field dalam mesej tidak sepadan dengan field yang disimpan. | | **Ketidakjelasan dua field** | `LesenPenjaja` model | `no_akaun_lesen` = akaun dalam sistem EPBT. `no_fail_lesen` = nombor fail fizikal MBIP. Kedua-dua digunakan dalam konteks berbeza tanpa dokumentasi jelas. | | **Typo nama migration** | `2025_06_19_084503_create_pengumumen_table.php` | Sepatutnya `pengumuman`, bukan `pengumumen`. Walaupun nama fail boleh kekal, jadual yang dicipta juga mungkin ada typo. | | **Nama route bercampur** | `routes/web.php` | Campuran Melayu/Inggeris: `pt.bawa-mesyuarat`, `admin.papar`, `get-bilpelbagai`, `penjaja-mohon`. Tiada naming convention yang konsisten. | | **Dua class bernama `PenjajaController`** | Namespace berbeza | `App\Http\Controllers\PenjajaController` (public) dan `App\Http\Controllers\Admin\PenjajaController` (admin). Dalam `web.php`, kedua-dua diimport dengan alias. Mengelirukan. | | **`senaraibawamesyuarat.blade.php`** | `admin/penjaja/` | Fail lama wujud tapi sistem menggunakan `senaraibawamesyuaratbaru.blade.php` yang lebih baru. | | **`laporandashboard.blade.php`** | `admin/penjaja/` | Nama mengelirukan — ia digunakan untuk paparan "semua permohonan" dalam `senarai_all()`, bukan laporan dashboard yang sebenar. | | **Boolean flags tidak digunakan** | `users` table | `is_admin_lesen_penjaja`, `is_admin_lesen_anjing`, `is_admin_lesen_perniagaan` ada dalam `$fillable` User model tetapi tidak digunakan dalam mana-mana logic. Role-based auth menggunakan `role` column sahaja. | | **`hantar_permohonan()` guna session** | `PenjajaController` | `lesen_penjaja_id` dibaca dari session — boleh gagal jika session expired atau tab dibuka berganda. | ### C5. Isu Seni Bina | Isu | Butiran | |---|---| | **Fat Controllers** | `Admin\PenjajaController::store()` melakukan dalam satu method: buat user, buat syarikat, buat user_syarikat, buat lesen_penjaja, upload dokumen, buat bil pelbagai, query EPBT, buat borang IK. Tiada DB transaction. Jika gagal di tengah, data tidak konsisten. | | **Status strings hardcoded** | Nilai seperti `'menunggu bayaran proses'`, `'lawatan tapak'`, `'ulasan pegawai'` tersebar dalam `PtPenjajaController`, `PenjajaController`, `Admin\PenjajaController`, dan `DashboardController`. Typo dalam satu tempat menyebabkan permohonan "hilang" dari semua queue. | | **N+1 query dalam Dashboard** | `DashboardController::utama()` dan `senarai_pt_proses()` loop semua rekod 'menunggu bayaran proses' dan buat query ke EPBT (`second_mysql`) untuk setiap rekod. Semakin banyak permohonan, semakin lambat halaman loads. | | **Logik EPBT diduplikasi** | Logik query `EpbtBpBil` dan `EpbtEcasResit` muncul dalam 4 tempat berbeza: `PtPenjajaController`, `Admin\PenjajaController`, `DashboardController`, dan lain-lain. Jika EPBT berubah struktur, perlu kemaskini 4 tempat. | | **Tiada Enum** | Semua nilai status adalah string literals. PHP 8.1 menyokong Enum natively. | | **Tiada Service layer** | Semua business logic dalam controllers. Tidak ada Service, Action, atau Command classes. | | **Gates vs Policies bercampur** | `AppServiceProvider` mendefinisikan 6 Gates, ada juga Policy classes, penggunaan tidak konsisten antara keduanya. | | **Tiada DB transaction** | Method-method yang menulis ke banyak jadual sekaligus (seperti `store()`) tidak wrapped dalam `DB::transaction()`. | | **Tiada event/job/observer** | Semua operasi synchronous. Tiada queue, tiada listeners, tiada observers. | | **Tiada FormRequest** | Validation berlaku secara inline dalam controllers. Hanya 2 FormRequest classes wujud untuk keseluruhan sistem. | | **Soft delete tidak digunakan** | `hapus_permohonan()` menggunakan `->delete()` — data dipadam terus tanpa boleh dipulihkan. | ### C6. Jadual Lengkap Routes dengan Status | Route | Method | Controller@Method | Status | |---|---|---|---| | `/` | GET | view('fahmi') | TEST VIEW — perlu tukar | | `/utama` | GET | Auth\AuthenticatedSessionController@create | aktif | | `/dashboard` | GET | PenjajaController@list | aktif | | `/mohon-penjaja` | GET | PenjajaController@create | aktif | | `/simpan-mohon-penjaja` | POST | PenjajaController@store | aktif | | `/mohon_hapus/{id}` | GET | PenjajaController@hapus | aktif | | `/mohon_edit/{id}` | GET | PenjajaController@edit | aktif | | `/mohon_papar/{id}` | GET | PenjajaController@papar | aktif | | `/mohon_hantar` | POST | PenjajaController@hantar | aktif | | `/pbtpay/checkout/{modul}/{id}` | POST | PbtpayController@checkout | **STUB** | | `/pbtpay/callback` | POST | view('pbtpay.callback') | **STUB** | | `/pbtpay/indirect` | POST | view('pbtpay.indirect') | **STUB** | | `/get-bil` | GET/POST | PtPenjajaController@searchPelanggan | aktif | | `/get_kawasan` | GET | DataController@getKawasan | aktif | | `/get_taman` | GET | DataController@getTaman | aktif | | `/get_jalan` | GET | DataController@getJalan | aktif | | `/get_penempatan` | GET | DataController@getPenempatan | aktif | | `/dashmin/{ctahun?}` | GET | DashboardController@utama | aktif | | `/penjaja-baru` | GET | Admin\PenjajaController@senarai_pt | aktif | | `/penjaja-proses` | GET | Admin\PenjajaController@senarai_pt_proses | aktif | | `/penjaja-bukafail` | GET | Admin\PenjajaController@senarai_pt_bukafail | aktif | | `/penjaja-daftarlesen` | GET | Admin\PenjajaController@senarai_pt_daftarlesen | aktif | | `/penjaja-pemeriksaan` | GET | IkPenjajaController@senarai_ik | aktif | | `/penjaja-cadangan` | GET | PegawaiPenjajaController@senarai_cadangan | aktif | | `/penjaja-ulasan-cadangan` | GET | PegawaiPenjajaController@senarai_ulasan_cadangan | aktif | | `/penjaja-mesyuarat` | GET | Admin\PenjajaController@senarai_mesyuarat | aktif | | `/penjaja-minitmesyuarat/{id}` | GET | Admin\PenjajaController@senarai_bawa_mesyuarat | aktif | | `/penjaja-keputusanmesyuarat` | GET | Admin\PenjajaController@senarai_keputusan | aktif | | `/penjaja-all` | GET | Admin\PenjajaController@senarai_all | aktif | | `/penjaja-hutang-lesen` | GET | DashboardController@senaraiLesenBelumBayar | aktif | | `/penjaja-hutang-lesen-semak` | GET | DashboardController@semakBayaranLesen | aktif | | `/simpan_wangproses` | POST | PtPenjajaController@simpanWangProses | aktif | | `/simpan_nofail` | POST | PtPenjajaController@simpanNoFail | aktif | | `/simpan_nolesen` | POST | PtPenjajaController@simpanNoLesen | aktif | | `/hantar_ppk` | POST | PtPenjajaController@hantarPPK | aktif | | `/simpan_mesyuarat` | POST | PtPenjajaController@simpanMesyuarat | aktif | | `/cetak_lampiran_b` | POST | PtPenjajaController@exportWord | aktif | | `/sahkan_senarai` | POST | PtPenjajaController@sahkanSenarai | aktif | | `/simpan_keputusan_mesyuarat` | POST | PtPenjajaController@simpanKeputusanMesyuarat | aktif | | `/ik-simpan-lokasi` | POST | IkPenjajaController@simpanLokasi | aktif | | `/ik-simpan-ulasan` | POST | IkPenjajaController@simpanUlasan | aktif | | `/pegawai-simpan-cadangan` | POST | PegawaiPenjajaController@simpan_cadangan | aktif | | `/pegawai-simpan-ulasan-cadangan` | POST | PegawaiPenjajaController@simpan_ulasan_cadangan | aktif | | `/pt/jana-bil-automatik` | POST | BilPelbagaiController@**doNothing** | **DIMATIKAN** (stub) | | `/mohon-penjaja-admin` | GET | Admin\PenjajaController@create | aktif | | `/simpan-mohon-penjaja-admin` | POST | Admin\PenjajaController@store | aktif | | `/lantikan_admin` | GET | PengurusanAdminController@showList | aktif (super) | | `/admin/users/{id}/update-role` | PATCH | PengurusanAdminController@updateRole | aktif (super) | | `/rem-admin/{nokp}` | GET | PengurusanAdminController@removeAdmin | aktif (super) | | `/admin/pengumuman/*` | CRUD | PengumumanController | aktif (super) | | `/carousel/*` | CRUD | GambarCarouselController | aktif (super) | --- ## D. Risiko Jika Terus Refactor Tanpa Pelan ### D1. Risiko Keselamatan — Perlu Tindakan Segera | Risiko | Punca | Kesan | |---|---|---| | `public/test_curl.php` boleh diakses tanpa auth | Fail ujian tertinggal dalam folder public | Pihak luar boleh guna `client_key = 'MPJBT'` untuk jana bil palsu ke sistem EPBT. Data pelanggan ujian terdedah. | | `mylesen(2).sql` dalam projek | Developer simpan backup dalam folder projek | Jika folder projek dikongsi atau di-commit ke git, seluruh database terdedah. | | Tiada HTTPS enforcement dalam kod | Tiada `ForceScheme` middleware | `BilPelbagaiController::janaBil()` memanggil endpoint EPBT melalui `http://` — komunikasi tidak selamat | ### D2. Risiko Integriti Data | Risiko | Punca | Kesan | |---|---|---| | Status "hilang" dari queue | Status string typo dalam satu controller | Permohonan tidak muncul dalam mana-mana queue — staf tidak dapat tindakan | | Data tidak konsisten jika simpan gagal | Tiada DB transaction dalam `store()` | Permohonan dicipta tetapi dokumen tidak diupload, atau syarikat dicipta tetapi lesen tidak | | Permohonan terlepas semak bayaran | Semak bayaran manual atau bila dashboard diload | Jika admin tidak reload dashboard, bayaran yang masuk tidak dikemaskini | | `no_fail_lesen` vs `no_akaun_lesen` kekeliruan | Dua field dengan nama serupa, peranan berbeza | Laporan salah, carian gagal, integration dengan EPBT gagal | ### D3. Risiko Prestasi | Risiko | Punca | Kesan | |---|---|---| | Dashboard lambat bila permohonan banyak | N+1 query ke EPBT `second_mysql` dalam loop | Setiap rekod 'menunggu bayaran proses' buat satu query. 50 rekod = 50 queries setiap kali dashboard dibuka | | Fail cetakan besar | PHPWord tanpa compression | `.docx` yang besar boleh timeout jika banyak permohonan dalam satu mesyuarat | ### D4. Risiko Kebolehselenggaraan | Risiko | Punca | Kesan | |---|---|---| | Developer baru keliru dengan `asal/` directories | Tiada dokumentasi tentang fail backup | Developer mungkin edit fail lama dalam `asal/` dan hairan kenapa tiada perubahan dalam sistem | | Perubahan status flow memerlukan tukar 4 tempat | Status strings tersebar | Kesilapan dalam satu tempat tidak akan kelihatan dalam ujian manual biasa | | `LaporanPrestasiController` tidak boleh diaktifkan | Syntax error | Jika developer cuba aktifkan, akan dapat 500 error | | Integrasi EPBT sukar dimodifikasi | Logic tersebar dalam 4 controllers | Jika EPBT tukar endpoint atau struktur data, perlu cari dan tukar di banyak tempat | ### D5. Risiko Integrasi | Risiko | Punca | Kesan | |---|---|---| | PBTPay tidak berfungsi jika diaktifkan | Semua stub, tiada implementasi sebenar | Pengguna boleh click butang bayar tetapi proses tidak berlaku, tiada makluman ralat yang berguna | | `janaBil()` `client_key` tidak disahkan | `'MPJBT'` hardcoded, tapi `test_curl.php` guna SHA-1 hash | Ada kemungkinan format key yang berbeza untuk production | --- ## E. Cadangan Struktur Baru Secara Ringkas ### E1. Pembersihan Segera (Lakukan Sebelum Sebarang Refactor) Tindakan berikut tidak memerlukan perubahan kepada mana-mana business logic: 1. **PADAM** `public/test_curl.php` — risiko keselamatan kritikal 2. **PINDAH** `mylesen(2).sql` keluar dari folder projek ke lokasi selamat 3. **PADAM** `app/Http/Controllers/Admin/asal/` (4 controllers lama) 4. **PADAM** `routes/asal/web.php` 5. **PADAM** `resources/views/admin/penjaja/asal/` (16 views lama) 6. **PADAM** semua fail dengan nama `-ori.blade.php`, `_lama.blade.php`, `-ori/` 7. **TUKAR** route `/` — dari `view('fahmi')` ke `view('welcome')` atau redirect ke `/utama` *Selepas setiap tindakan, jalankan semula semua routes untuk pastikan tiada broken link.* ### E2. Cadangan Struktur Direktori Baru ``` app/ Enums/ StatusPermohonan.php ← gantikan string hardcoded StatusMesyuarat.php RolePengguna.php Services/ ApplicationService.php ← business logic permohonan EpbtService.php ← semua EPBT API + DB calls BilService.php ← bil proses + lesen MesyuaratService.php ← mesyuarat + Lampiran B Http/ Controllers/ Pemohon/ ← public controllers Admin/ PT/ ← pembantu tadbir IK/ ← inspektor kesihatan Pegawai/ ← pp + pengarah Pengurusan/ ← admin management Laporan/ ← reports Api/ ← chrome extension API Requests/ Permohonan/ Bil/ Mesyuarat/ ``` **Rujuk `docs/rebuild-architecture.md` untuk pelan rebuild penuh termasuk status flow, role matrix, dashboard plan, integration design, API design, dan implementation roadmap.** --- *Dokumen ini adalah hasil audit statik berdasarkan pembacaan kod. Untuk maklumat terkini, sila semak kod semasa.*