27 KiB
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:
rolecolumn dalam jadualusers— 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):
- Tiada status terminal "LESEN DIKELUARKAN" atau "SELESAI" —
status_progresskekal 'keputusan diperolehi' walaupun lesen sudah dikeluarkan senarai_pt_daftarlesen(queue pendaftaran no lesen) menggunakan statusulasan pegawai/pengarah/sokongdenganwhereNull('no_akaun_lesen')— ini adalah aliran berasingan tanpa status dedicated- Bayaran lesen (hutang lesen) dikesan melalui
whereNotNull('no_akaun_lesen')->whereNull('lesen_no_resit')— tiada status formal untuk ini - 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:
- PADAM
public/test_curl.php— risiko keselamatan kritikal - PINDAH
mylesen(2).sqlkeluar dari folder projek ke lokasi selamat - PADAM
app/Http/Controllers/Admin/asal/(4 controllers lama) - PADAM
routes/asal/web.php - PADAM
resources/views/admin/penjaja/asal/(16 views lama) - PADAM semua fail dengan nama
-ori.blade.php,_lama.blade.php,-ori/ - TUKAR route
/— dariview('fahmi')keview('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.