1031 lines
39 KiB
Markdown
1031 lines
39 KiB
Markdown
# Cadangan Rebuild Architecture: Sistem myLesen
|
|
**Versi:** 1.0 — 18 Mac 2026
|
|
**Berdasarkan:** Audit `docs/audit-mylesen.md`
|
|
**Stack:** Laravel 11 + Bootstrap 5 + jQuery + MySQL
|
|
|
|
> **Nota:** Dokumen ini adalah blueprint cadangan. Ia tidak memerlukan implementasi sepenuhnya sekaligus. Setiap bahagian boleh dilaksanakan secara berperingkat.
|
|
|
|
---
|
|
|
|
## Bahagian 1 — Ringkasan Hala Tuju Rebuild
|
|
|
|
### 1.1 Masalah Utama Codebase Lama
|
|
|
|
**Masalah 1: Tiada satu sumber kebenaran untuk status**
|
|
Nilai `status_progress` seperti `'menunggu bayaran proses'` ditulis sebagai string literals dalam 4 controllers berbeza. Typo dalam satu tempat boleh menyebabkan permohonan tidak kelihatan dalam mana-mana queue.
|
|
|
|
**Masalah 2: Business logic tersebar dalam fat controllers**
|
|
`Admin\PenjajaController::store()` melakukan banyak perkara sekaligus tanpa DB transaction. Jika upload dokumen fail selepas lesen dicipta, data menjadi tidak konsisten.
|
|
|
|
**Masalah 3: EPBT integration logic diduplikasi**
|
|
Kod untuk query `EpbtBpBil` dan `EpbtEcasResit` muncul dalam 4 tempat berbeza. Satu perubahan pada EPBT memerlukan update di 4 lokasi.
|
|
|
|
**Masalah 4: Fail berbahaya dan kod tidak siap ditinggalkan**
|
|
`public/test_curl.php` adalah risiko keselamatan kritikal. Kod PBTPay, Laporan Prestasi, dan `LesenPenjajaHistory` adalah stubs yang tidak siap tetapi masih dalam codebase.
|
|
|
|
### 1.2 Prinsip Rebuild
|
|
|
|
1. **Bukan rewrite penuh** — aliran bisnes sedia ada sudah betul. Yang perlu diperbaiki adalah cara kod disusun.
|
|
2. **Laravel convention** — gunakan apa yang sudah ada dalam Laravel (FormRequest, Policy, Enum, Queue) sebelum bina sendiri.
|
|
3. **Tidak over-engineer** — tiada Repository pattern, tiada CQRS, tiada microservices. Service class yang mudah sudah cukup.
|
|
4. **Satu sumber kebenaran** — status, roles, dan constants dalam Enum dan Config, bukan string literals.
|
|
5. **Team kecil** — keputusan seni bina perlu boleh difahami oleh developer Laravel biasa dalam masa 30 minit membaca kod.
|
|
|
|
### 1.3 Pendekatan Keseluruhan
|
|
|
|
Rebuild dilakukan dalam **4 fasa berurutan**, bukan sekaligus:
|
|
|
|
| Fasa | Nama | Tempoh | Fokus |
|
|
|---|---|---|---|
|
|
| 0 | Cleanup | 1 minggu | Padam fail berbahaya dan backup lama |
|
|
| 1 | Refactor Core | 3 minggu | Enum, Services, FormRequest, fix N+1 |
|
|
| 2 | Lengkapkan Integrasi | 3 minggu | Aktifkan integration, putuskan PBTPay, bina laporan |
|
|
| 3 | API + UI | 4 minggu | Chrome extension API, UI improvements, UAT |
|
|
|
|
### 1.4 Keputusan Penting Yang Perlu Diambil Awal
|
|
|
|
1. Pakai PBTPay atau bayaran kekal melalui EPBT eCAS sahaja?
|
|
2. Aktifkan `janaBil()` auto-generate atau kekal manual?
|
|
3. Apa status terminal yang jelas untuk permohonan yang selesai?
|
|
4. Clarify peranan `no_akaun_lesen` vs `no_fail_lesen`
|
|
|
|
### 1.5 Trade-Off: Reuse vs Rewrite
|
|
|
|
| | Reuse | Rewrite |
|
|
|---|---|---|
|
|
| **Kelebihan** | Cepat, business rules terpelihara | Lebih bersih, technical debt hilang |
|
|
| **Kelemahan** | Masalah lama mungkin kekal | Berisiko hilang business rules |
|
|
| **Cadangan** | Reuse models dan blade views aktif. Rewrite controllers kepada pattern baru. Padam semua kod stub/backup. | |
|
|
|
|
---
|
|
|
|
## Bahagian 2 — Cadangan Seni Bina Baru
|
|
|
|
### 2.1 Struktur Folder Baru
|
|
|
|
```
|
|
app/
|
|
│
|
|
├── Enums/
|
|
│ ├── StatusPermohonan.php ← gantikan string hardcoded
|
|
│ ├── StatusMesyuarat.php
|
|
│ └── RolePengguna.php
|
|
│
|
|
├── Services/
|
|
│ ├── ApplicationService.php ← create, submit, status transitions
|
|
│ ├── EpbtService.php ← semua EPBT API + DB lookups
|
|
│ ├── BilService.php ← bil proses + bil lesen
|
|
│ └── MesyuaratService.php ← meeting + Lampiran B
|
|
│
|
|
├── Http/
|
|
│ ├── Controllers/
|
|
│ │ ├── Pemohon/ ← portal awam
|
|
│ │ │ ├── DashboardController.php
|
|
│ │ │ └── PermohonanController.php
|
|
│ │ ├── Admin/
|
|
│ │ │ ├── DashboardController.php
|
|
│ │ │ ├── PT/
|
|
│ │ │ │ ├── PermohonanController.php (senarai + view)
|
|
│ │ │ │ ├── BilController.php (wang proses)
|
|
│ │ │ │ └── MesyuaratController.php
|
|
│ │ │ ├── IK/
|
|
│ │ │ │ └── PemeriksaanController.php
|
|
│ │ │ ├── Pegawai/
|
|
│ │ │ │ ├── CadanganController.php (PP)
|
|
│ │ │ │ └── UlasanController.php (Pengarah)
|
|
│ │ │ ├── Pengurusan/
|
|
│ │ │ │ ├── PenggunaController.php
|
|
│ │ │ │ ├── PengumumanController.php
|
|
│ │ │ │ └── CarouselController.php
|
|
│ │ │ └── Laporan/
|
|
│ │ │ └── LaporanController.php
|
|
│ │ └── Api/
|
|
│ │ ├── AuthController.php
|
|
│ │ └── PermohonanController.php
|
|
│ ├── Requests/
|
|
│ │ ├── Permohonan/
|
|
│ │ │ ├── StorePermohonanRequest.php
|
|
│ │ │ └── UpdatePermohonanRequest.php
|
|
│ │ ├── Bil/
|
|
│ │ │ └── StoreBilRequest.php
|
|
│ │ └── Mesyuarat/
|
|
│ │ └── StoreMesyuaratRequest.php
|
|
│ └── Middleware/
|
|
│ ├── AdminMiddleware.php
|
|
│ └── KakitanganMiddleware.php
|
|
│
|
|
├── Models/ ← kekal, dengan penambahan
|
|
├── Policies/ ← implement sepenuhnya
|
|
└── Providers/
|
|
└── AppServiceProvider.php ← buang Gate definitions, guna Policy
|
|
|
|
routes/
|
|
├── web.php ← dikemas, dikelompok mengikut role
|
|
├── api.php ← BARU — untuk Chrome extension
|
|
└── auth.php
|
|
|
|
resources/views/
|
|
├── layouts/
|
|
│ └── app.blade.php ← satu layout sahaja
|
|
├── components/
|
|
├── pemohon/ ← portal awam
|
|
├── admin/
|
|
│ ├── dashboard.blade.php
|
|
│ ├── pt/
|
|
│ ├── ik/
|
|
│ ├── pegawai/
|
|
│ └── pengurusan/
|
|
└── print/ ← semua cetakan
|
|
├── lampiran-b.blade.php
|
|
├── borang-ik.blade.php
|
|
└── cadangan-pegawai.blade.php
|
|
```
|
|
|
|
### 2.2 Enum yang Dicadangkan
|
|
|
|
```php
|
|
// app/Enums/StatusPermohonan.php
|
|
enum StatusPermohonan: string
|
|
{
|
|
case DRAF = 'draf';
|
|
case BARU = 'baru';
|
|
case TUNGGU_BAYAR_PROSES = 'menunggu bayaran proses';
|
|
case SEMAK_BAYAR_PROSES = 'semakan bayaran proses';
|
|
case LAWATAN_TAPAK = 'lawatan tapak';
|
|
case ULASAN_PEGAWAI = 'ulasan pegawai';
|
|
case ULASAN_PENGARAH = 'ulasan pengarah';
|
|
case SOKONG_KE_MESYUARAT = 'sokong dibawa ke mesyuarat';
|
|
case TUNGGU_KEPUTUSAN = 'menunggu keputusan mesyuarat';
|
|
case KEPUTUSAN_DITERIMA = 'keputusan diperolehi';
|
|
case LESEN_DIKELUARKAN = 'lesen dikeluarkan'; ← BARU
|
|
case DITOLAK = 'ditolak'; ← BARU
|
|
|
|
public function label(): string { /* Malay labels */ }
|
|
public function warna(): string { /* badge colour */ }
|
|
}
|
|
|
|
// app/Enums/StatusMesyuarat.php
|
|
enum StatusMesyuarat: string
|
|
{
|
|
case DILULUSKAN = 'diluluskan';
|
|
case DITOLAK = 'ditolak';
|
|
case DITANGGUHKAN = 'ditangguhkan';
|
|
}
|
|
|
|
// app/Enums/RolePengguna.php
|
|
enum RolePengguna: string
|
|
{
|
|
case SUPER = 'super';
|
|
case PEMBANTU_TADBIR = 'pembantu tadbir';
|
|
case PP_KESIHATAN = 'penolong pegawai kesihatan';
|
|
case PP_TADBIR = 'penolong pegawai tadbir';
|
|
case PEGAWAI_TADBIR = 'pegawai tadbir';
|
|
case PENGARAH = 'pengarah';
|
|
}
|
|
```
|
|
|
|
### 2.3 Service Layer
|
|
|
|
Empat service class yang dicadangkan. Setiap satu mempunyai satu tanggungjawab yang jelas:
|
|
|
|
**`EpbtService`** — satu tempat untuk semua EPBT interactions:
|
|
```
|
|
getBilDetails(string $noAkaun): ?array
|
|
getPaymentReceipt(string $noAkaun): ?object
|
|
registerBilPelbagai(array $data): array
|
|
getLicenseAccount(string $noAkaun): ?object
|
|
```
|
|
|
|
**`BilService`** — wrapper untuk bil proses dan bil lesen:
|
|
```
|
|
simpanBilProses(LesenPenjaja $lesen, string $noAkaun): BilPelbagai
|
|
semakBayaranBilProses(BilPelbagai $bil): bool
|
|
semakBayaranLesen(LesenPenjaja $lesen): bool
|
|
```
|
|
|
|
**`ApplicationService`** — status transitions dan business rules:
|
|
```
|
|
hantarPermohonan(LesenPenjaja $lesen): void
|
|
hantarKeIk(LesenPenjaja $lesen): BorangUlasanIk
|
|
hantarKeUlasanPegawai(BorangUlasanIk $borang): void
|
|
```
|
|
|
|
**`MesyuaratService`** — mesyuarat logic:
|
|
```
|
|
tambahKeMesyuarat(LesenPenjaja $lesen, MesyuaratPelesenan $mesyuarat): void
|
|
simpanKeputusan(MesyuaratPelesenan $mesyuarat, array $keputusans): void
|
|
exportLampiranB(MesyuaratPelesenan $mesyuarat): StreamedResponse
|
|
```
|
|
|
|
### 2.4 Model Inventory
|
|
|
|
| Model | Tindakan | Penambahan |
|
|
|---|---|---|
|
|
| `LesenPenjaja` | Kekal, refactor | Tambah `SoftDeletes`, `StatusPermohonan` cast, indexes pada `status_progress` + `kawasan_id` |
|
|
| `User` | Kekal | Buang boolean flags yang tidak digunakan (`is_admin_lesen_*`) |
|
|
| `BorangUlasanIk` | Kekal | Tiada perubahan ketara |
|
|
| `UlasanPegawai` | Kekal | Namanya mengelirukan tapi OK untuk dikekalkan |
|
|
| `MesyuaratPelesenan` | Kekal | Tiada perubahan ketara |
|
|
| `BilPelbagai` | Kekal | Tambah index pada `lesen_penjaja_id` |
|
|
| `BilPelbagaiApi` | Kekal | Gunakan sebagai integration log |
|
|
| `EpbtBpBil` hingga `EpbtBandar` (11 models) | Kekal | Read-only, sudah betul |
|
|
| `LesenPenjajaHistory` | **Implement** | Tambah fillable, gunakan sebagai audit trail |
|
|
| `PbtpayBil/Cart/CartItem/Transaksi` | **Keputusan** | Implement atau padam |
|
|
| `GrabResitLesen` | Refactor | Jadikan generic `BatchSemakan` atau integrate ke `BilService` |
|
|
| `UserPolicies` | Kekal | Tapi gunakan sepenuhnya dalam Policy classes |
|
|
|
|
### 2.5 Naming Convention
|
|
|
|
| Jenis | Convention | Contoh |
|
|
|---|---|---|
|
|
| Controller | PascalCase + suffix | `PermohonanController`, `BilController` |
|
|
| Model | PascalCase domain term | `LesenPenjaja`, `BorangUlasanIk` |
|
|
| Route name | dot-notation, bahasa Melayu | `permohonan.index`, `bil.proses.simpan` |
|
|
| Blade view | kebab-case | `borang-permohonan.blade.php` |
|
|
| Service | PascalCase + Service | `EpbtService`, `BilService` |
|
|
| Enum | PascalCase | `StatusPermohonan`, `RolePengguna` |
|
|
| Migration | snake_case, descriptive | `add_soft_deletes_to_lesen_penjajas` |
|
|
|
|
### 2.6 Approach untuk Validation, Policies, Helpers
|
|
|
|
**Validation:** Setiap action yang menerima input pengguna MESTI ada FormRequest class sendiri. Tidak ada inline `$request->validate([...])` dalam controllers.
|
|
|
|
**Policies:** Buang semua Gate definitions dari `AppServiceProvider`. Guna Policy sepenuhnya. Satu Policy per model utama. Implement semua method yang sekarang masih empty stub.
|
|
|
|
**Helpers:** Gunakan static methods dalam model atau Service, bukan global helper functions. Contoh: `LesenPenjaja::statusLabel($status)` atau `EpbtService::formatCustomer($lesen)`.
|
|
|
|
**Config:** Buat `config/epbt.php` untuk semua tetapan EPBT (host, client_key, dept, cost_center). Jangan hardcode dalam controller.
|
|
|
|
### 2.7 Pendekatan File Upload / Document Handling
|
|
|
|
- Kekal guna `Storage::disk('local')` dengan streaming melalui controller — ini adalah cara yang betul dan selamat
|
|
- Standardkan path: `storage/app/private/penjaja/{lesen_id}/{jenis}/{filename}`
|
|
- Untuk foto IK: `storage/app/private/penjaja/{lesen_id}/ik/{borang_id}/{foto}`
|
|
- Buat satu helper method dalam model atau service untuk generate path — elak duplicate path logic
|
|
|
|
### 2.8 Audit Trail
|
|
|
|
Implement `LesenPenjajaHistory` sebagai audit trail yang betul:
|
|
- Setiap perubahan `status_progress` simpan satu rekod: `lesen_penjaja_id`, `dari_status`, `ke_status`, `tindakan`, `catatan`, `user_id`, `created_at`
|
|
- Guna Model Observer untuk auto-log perubahan status
|
|
- Paparan timeline dalam tab "Sejarah" pada halaman detail permohonan
|
|
|
|
### 2.9 Pendekatan Print / PDF
|
|
|
|
- Kekal guna PHPWord untuk output `.docx` (Lampiran B, borang IK, cadangan pegawai) — ini sudah sesuai untuk keperluan PBT
|
|
- Extract semua print logic ke `MesyuaratService::exportLampiranB()` dan `PrintService::cetakBorangIk()`
|
|
- Jika PDF diperlukan pada masa hadapan, pertimbangkan DomPDF — tetapi ini adalah enhancement kemudian, bukan keperluan awal
|
|
- View untuk print berasingan dalam `resources/views/print/`
|
|
|
|
---
|
|
|
|
## Bahagian 3 — Status Flow dan Workflow Sistem
|
|
|
|
### 3.1 Diagram Aliran Status Lengkap
|
|
|
|
```
|
|
STATUS SIAPA TRIGGER TINDAKAN
|
|
────── ───────────── ────────
|
|
(null/draf) ←─ Pemohon/Admin ←─ simpan borang, belum hantar
|
|
|
|
↓ hantar_permohonan()
|
|
↓ [PEMOHON atau ADMIN]
|
|
|
|
BARU ─ queue PT ─
|
|
↓ simpanWangProses() [PT]
|
|
↓ masukkan No. Bil EPBT
|
|
|
|
MENUNGGU ─ queue PT ─
|
|
BAYARAN PROSES
|
|
↓ Auto: bila EpbtEcasResit ada resit
|
|
↓ [triggered semasa page load atau scheduled job]
|
|
|
|
SEMAKAN ─ queue PT ─
|
|
BAYARAN PROSES
|
|
↓ hantarPPK() [PT]
|
|
↓ buat BorangUlasanIk kosong
|
|
|
|
LAWATAN TAPAK ─ queue IK ─
|
|
↓ simpanUlasan() [IK — lengkapkan borang]
|
|
|
|
ULASAN PEGAWAI ─ queue PP/Pegawai Tadbir ─
|
|
↓ simpan_cadangan() [PP]
|
|
|
|
ULASAN PENGARAH ─ queue Pengarah ─
|
|
↓ simpan_ulasan_cadangan() [Pengarah]
|
|
│
|
|
├─ jika pengarah_ulasan = 'tidak disokong' (tangguh)
|
|
│ → kembali ke LAWATAN TAPAK (borang IK baru)
|
|
│
|
|
└─ jika pengarah_ulasan = 'disokong'
|
|
|
|
SOKONG KE ─ PT masukkan dalam mesyuarat ─
|
|
MESYUARAT
|
|
↓ sahkanSenarai() [PT — kunci senarai]
|
|
|
|
MENUNGGU ─ mesyuarat berlangsung ─
|
|
KEPUTUSAN
|
|
↓ simpanKeputusanMesyuarat() [PT]
|
|
|
|
KEPUTUSAN ─ status_mesyuarat set ─
|
|
DITERIMA
|
|
│
|
|
├─ 'diluluskan' → PT daftar No. Lesen → LESEN DIKELUARKAN ← BARU
|
|
├─ 'ditolak' → DITOLAK ← BARU (status terminal)
|
|
└─ 'ditangguhkan' → kekal KEPUTUSAN DITERIMA, tunggu mesyuarat berikut
|
|
|
|
LESEN DIKELUARKAN ─ status terminal positif ─
|
|
│
|
|
└─ Bil Lesen diterima dari EPBT
|
|
└─ Bayaran semak via EpbtEcasResit
|
|
```
|
|
|
|
### 3.2 Role yang Bertindak pada Setiap Peringkat
|
|
|
|
| Status | Queue Siapa | Tindakan Yang Boleh |
|
|
|---|---|---|
|
|
| (draf) | Pemohon | Edit, Hantar, Padam |
|
|
| BARU | PT | View detail, Masukkan No. Bil EPBT |
|
|
| TUNGGU BAYAR PROSES | PT | Semak bayaran (manual/auto) |
|
|
| SEMAK BAYAR PROSES | PT | Hantar ke IK |
|
|
| LAWATAN TAPAK | IK | Isi Borang Ulasan, Simpan lokasi, Upload foto |
|
|
| ULASAN PEGAWAI | PP/Pegawai Tadbir | Tulis cadangan |
|
|
| ULASAN PENGARAH | Pengarah | Buat ulasan, Sokong atau Tangguh |
|
|
| SOKONG KE MESYUARAT | PT | Masukkan dalam mesyuarat, Set kadar |
|
|
| TUNGGU KEPUTUSAN | PT | Simpan keputusan mesyuarat |
|
|
| KEPUTUSAN DITERIMA | PT | Daftar no. lesen (jika lulus) |
|
|
| LESEN DIKELUARKAN | PT | Semak bayaran lesen |
|
|
|
|
### 3.3 History / Status Log
|
|
|
|
Setiap perubahan status perlu dilog dalam `lesen_penjaja_histories`:
|
|
|
|
```
|
|
id
|
|
lesen_penjaja_id
|
|
dari_status ← StatusPermohonan enum value
|
|
ke_status ← StatusPermohonan enum value
|
|
tindakan ← contoh: 'PT hantar ke IK', 'IK simpan ulasan'
|
|
catatan ← optional, untuk note tambahan
|
|
user_id ← siapa buat tindakan
|
|
created_at
|
|
```
|
|
|
|
Ini membolehkan:
|
|
- Paparan timeline permohonan
|
|
- Debug bila status bermasalah
|
|
- Audit trail untuk pemeriksaan
|
|
|
|
---
|
|
|
|
## Bahagian 4 — Role dan Permission Matrix
|
|
|
|
### 4.1 Clarifikasi Role
|
|
|
|
Berdasarkan kod semasa, terdapat kemungkinan `pp tadbir` dan `pegawai tadbir` adalah dua nama untuk fungsi yang sama. Cadangan: **satukan kepada satu role** iaitu `pegawai tadbir` untuk semua PP/Pegawai.
|
|
|
|
| Role | Fungsi |
|
|
|---|---|
|
|
| `super` | Admin penuh sistem |
|
|
| `pembantu tadbir` | PT — proses permohonan, bil, mesyuarat |
|
|
| `pp kesihatan` | IK — lawatan tapak |
|
|
| `pegawai tadbir` | PP — cadangan + Pengarah — ulasan |
|
|
| `pengarah` | Pengarah — ulasan cadangan, keputusan |
|
|
| *(tiada role)* | Pemohon awam |
|
|
|
|
### 4.2 Permission Matrix
|
|
|
|
| Tindakan | super | pembantu tadbir | pp kesihatan | pegawai tadbir | pengarah | pemohon |
|
|
|---|---|---|---|---|---|---|
|
|
| Daftar akaun | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
|
| Login | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
|
| **Permohonan** | | | | | | |
|
|
| Hantar permohonan sendiri | ✓ | ✓ | — | — | — | ✓ |
|
|
| Hantar atas nama (admin) | ✓ | ✓ | — | — | — | — |
|
|
| Edit permohonan sendiri (draf) | ✓ | — | — | — | — | ✓ |
|
|
| Padam permohonan sendiri (draf) | ✓ | — | — | — | — | ✓ |
|
|
| View permohonan sendiri | ✓ | — | — | — | — | ✓ |
|
|
| **PT Workflow** | | | | | | |
|
|
| View queue baru/proses/bukafail | ✓ | ✓ | — | — | — | — |
|
|
| Masuk no bil EPBT | ✓ | ✓ | — | — | — | — |
|
|
| Hantar ke IK | ✓ | ✓ | — | — | — | — |
|
|
| Urus mesyuarat | ✓ | ✓ | — | — | — | — |
|
|
| Cetak Lampiran B | ✓ | ✓ | — | — | — | — |
|
|
| Daftar no lesen | ✓ | ✓ | — | — | — | — |
|
|
| Semak bayaran lesen | ✓ | ✓ | — | — | — | — |
|
|
| **IK Workflow** | | | | | | |
|
|
| View queue lawatan tapak | ✓ | ✓ | ✓ | — | — | — |
|
|
| Isi borang ulasan IK | ✓ | — | ✓ | — | — | — |
|
|
| Upload foto tapak | ✓ | — | ✓ | — | — | — |
|
|
| Cetak borang IK | ✓ | ✓ | ✓ | ✓ | ✓ | — |
|
|
| **PP/Pengarah Workflow** | | | | | | |
|
|
| View queue cadangan PP | ✓ | ✓ | — | ✓ | — | — |
|
|
| Tulis cadangan PP | ✓ | — | — | ✓ | — | — |
|
|
| View queue ulasan Pengarah | ✓ | ✓ | — | — | ✓ | — |
|
|
| Buat ulasan Pengarah | ✓ | — | — | — | ✓ | — |
|
|
| **Pengurusan** | | | | | | |
|
|
| Urus pengguna & role | ✓ | — | — | — | — | — |
|
|
| Urus pengumuman | ✓ | — | — | — | — | — |
|
|
| Urus carousel | ✓ | — | — | — | — | — |
|
|
| Urus master data | ✓ | — | — | — | — | — |
|
|
| **API** | | | | | | |
|
|
| Akses API Chrome Extension | ✓ | ✓ | ✓ | ✓ | ✓ | — |
|
|
| Kemaskini status via API | ✓ | ✓ | — | — | — | — |
|
|
|
|
### 4.3 Implementasi Cadangan
|
|
|
|
Guna **Policy** sepenuhnya, buang Gate definitions dari `AppServiceProvider`.
|
|
|
|
```php
|
|
// Satu Policy per model utama:
|
|
LesenPenjajaPolicy ← view, create, update, hantar, padam
|
|
BorangUlasanIkPolicy ← view, create, update
|
|
UlasanPegawaiPolicy ← view, create, update
|
|
MesyuaratPolicy ← view, create, update, cetak
|
|
```
|
|
|
|
Untuk check role dalam Policy, guna helper:
|
|
```php
|
|
$user->hasRole(RolePengguna::PEMBANTU_TADBIR)
|
|
```
|
|
|
|
---
|
|
|
|
## Bahagian 5 — Dashboard dan UI/UX Plan
|
|
|
|
### 5.1 Dashboard Per Role
|
|
|
|
**Pemohon:**
|
|
- Senarai semua permohonan saya + badge status berwarna
|
|
- Butang "Mohon Baru" yang jelas
|
|
- Notis jika ada dokumen yang perlu dikemaskini
|
|
- Pengumuman aktif
|
|
|
|
**PT (Pembantu Tadbir):**
|
|
- 4 count cards: Baru, Tunggu Bayar, Bayar Disahkan, Daftar Lesen
|
|
- Senarai "Urgent" — permohonan yang melebihi tempoh tertentu (aging indicator)
|
|
- Senarai mesyuarat akan datang
|
|
- Quick action: "Carian Permohonan" by No. NRIC atau No. Fail
|
|
|
|
**IK (Inspektor Kesihatan):**
|
|
- Count card: Dalam Queue Lawatan Tapak
|
|
- Senarai mengikut kawasan (kawasan yang paling banyak menunggu dahulu)
|
|
- Aging indicator: berapa hari sejak dihantar ke IK
|
|
- Quick action: klik terus ke borang ulasan
|
|
|
|
**PP/Pegawai Tadbir:**
|
|
- Count card: Menunggu Cadangan
|
|
- Senarai mengikut tarikh dihantar
|
|
- Aging indicator
|
|
|
|
**Pengarah:**
|
|
- Count card: Menunggu Ulasan Pengarah
|
|
- Paparan ringkasan cadangan PP untuk setiap item
|
|
- Butang Sokong / Tangguh terus dari dashboard
|
|
- Senarai mesyuarat akan datang
|
|
|
|
**Super/Admin:**
|
|
- KPI dashboard: permohonan diterima vs diproses vs diluluskan (mengikut tahun)
|
|
- Kadar kepatuhan KPI (berapa peratus dalam masa 14 hari)
|
|
- Graf trend bulanan
|
|
- Breakdown mengikut kawasan
|
|
- Senarai semua permohonan (carian + filter lengkap)
|
|
|
|
### 5.2 Prinsip UI/UX Keseluruhan
|
|
|
|
1. **Satu tema sahaja** — pilih satu daripada 4 tema yang ada, buang yang lain
|
|
2. **Bootstrap 5** — lebih mudah untuk team kecil maintain berbanding Tailwind + custom theming
|
|
3. **Status badge konsisten** — setiap status ada warna yang sama di semua halaman
|
|
4. **Mobile-friendly** — PT mungkin guna tablet semasa kerja
|
|
5. **Tindakan yang jelas** — setiap halaman queue ada satu "primary action" yang obvious
|
|
|
|
### 5.3 Landing Page dan Login
|
|
|
|
- Route `/` perlu redirect ke halaman login atau halaman awam yang betul
|
|
- Halaman login: ringkas, ada logo MBIP, ada link "Mohon Lesen Baharu"
|
|
- Selepas login, redirect mengikut role:
|
|
- Pemohon → `/dashboard` (senarai permohonan saya)
|
|
- Staf/Admin → `/dashmin` (admin dashboard)
|
|
|
|
### 5.4 Borang Panjang
|
|
|
|
- Borang permohonan panjang (ada maklumat peribadi, syarikat, lokasi, dokumen)
|
|
- Cadangan: kekalkan borang satu halaman tapi ada tab atau section headers yang jelas
|
|
- Simpan `draf` secara automatik — jangan paksa pemohon isi semua sekali gus
|
|
- Tunjukkan progress indicator (langkah 1/4, 2/4, dll)
|
|
|
|
### 5.5 Table, Filter, Search
|
|
|
|
- Semua senarai queue perlu ada:
|
|
- Carian by nama, NRIC, No. Fail
|
|
- Filter by kawasan
|
|
- Filter by tarikh (dari-hingga)
|
|
- Sorting by tarikh mohon (default: terbaru dahulu)
|
|
- Gunakan DataTables (sudah ada dalam `public/plugins/datatables/`) — cukup untuk keperluan semasa
|
|
|
|
### 5.6 Bahagian UI Yang Perlu Dibina Semula
|
|
|
|
| Bahagian | Isu Sekarang | Cadangan |
|
|
|---|---|---|
|
|
| Landing page | Route `/` → test view | Bina halaman awam yang proper |
|
|
| `papar_permohonan.blade.php` | Satu fail besar dengan `$show` tabs | Kekal tapi bersihkan, pisahkan partial yang lebih kecil |
|
|
| Dashboard pemohon | Hanya senarai, tiada context | Tambah status badge + next action hint |
|
|
| Dashboard admin | Muat semua data pada load | Pindah semak bayaran ke background job |
|
|
|
|
---
|
|
|
|
## Bahagian 6 — Rekabentuk Integration, Bil, Bayaran, No Resit, No Lesen
|
|
|
|
### 6.1 Dua Mode Integrasi EPBT
|
|
|
|
**Mode 1: Manual (Semasa Aktif)**
|
|
```
|
|
PT masuk No. Bil EPBT secara manual
|
|
→ sistem query second_mysql: EpbtBpBil.where('noakaun', $noAkaun)
|
|
→ simpan butiran dalam BilPelbagai
|
|
→ sistem query EpbtEcasResit untuk resit bayaran
|
|
→ jika ada resit, kemaskini status ke 'semakan bayaran proses'
|
|
```
|
|
|
|
**Mode 2: Auto-Generate (Kod Siap, Dimatikan)**
|
|
```
|
|
Sistem hantar HTTP POST ke epbt.mbip.gov.my/appsepbtkompaun_ws/...
|
|
→ EPBT create bil, return accountNo
|
|
→ simpan dalam BilPelbagaiApi (sebagai log)
|
|
→ continue ke semak bayaran seperti Mode 1
|
|
```
|
|
|
|
**Cadangan:** Aktifkan Mode 2 secara berperingkat:
|
|
1. Test di persekitaran UAT dulu
|
|
2. Sahkan `client_key = 'MPJBT'` dengan MBIP IT
|
|
3. Pindah config ke `config/epbt.php` (jangan hardcode)
|
|
4. Aktifkan dalam production setelah berjaya UAT
|
|
|
|
### 6.2 Rekabentuk BilService
|
|
|
|
```php
|
|
class BilService
|
|
{
|
|
public function simpanBilProses(LesenPenjaja $lesen, string $noAkaun): BilPelbagai
|
|
{
|
|
// Buat/semak BilPelbagai
|
|
// Tarik butiran dari EpbtBpBil (second_mysql)
|
|
// Semak EpbtEcasResit untuk bayaran
|
|
// Kemaskini status_progress jika bayar
|
|
// Log dalam LesenPenjajaHistory
|
|
}
|
|
|
|
public function semakSemuaBayaranPending(): void
|
|
{
|
|
// Untuk scheduled job
|
|
// Query semua lesen dengan status 'menunggu bayaran proses'
|
|
// Semak setiap satu, kemaskini jika sudah bayar
|
|
}
|
|
}
|
|
```
|
|
|
|
### 6.3 Aliran No. Fail dan No. Lesen
|
|
|
|
**Clarifikasi yang diperlukan (lihat Bahagian 10):**
|
|
|
|
| Field | Tujuan Dicadangkan | Siapa Isi | Bila |
|
|
|---|---|---|---|
|
|
| `no_fail_lesen` | Nombor fail fizikal MBIP (cth: MBIP/PS/2025/001) | PT | Selepas bayaran proses disahkan |
|
|
| `no_akaun_lesen` | Nombor akaun lesen dalam sistem EPBT | PT | Selepas keputusan mesyuarat diluluskan |
|
|
| `kod_lesen` | Kod jenis lesen dalam sistem EPBT | PT | Sama masa dengan no_akaun_lesen |
|
|
| `dt_lesen_dikeluarkan` | Tarikh lesen dikeluarkan | Auto (dari EPBT ElsnAkaun) | Bila no_akaun_lesen disimpan |
|
|
|
|
### 6.4 Cadangan Scheduled Jobs
|
|
|
|
```php
|
|
// routes/console.php atau app/Console/Kernel.php
|
|
|
|
// Setiap 15 minit: semak bayaran yang pending
|
|
Schedule::job(new SemakBayaranPendingJob)->everyFifteenMinutes();
|
|
|
|
// Setiap hari tengah malam: semak hutang lesen
|
|
Schedule::job(new SemakBayaranLesenJob)->dailyAt('23:00');
|
|
```
|
|
|
|
Ini menggantikan semak manual yang sekarang ada dalam dashboard dan perlu admin klik butang.
|
|
|
|
### 6.5 Keputusan PBTPay
|
|
|
|
**Pilihan A: Implement PBTPay**
|
|
- Kira-kira 2-3 minggu kerja
|
|
- Perlu: `PbtpayBil` model siap, `PbtpayController::checkout()`, callback handler, `PbtpayTransaksi` untuk tracking
|
|
- Bila pemohon bayar, status kemaskini automatik
|
|
|
|
**Pilihan B: Padam Semua PBTPay Stubs**
|
|
- Bayaran kekal melalui EPBT eCAS (sistem sedia ada)
|
|
- Kurang 20 fail untuk dikekalkan dalam codebase
|
|
- Lebih mudah maintain
|
|
|
|
**Cadangan: Pilihan B dahulu.** Jika PBTPay perlu kemudian, lebih senang bina dari awal dengan codebase yang bersih berbanding extend stubs yang ada.
|
|
|
|
### 6.6 Fail-Safe dan Duplicate Prevention
|
|
|
|
- Gunakan `firstOrCreate` (sudah ada dalam `simpanWangProses`) — kekalkan pattern ini
|
|
- Untuk scheduled job semak bayaran: semak `updated_at` terakhir, jangan proses rekod yang baru dikemaskini dalam masa 5 minit (debounce)
|
|
- Log setiap API call ke EPBT dalam `bil_pelbagai_apis` — sudah ada model untuk ini
|
|
|
|
### 6.7 Config yang Patut Boleh Dikonfigur
|
|
|
|
Buat `config/epbt.php`:
|
|
```php
|
|
return [
|
|
'host' => env('EPBT_HOST', 'epbt.mbip.gov.my'),
|
|
'client_key' => env('EPBT_CLIENT_KEY', 'MPJBT'),
|
|
'dept' => env('EPBT_DEPT', 'Jabatan Pelesenan'),
|
|
'cr_code' => env('EPBT_CR_CODE', 'H72407'),
|
|
'dr_code' => env('EPBT_DR_CODE', 'H72407'),
|
|
'cost_center' => env('EPBT_COST_CENTER', '101005'),
|
|
];
|
|
```
|
|
|
|
---
|
|
|
|
## Bahagian 7 — Rekabentuk API untuk Chrome Extension
|
|
|
|
### 7.1 Tujuan API
|
|
|
|
Chrome extension yang akan auto-fill sistem lain (cth: sistem utama EPBT atau sistem lain dalam rangkaian PBT) menggunakan data dari myLesen. Extension menggunakan data permohonan dari myLesen untuk mengisi borang dalam sistem lain tanpa menaip semula.
|
|
|
|
### 7.2 Authentication Strategy
|
|
|
|
Guna **Laravel Sanctum** untuk API token:
|
|
- Lebih ringan daripada Passport
|
|
- Sesuai untuk internal tool
|
|
- Token boleh dibuat per-user dalam dashboard profile
|
|
- Token boleh di-revoke bila-bila masa
|
|
|
|
Flow:
|
|
1. Staf login ke myLesen web UI biasa
|
|
2. Dalam Profile, staf boleh "Jana Token API" untuk Chrome extension
|
|
3. Token disimpan dalam extension
|
|
4. Setiap request API hantar `Authorization: Bearer {token}` header
|
|
|
|
### 7.3 Endpoints yang Dicadangkan
|
|
|
|
```
|
|
# Auth
|
|
POST /api/v1/auth/login → JWT/token (jika guna token-based login)
|
|
GET /api/v1/auth/me → maklumat pengguna semasa
|
|
|
|
# Carian Permohonan
|
|
GET /api/v1/permohonan → senarai (dengan filter: nokp, no_fail, status)
|
|
GET /api/v1/permohonan/{id} → detail permohonan
|
|
|
|
# Tindakan (restricted)
|
|
PATCH /api/v1/permohonan/{id}/status → kemaskini status (bergantung kebenaran)
|
|
|
|
# Referensi
|
|
GET /api/v1/kawasan → senarai kawasan
|
|
GET /api/v1/jenis-penjaja → senarai jenis penjaja
|
|
```
|
|
|
|
### 7.4 Struktur Response JSON
|
|
|
|
```json
|
|
{
|
|
"data": {
|
|
"id": 123,
|
|
"no_fail": "MBIP/PS/2025/001",
|
|
"no_akaun_lesen": "L001234",
|
|
"status": "lesen_dikeluarkan",
|
|
"status_label": "Lesen Dikeluarkan",
|
|
"pemohon": {
|
|
"nama": "Ahmad bin Ali",
|
|
"nokp": "800101-14-1234",
|
|
"notelefon": "0123456789",
|
|
"alamat": "No. 1, Jalan Kenanga"
|
|
},
|
|
"perniagaan": {
|
|
"jenis": "Gerai Makanan",
|
|
"jenis_jualan": "Nasi Campur",
|
|
"lokasi": "Batu 9, Jalan Skudai, Johor Bahru"
|
|
},
|
|
"lesen": {
|
|
"no_akaun": "L001234",
|
|
"kod_lesen": "PS001",
|
|
"tarikh_dikeluarkan": "2025-03-15",
|
|
"kadar_lesen": 150.00,
|
|
"kadar_sampah": 20.00
|
|
},
|
|
"diakses_extension_pada": "2026-03-18T10:00:00Z"
|
|
},
|
|
"meta": {
|
|
"api_version": "v1",
|
|
"akses_oleh": "ahmadstaff"
|
|
}
|
|
}
|
|
```
|
|
|
|
### 7.5 Status yang Layak untuk Export
|
|
|
|
Hanya permohonan dengan status tertentu yang patut boleh diakses oleh extension:
|
|
- `lesen_dikeluarkan` — lesen sudah aktif
|
|
- `keputusan_diterima` dengan `status_mesyuarat = 'diluluskan'` — diluluskan, proses pendaftaran
|
|
|
|
Permohonan dalam proses (baru, tunggu bayar, dll) tidak perlu diakses oleh extension kerana data belum lengkap.
|
|
|
|
### 7.6 Audit Log Extension
|
|
|
|
Setiap akses API Chrome extension log dalam `api_access_logs`:
|
|
```
|
|
id, user_id, permohonan_id, action, ip_address, user_agent, created_at
|
|
```
|
|
|
|
Ini membolehkan:
|
|
- Track siapa akses data permohonan mana
|
|
- Detect penggunaan tidak biasa (banyak request dari satu IP)
|
|
- Audit trail untuk pemeriksaan
|
|
|
|
### 7.7 Security Controls
|
|
|
|
- Rate limiting: 60 requests/minit per user (Laravel built-in throttle)
|
|
- Token expiry: boleh set dalam Sanctum config (cth: 24 jam atau tiada expiry untuk internal tool)
|
|
- Token revocation: dari dashboard Profile
|
|
- IP whitelist: opsional — boleh hadkan akses API kepada rangkaian pejabat sahaja (via middleware)
|
|
- API responses tidak include data sensitif yang tidak diperlukan (contoh: password_hash, remember_token)
|
|
|
|
### 7.8 Versioning
|
|
|
|
Gunakan URL versioning: `/api/v1/...`
|
|
|
|
Ini membolehkan API diubah pada masa hadapan tanpa breaking extension yang sedia ada. Jika ada breaking change, buat `/api/v2/...` dan maintain kedua-dua sementara extension dikemaskini.
|
|
|
|
### 7.9 Tandakan Rekod yang Telah Diakses
|
|
|
|
Tambah field dalam `lesen_penjajas`:
|
|
```
|
|
extension_diakses_pada timestamp nullable ← bila pertama kali diakses extension
|
|
extension_diakses_oleh foreign key (user) ← siapa akses
|
|
dipindahkan_pada timestamp nullable ← bila rekod ditandakan 'telah dipindah'
|
|
```
|
|
|
|
Ini membolehkan admin tahu rekod mana yang sudah dipindahkan ke sistem lain, dan yang mana perlu dikaji semula.
|
|
|
|
---
|
|
|
|
## Bahagian 8 — Reuse vs Rewrite
|
|
|
|
### 8.1 Komponen yang Boleh Reuse (dengan sedikit kemas kini)
|
|
|
|
| Komponen | Tindakan |
|
|
|---|---|
|
|
| `LesenPenjaja` model | Tambah SoftDeletes, StatusPermohonan cast |
|
|
| `BorangUlasanIk` model | Kekal, tiada perubahan ketara |
|
|
| `UlasanPegawai` model | Kekal, nama boleh kekal walaupun mengelirukan |
|
|
| `MesyuaratPelesenan` model + pivot | Kekal |
|
|
| `BilPelbagai`, `BilPelbagaiItem` | Kekal |
|
|
| `BilPelbagaiApi` | Kekal sebagai integration log |
|
|
| Semua 11 EPBT models | Kekal, read-only, betul |
|
|
| `Kawasan`, `Taman`, `Jalan`, `Penempatan` | Kekal |
|
|
| `JenisPenjaja`, `JenisJualan` | Kekal |
|
|
| `Syarikat`, `UserSyarikat` | Kekal |
|
|
| `UserPolicies` | Kekal, tapi implement Policy sepenuhnya |
|
|
| `Pengumuman`, `GambarCarousel` | Kekal |
|
|
| `User` model | Kekal, buang boolean flags tidak digunakan |
|
|
| Layout `appmin.blade.php` | Kekal sebagai base (selepas bersihkan) |
|
|
| Components blade (`text-input`, dll) | Kekal |
|
|
| Views queue senarai | Kekal, tambah filter/search |
|
|
| `papar_permohonan.blade.php` | Kekal, bersihkan, pisahkan partial |
|
|
| `DataController` (AJAX cascading dropdown) | Kekal |
|
|
|
|
### 8.2 Komponen yang Guna Logic Sahaja tapi Lebih Baik Ditulis Semula
|
|
|
|
| Komponen | Masalah | Cadangan |
|
|
|---|---|---|
|
|
| `Admin\PenjajaController::store()` | Fat method, tiada transaction | Pindah logic ke `ApplicationService`, buat FormRequest |
|
|
| `PtPenjajaController` | EPBT logic inline | Extract ke `EpbtService`, `BilService` |
|
|
| `DashboardController` | N+1 query, inline payment sync | Fix query, pindah sync ke scheduled job |
|
|
| `PegawaiPenjajaController` | OK tapi tiada FormRequest | Tambah FormRequest |
|
|
| `LaporanPrestasiController` | Syntax error, incomplete | Tulis semula dari awal |
|
|
| Gates dalam `AppServiceProvider` | Tiada konsistensi | Buang, implement Policy sepenuhnya |
|
|
| `ProfileController` | OK tapi ada kedua-dua public/admin path yang confusing | Bersihkan |
|
|
|
|
### 8.3 Komponen yang Patut Dibuang Terus
|
|
|
|
| Komponen | Sebab |
|
|
|---|---|
|
|
| `public/test_curl.php` | Risiko keselamatan kritikal |
|
|
| `mylesen(2).sql` | SQL backup dalam projek |
|
|
| `app/Http/Controllers/Admin/asal/` (4 files) | Backup lama, tidak digunakan |
|
|
| `routes/asal/web.php` | Route lama |
|
|
| `resources/views/admin/penjaja/asal/` | Views lama |
|
|
| Semua `-ori.blade.php`, `_lama.blade.php` | Fail backup |
|
|
| `resources/views/fahmi.blade.php` | Test view |
|
|
| `PbtpayController` + 4 PbtPay models | Jika keputusan tidak implement PBTPay |
|
|
| `GrabResitLesen` model | Gantikan dengan BilService + scheduled job yang lebih bersih |
|
|
| `User` boolean flags (`is_admin_lesen_*`) | Tidak digunakan |
|
|
| 3 daripada 4 admin themes (`public/kai/`, `public/corporate-ui/`, `public/kapella/`) | Hanya satu yang digunakan |
|
|
|
|
---
|
|
|
|
## Bahagian 9 — Pelan Implementasi Menyeluruh
|
|
|
|
### 9.1 Fasa 0 — Pembersihan (1 Minggu)
|
|
|
|
**Tiada perubahan pada business logic, hanya cleanup.**
|
|
|
|
| Task | Keutamaan | Anggaran |
|
|
|---|---|---|
|
|
| Padam `public/test_curl.php` | KRITIKAL | 5 min |
|
|
| Pindah `mylesen(2).sql` keluar dari projek | TINGGI | 5 min |
|
|
| Padam `app/Http/Controllers/Admin/asal/` | TINGGI | 30 min |
|
|
| Padam `routes/asal/web.php` | TINGGI | 5 min |
|
|
| Padam `resources/views/admin/penjaja/asal/` | TINGGI | 30 min |
|
|
| Padam semua `-ori.blade.php` dan `_lama.blade.php` | SEDERHANA | 30 min |
|
|
| Tukar route `/` dari `view('fahmi')` ke `redirect('/utama')` | SEDERHANA | 5 min |
|
|
| Test semua active routes masih berfungsi | WAJIB | 2 jam |
|
|
| Commit: "cleanup: remove backup files and test files" | — | 10 min |
|
|
|
|
**Jangan proceed ke Fasa 1 sebelum semua test lulus.**
|
|
|
|
### 9.2 Fasa 1 — Refactor Core (3 Minggu)
|
|
|
|
**Minggu 1: Enum + Config**
|
|
- Buat `app/Enums/StatusPermohonan.php`
|
|
- Buat `app/Enums/StatusMesyuarat.php`
|
|
- Buat `app/Enums/RolePengguna.php`
|
|
- Gantikan semua string literals dalam 4 controllers
|
|
- Buat `config/epbt.php`
|
|
- Test: semua queue screens tunjuk data betul
|
|
|
|
**Minggu 2: Services + FormRequest**
|
|
- Buat `app/Services/EpbtService.php` — consolidate 4-location duplication
|
|
- Buat `app/Services/BilService.php`
|
|
- Buat FormRequest: `StorePermohonanRequest`, `StoreBilRequest`
|
|
- Extract `Admin\PenjajaController::store()` ke `ApplicationService`
|
|
- Tambah `DB::transaction()` di mana perlu
|
|
- Tambah soft deletes pada `lesen_penjajas`
|
|
|
|
**Minggu 3: Policy + Audit Trail**
|
|
- Implement `LesenPenjajaPolicy` sepenuhnya
|
|
- Implement `BorangUlasanIkPolicy` sepenuhnya
|
|
- Buang Gate definitions dari `AppServiceProvider`
|
|
- Implement `LesenPenjajaHistory` sebagai audit trail
|
|
- Buat Observer untuk auto-log perubahan status
|
|
- Fix N+1: implement eager loading di senarai queue
|
|
|
|
### 9.3 Fasa 2 — Lengkapkan Integrasi (3 Minggu)
|
|
|
|
**Minggu 4: Aktifkan Integrasi**
|
|
- Aktifkan `BilPelbagaiController::janaBil()` (buang `doNothing()` routing)
|
|
- Test dalam persekitaran UAT dengan EPBT
|
|
- Implement `CheckPaymentStatusJob` untuk scheduled polling
|
|
|
|
**Minggu 5: PBTPay Decision + Laporan**
|
|
- Laksanakan keputusan PBTPay (implement atau padam)
|
|
- Betulkan `LaporanPrestasiController` — tulis semula dengan metric berguna:
|
|
- KPI compliance (permohonan dalam masa 14 hari)
|
|
- Breakdown mengikut kawasan
|
|
- Trend bulanan
|
|
|
|
**Minggu 6: UAT**
|
|
- UAT dengan pengguna sebenar (PT, IK, PP, Pengarah)
|
|
- Fix bugs dari UAT
|
|
- Update dokumentasi
|
|
|
|
### 9.4 Fasa 3 — API + UI (4 Minggu)
|
|
|
|
**Minggu 7-8: Chrome Extension API**
|
|
- Pasang Laravel Sanctum
|
|
- Buat `routes/api.php`
|
|
- Buat `Api\AuthController`
|
|
- Buat `Api\PermohonanController`
|
|
- Buat API Resources (`PermohonanResource`)
|
|
- Tambah token management dalam Profile page
|
|
- Test API dengan Postman atau bruno
|
|
|
|
**Minggu 9-10: UI + Final**
|
|
- Bina halaman awam / landing page yang betul
|
|
- Implementasi master data management UI (kawasan, taman, jalan, dll — sekarang tiada UI untuk edit)
|
|
- UI improvements berdasarkan feedback UAT
|
|
- Final end-to-end testing
|
|
- Deployment
|
|
|
|
### 9.5 Dependency Map
|
|
|
|
```
|
|
Fasa 0 (cleanup)
|
|
↓
|
|
Fasa 1 — Enum (tiada dependency)
|
|
↓
|
|
Fasa 1 — Services (perlu Enum dahulu)
|
|
↓
|
|
Fasa 1 — Policy (perlu Services)
|
|
↓
|
|
Fasa 2 — Integration (perlu Services dari Fasa 1)
|
|
↓
|
|
Fasa 3 — API (boleh parallel dengan Fasa 2, tapi perlu Enum + Models siap)
|
|
```
|
|
|
|
### 9.6 Strategi Migrasi (jika perlu run serentak)
|
|
|
|
Jika sistem lama perlu terus berjalan semasa rebuild:
|
|
- Kekalkan schema database yang sama — jangan tukar nama jadual atau column
|
|
- Semua perubahan additive (tambah column, tambah jadual, bukan ubah/padam)
|
|
- Jika tukar nama column perlu, buat alias atau migration yang tambah column baru dahulu, migrate data, kemudian padam yang lama
|
|
- Gunakan feature flag: `config('app.use_new_service_layer')` untuk switch antara lama/baru
|
|
|
|
### 9.7 Strategi Business Rule Preservation
|
|
|
|
- Baca kod lama secara teliti sebelum extract ke Service — jangan assume, confirm behavior
|
|
- Tulis tests untuk setiap business rule kritikal sebelum refactor
|
|
- Utamakan integration tests yang test full flow berbanding unit tests sahaja
|
|
|
|
### 9.8 Strategi Testing / UAT
|
|
|
|
**Fasa 1-2:** Developer test sendiri — jalankan semua route, check semua queue screens masih betul
|
|
|
|
**UAT Fasa 2 (akhir):** Minta pengguna sebenar test:
|
|
- Pemohon: hantar permohonan baru dari awal hingga hantar
|
|
- PT: proses permohonan dari baru hingga hantar ke IK
|
|
- IK: isi borang ulasan, upload foto
|
|
- PP: tulis cadangan
|
|
- Pengarah: buat ulasan
|
|
- PT: proses mesyuarat, keputusan, cetak Lampiran B
|
|
- PT: daftar lesen
|
|
|
|
---
|
|
|
|
## Bahagian 10 — Cadangan Keputusan Awal yang Perlu Dimuktamadkan
|
|
|
|
Senarai keputusan berikut perlu diputuskan **sebelum coding Fasa 1 bermula** untuk elak rework.
|
|
|
|
---
|
|
|
|
**Keputusan 1: PBTPay — Implement atau Padam?**
|
|
|
|
*Konteks:* PBTPay adalah payment gateway untuk pemohon bayar secara online. Sekarang semua code adalah stub.
|
|
|
|
- **Pilihan A:** Implement PBTPay (kira-kira 2-3 minggu kerja)
|
|
- **Pilihan B:** Padam semua stub. Bayaran kekal melalui EPBT eCAS semata-mata.
|
|
- **Cadangan:** Pilihan B untuk jangka pendek. Bina semula jika diperlukan pada masa hadapan.
|
|
|
|
---
|
|
|
|
**Keputusan 2: Aktifkan Auto-Generate Bil (janaBil)?**
|
|
|
|
*Konteks:* `BilPelbagaiController::janaBil()` sudah siap ditulis. Route sengaja ditukar ke `doNothing()`.
|
|
|
|
- **Soalan untuk MBIP IT:** Adakah `client_key = 'MPJBT'` sah untuk production? Adakah API endpoint EPBT boleh diakses dari server Laravel?
|
|
- **Cadangan:** Aktifkan dalam UAT dulu, production setelah disahkan.
|
|
|
|
---
|
|
|
|
**Keputusan 3: Status Terminal untuk Permohonan Selesai**
|
|
|
|
*Konteks:* Sekarang tiada status formal selepas lesen dikeluarkan.
|
|
|
|
- **Pilihan A:** Tambah `status_progress = 'lesen dikeluarkan'` sebagai status terminal
|
|
- **Pilihan B:** Kekal `keputusan diperolehi`, tapi tambah column boolean `lesen_sudah_dikeluarkan`
|
|
- **Cadangan:** Pilihan A — lebih jelas, konsisten dengan flow lain.
|
|
|
|
---
|
|
|
|
**Keputusan 4: Clarify no_akaun_lesen vs no_fail_lesen**
|
|
|
|
*Konteks:* Dua field ini serupa nama. Ada bug dalam kod semasa (simpan ke `no_akaun_lesen` tapi mesej kata `no_fail_lesen`).
|
|
|
|
- **Soalan untuk pentadbiran:** Apakah maksud tepat setiap nombor dalam aliran kerja PBT? Adakah `no_fail_lesen` adalah nombor fail fizikal MBIP (cth: MBIP/PS/2025/001)?
|
|
- **Cadangan:** Definisikan secara rasmi, kemudian fix bug dalam `simpanNoLesen()`.
|
|
|
|
---
|
|
|
|
**Keputusan 5: Email Notification**
|
|
|
|
*Konteks:* `MustVerifyEmail` dicomment out dalam `User.php`. Tiada email notification dalam sistem sekarang.
|
|
|
|
- **Pilihan A:** Implement email notification bila status berubah (perlu SMTP config)
|
|
- **Pilihan B:** Kekal tanpa email — pemohon perlu login untuk tahu status
|
|
- **Cadangan:** Pilihan B untuk Fasa 1. Email boleh ditambah kemudian jika diperlukan.
|
|
|
|
---
|
|
|
|
**Keputusan 6: Clarify Role PP — Satu atau Dua?**
|
|
|
|
*Konteks:* `pp tadbir` dan `pegawai tadbir` ada dalam middleware, tapi dalam controller hanya `pegawai tadbir` digunakan untuk PP.
|
|
|
|
- **Soalan:** Adakah `pp tadbir` berbeza daripada `pegawai tadbir` dalam konteks operasi harian?
|
|
- **Cadangan:** Jika sama fungsi, satukan kepada satu role sahaja. Jika berbeza, define dengan jelas perbezaan akses.
|
|
|
|
---
|
|
|
|
**Keputusan 7: Laporan Prestasi — Metric Apa Diperlukan?**
|
|
|
|
*Konteks:* `LaporanPrestasiController` ada tapi broken. KPI tracking sudah ada dalam model (`kiraKpi()`, `patuh_kpi` field).
|
|
|
|
- **Soalan untuk pengurusan:** Laporan apa yang benar-benar diperlukan?
|
|
- **Cadangan minimum:**
|
|
1. Laporan KPI bulanan (berapa % permohonan siap dalam 14 hari)
|
|
2. Laporan breakdown mengikut kawasan
|
|
3. Laporan status semua permohonan terkini
|
|
|
|
---
|
|
|
|
*Dokumen ini adalah cadangan hidup — boleh dikemaskini apabila keputusan dibuat.*
|
|
*Rujuk `docs/audit-mylesen.md` untuk maklumat codebase semasa.*
|