Files
KarbonDatacenter/README.md
2026-06-24 20:32:14 +08:00

283 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 **JanuariDisember** 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 <repo> 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).