# Sistem Pemantauan Kemampanan Pusat Data MBIP Aplikasi web untuk **Majlis Bandaraya Iskandar Puteri (MBIP)** bagi memantau kemampanan dan pelaporan karbon pusat data dalam kawasan pentadbiran MBIP. Sistem ini membantu JPP memantau penggunaan karbon, menyemak laporan perunding, merancang program/projek pengurangan karbon, dan menguruskan pelaporan pembaharuan lesen tahunan. Dibina dengan **Laravel 13 + MySQL + Blade + Bootstrap 5 + jQuery (Vite)**. --- ## Kandungan - [Ciri Utama](#ciri-utama) - [Keperluan Sistem](#keperluan-sistem) - [Pemasangan](#pemasangan) - [Akaun Contoh](#akaun-contoh) - [Peraturan Perniagaan Penting](#peraturan-perniagaan-penting) - [Senarai Semak Dinamik & Enjin Formula](#senarai-semak-dinamik--enjin-formula) - [Peranan & Kebenaran](#peranan--kebenaran) - [Keselamatan & Jejak Audit](#keselamatan--jejak-audit) - [Ujian](#ujian) - [Struktur Pangkalan Data](#struktur-pangkalan-data) --- ## Ciri Utama 1. **Autentikasi & Kawalan Akses** — log masuk/keluar, papan pemuka mengikut peranan, polisi & kebenaran, jejak audit penuh. 2. **Pengurusan Perunding** — JPP mendaftar akaun perunding; satu perunding boleh urus banyak pusat data. 3. **Pengurusan Pusat Data** — maklumat pusat data, perunding semasa, sejarah penugasan. 4. **Kitaran Pelaporan / Pembaharuan Lesen** — tahun pelaporan dikira automatik, tarikh tutup boleh dikonfigur. 5. **Pembina Templat Senarai Semak Dinamik** — JPP boleh tambah/ubah/buang seksyen, skop, item & formula **tanpa perubahan kod**. 6. **Modul Serahan Perunding** — isi senarai semak, muat naik PDF, simpan draf, hantar muktamad, jawab pembetulan. 7. **Muat Naik Dokumen & Versi** — PDF sahaja, hash fail, sejarah versi, muat turun dilindungi polisi. 8. **Aliran Kerja Semakan JPP** — tukar status, tugaskan pegawai, kunci/buka kunci, salinan keras, permohonan pembetulan. 9. **Modul Komen/Perbualan** — perbualan setiap serahan, mesej dalaman/luaran, soft delete dengan rekod audit. 10. **Senarai Peringatan** — pusat data yang belum serah untuk kitaran aktif, sorotan lampau tempoh. 11. **Papan Pemuka & Laporan** — statistik karbon A/B/C/D/E mengikut tahun, trend, pecahan status. 12. **Tetapan & Log Audit** — konfigurasi tarikh tutup lalai, had muat naik, toggle peringatan emel. --- ## Keperluan Sistem - PHP >= 8.3 (diuji pada PHP 8.5) - Composer 2.x - MySQL 8.x - Node.js >= 18 & NPM (untuk binaan aset Vite) --- ## Pemasangan ```bash # 1. Pasang kebergantungan PHP composer install # 2. Pasang & bina aset frontend (Bootstrap 5 + jQuery via Vite) npm install npm run build # atau `npm run dev` semasa pembangunan # 3. Fail persekitaran cp .env.example .env php artisan key:generate ``` Kemas kini tetapan pangkalan data dalam `.env`: ```dotenv DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=mbip_datacenter DB_USERNAME=root DB_PASSWORD=1234 ``` ```bash # 4. Cipta pangkalan data (jika belum) # CREATE DATABASE mbip_datacenter CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; # 5. Migrasi + semai data (peranan, pengguna contoh, templat senarai semak, data demo) php artisan migrate:fresh --seed # 6. Pautan storan (laporan PDF disimpan di storage/app/private) php artisan storage:link # 7. Jalankan pelayan php artisan serve ``` Lawati `http://127.0.0.1:8000` dan log masuk. > **Nota muat naik fail:** Laporan PDF disimpan pada disk `local` (`storage/app/private/reports/…`), **di luar** direktori awam. Ia hanya boleh dimuat turun melalui laluan terlindung yang dikuatkuasakan oleh polisi. --- ## Akaun Contoh Semua kata laluan: **`password`** | Peranan | Emel | |---|---| | Super Admin | superadmin@mbip.gov.my | | JPP Admin | jppadmin@mbip.gov.my | | Pegawai JPP | pegawai@mbip.gov.my | | Penolong Pegawai | penolong@mbip.gov.my | | Kerani | kerani@mbip.gov.my | | Perunding | perunding@example.com | --- ## Peraturan Perniagaan Penting 1. Pembaharuan lesen dibuat **pada/sebelum 1 Disember** setiap tahun (tarikh tutup boleh dikonfigur). 2. Tempoh lesen ialah **1 tahun**. 3. Perunding mesti serahkan bacaan/laporan karbon **Januari–Disember** bagi tahun pelaporan. 4. **Tahun pelaporan = Tahun pembaharuan − 2.** Contoh: pembaharuan **2028** ⇒ data pelaporan **2026**. 5. JPP boleh konfigur tarikh tutup tahunan (Tetapan → Kitaran). 6. Perunding mesti isi borang senarai semak **dan** muat naik laporan PDF sebelum pembaharuan diteruskan. 7. Serahan pertama diperlukan sebelum CCC diperoleh; serahan tahunan selepas itu. --- ## Senarai Semak Dinamik & Enjin Formula Senarai semak **tidak ditetapkan dalam kod**. Struktur disimpan secara relasi: ``` checklist_templates -> checklist_sections -> checklist_scopes -> checklist_items -> checklist_formulas (A = SKOP1 + SKOP2 + SKOP3, dsb.) ``` Setiap item boleh diberi `formula_token` (cth: `SKOP1`, `EE`, `RE`, `D4I`). Formula seksyen merujuk token ini dan token hasil seksyen terdahulu, dinilai mengikut turutan: | Token | Formula | Maksud | |---|---|---| | A | `SKOP1 + SKOP2 + SKOP3` | Jumlah pelepasan karbon | | B | `EE + RE` | Mekanisme pengurangan | | C | `A - B` | Baki karbon | | D | `A - D4I - D4II` | Bersih karbon | | E | `D / A * 100` | % pengurangan (dengan perlindungan bahagi sifar) | Formula dinilai oleh `App\Services\ExpressionEvaluator` — sebuah **parser aritmetik selamat** (recursive descent, menyokong `+ - * / ( )` dan pemboleh ubah token). Ia **tidak** menggunakan `eval()`, jadi formula yang dikonfigur pengguna JPP adalah selamat. Hasil disimpan dalam `submission_results` untuk pengagregatan papan pemuka. JPP boleh ubah semua ini melalui **Pembina Templat Senarai Semak** (menu sisi → Templat Senarai Semak → Bina). --- ## Peranan & Kebenaran Menggunakan `spatie/laravel-permission`. Super Admin memintas semua semakan melalui `Gate::before`. | Kebenaran | JPP Admin | Pegawai JPP | Penolong | Kerani | Perunding | |---|:--:|:--:|:--:|:--:|:--:| | Urus perunding | ✔ | ✔ | | | | | Urus pusat data | ✔ | ✔ | ✔ | | | | Urus penugasan | ✔ | ✔ | | | | | Urus kitaran | ✔ | ✔ | | | | | Urus templat senarai semak | ✔ | | | | | | Lihat semua serahan | ✔ | ✔ | ✔ | ✔ | | | Semak serahan | ✔ | ✔ | ✔ | | | | Kunci/buka kunci | ✔ | ✔ | | | | | Tanda salinan keras | ✔ | ✔ | ✔ | ✔ | | | Urus serahan sendiri | | | | | ✔ | | Laporan & statistik | ✔ | ✔ | ✔ | | | | Senarai peringatan | ✔ | ✔ | ✔ | ✔ | | | Urus pengguna & tetapan | ✔ | | | | | Perunding hanya boleh melihat pusat data & serahan yang **ditugaskan kepadanya** (dikuatkuasakan oleh `SubmissionPolicy` & `DataCentrePolicy`). --- ## Keselamatan & Jejak Audit - Validasi muat naik **PDF sahaja** (`mimes:pdf` + `mimetypes:application/pdf`) dengan had saiz boleh dikonfigur. - Fail disimpan di luar laluan awam; muat turun melalui laluan terlindung + polisi. - Setiap paparan/muat turun/tindakan diberi kuasa melalui polisi. - Jejak audit (`spatie/laravel-activitylog`) bagi: log masuk, perubahan status, kunci/buka kunci, muat naik dokumen, permohonan pembetulan, penugasan perunding, padam komen. - Soft delete pada model utama; komen hanya soft delete (rekod audit dikekalkan). - Perlindungan CSRF, pengesahan sisi pelayan, indeks pangkalan data pada kunci asing/status/kitaran/perunding/pusat data. --- ## Ujian Ujian ciri menggunakan SQLite dalam-memori (lihat `phpunit.xml`). ```bash php artisan test ``` Liputan ujian utama: - Perunding tidak boleh akses pusat data perunding lain - JPP boleh cipta perunding (+ akaun log masuk) - JPP boleh tugaskan perunding kepada pusat data - Hanya satu perunding aktif setiap pusat data (sejarah dikekalkan) - Tahun pelaporan dikira betul daripada tahun pembaharuan - Perunding boleh hantar senarai semak + PDF (tidak boleh hantar tanpa PDF) - Perunding tidak boleh edit serahan yang dikunci - JPP tukar status ke "pembetulan perunding" hanya dengan butiran pembetulan - Status "selesai" memerlukan tarikh hardcopy dihantar - Senarai peringatan mengeluarkan perunding selepas serahan - Pengiraan formula A, B, C, D, E (+ perlindungan bahagi sifar + keutamaan operator) --- ## Struktur Pangkalan Data `users`, `roles`/`permissions` (spatie), `consultants`, `data_centres`, `data_centre_consultant_assignments`, `reporting_cycles`, `checklist_templates`, `checklist_sections`, `checklist_scopes`, `checklist_items`, `checklist_formulas`, `submissions`, `submission_answers`, `submission_results`, `submission_documents`, `submission_status_histories`, `submission_correction_requests`, `submission_comments`, `app_settings`, `activity_log`. --- ## Pengezanan Docker (Produksi Ubuntu) Setup Docker mengikut konvensyen projek MBIP yang terbukti (rujukan: `spr2026`): **PHP 8.4 FPM + Nginx 1.27 (Alpine) + Supervisor**, menyambung ke **MySQL luaran** pada host/LAN. ### Fail berkaitan ``` Dockerfile # imej PHP 8.4 FPM (Debian Bookworm) docker-compose.yml # servis app + nginx, volume, network docker-compose.override.yml # override pembangunan (auto-dimuat) .dockerignore .env.docker # templat env produksi deploy.sh # skrip deploy/kemas kini docker/ ├── entrypoint.sh # tunggu MySQL, migrate, seed, cache ├── nginx/{nginx.conf,default.conf} ├── php/{php.ini,www.conf,opcache-dev.ini} └── supervisor/supervisord.conf # php-fpm + queue worker + scheduler ``` ### Langkah deploy pertama (di server Ubuntu) ```bash # 1. Klon kod & masuk direktori git clone mbip-datacenter && cd mbip-datacenter # 2. Sediakan env produksi cp .env.docker .env php artisan key:generate --show # salin nilai ke APP_KEY dalam .env nano .env # isi APP_URL, DB_USERNAME, DB_PASSWORD, DB_HOST # 3. Pastikan pangkalan data MySQL wujud (pada host/LAN) # CREATE DATABASE mbip_datacenter CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; # 4. Deploy (bina imej + aset + naik container + migrate + seed automatik) chmod +x deploy.sh ./deploy.sh --build ``` Container `app` (PHP-FPM) hanya didedahkan kepada `nginx` dalaman; Nginx didedahkan pada `NGINX_HTTP_PORT` (lalai **8010**). Letakkan reverse proxy (Nginx/Apache host atau Cloudflare) untuk TLS/443 di hadapan port ini. ### Kemas kini (deploy seterusnya) ```bash ./deploy.sh # git pull + npm build + up + migrate + optimize ./deploy.sh --build # paksa bina semula imej (selepas tukar Dockerfile) ./deploy.sh --fresh # migrate:fresh --seed (AMARAN: kosongkan data) ./deploy.sh --logs # ikut log container ./deploy.sh --down # hentikan container ``` ### Nota - **MySQL luaran:** `DB_HOST=host.docker.internal` menyambung ke MySQL pada host Ubuntu yang sama (dipetakan melalui `extra_hosts: host-gateway`). Tukar kepada IP pelayan MySQL jika berasingan. - **Aset Vite** dibina pada host oleh `deploy.sh` (`npm run build`) dan dihidang terus oleh Nginx daripada `./public` (lekapan baca-sahaja) — tiada langkah build aset dalam imej. - **Laporan PDF** disimpan dalam volume `mbip_dc_storage` (`storage/app/private`), kekal merentas deploy, di luar laluan awam. - `entrypoint.sh` automatik menunggu MySQL, jalankan migrasi, semai data kali pertama, dan bina semula cache pada setiap permulaan container. - Supervisor menjalankan **php-fpm + queue worker + scheduler** dalam container `app`. --- ## Binaan Aset (Build) ```bash npm run build # binaan produksi aset (manifest dalam public/build) ``` © Majlis Bandaraya Iskandar Puteri (MBIP).