# eCert MBIP — System Architecture

## Overview

Sistem pengurusan sijil digital (eCert) untuk program-program yang dianjurkan oleh MBIP (Majlis Bandaraya Ipoh Perak). Sistem membolehkan admin urus program, kehadiran peserta, soalselidik, dan penjanaan sijil digital secara automatik.

---

## Technology Stack

| Komponen | Pilihan | Versi |
|----------|---------|-------|
| Backend Framework | Laravel | 12.x (latest stable) |
| PHP | PHP | 8.5.x |
| Database | MySQL | 8.x |
| Frontend CSS | Bootstrap | 5.3 |
| Frontend JS | jQuery | 3.7 |
| Template Engine | Blade | (built-in) |
| Asset Pipeline | Vite | (built-in Laravel) |
| Queue Driver | Database (→ Redis production) | — |
| Storage | Laravel Storage (local disk) | — |

---

## Composer Packages (Cadangan)

### Core / Wajib

| Package | Tujuan | Sebab Pilih |
|---------|--------|-------------|
| `intervention/image:^3.0` | Image manipulation untuk generate sijil | GD sudah ada, sokongan penuh Malay font TTF |
| `barryvdh/laravel-dompdf:^3.0` | Generate PDF sijil dari HTML | Standard Laravel, senang maintain |
| `simplesoftwareio/simple-qrcode:^4.0` | Generate QR Code PNG | Wrapper BaconQRCode, Laravel-friendly |
| `league/csv:^9.0` | Import CSV peserta | Ringan, tanpa dependency besar, handle UTF-8 BOM |
| `laravel/breeze:^2.0` | Admin auth scaffolding | Minimal, Blade stack, senang customise |

### Optional (Cadang Fasa Lanjut)

| Package | Tujuan | Bila Perlukan |
|---------|--------|---------------|
| `maatwebsite/excel:^3.1` | Import Excel (.xlsx) | Jika perlu format Excel (bukan CSV) |
| `spatie/laravel-activitylog:^4.0` | Audit log | Jika audit trail perlu lebih structured |

### Kenapa Tidak Pakai

- **Imagick**: Tidak ada sebagai PHP extension dalam environment ini — guna GD sahaja.
- **Laravel Sanctum/Passport**: Tidak perlu — public peserta akses via token, bukan API JWT.
- **Livewire/Vue/React**: Tidak dalam requirement — kekal Blade + jQuery.
- **Spatie Media Library**: Over-engineered untuk keperluan ini — guna Laravel Storage terus.

---

## Laravel Boost — Perlu Penjelasan

> **NOTA**: "Laravel Boost" tidak jelas merujuk kepada package mana. Kemungkinan:
> 1. **Laravel Breeze** — Auth scaffolding (cadangan saya untuk admin auth)
> 2. **Package dalaman** — Jika ada package khusus MBIP/organisasi
> 3. **Laravel Octane** — Performance boost (tidak diperlukan untuk sistem ini)
>
> **Sila sahkan** apa yang dimaksudkan dengan "Laravel Boost" sebelum Fasa 1 dimulakan.

---

## Application Architecture

```
eCert MBIP
├── Admin Module (authenticated, /admin/*)
│   ├── Program Management
│   ├── QR Code Management
│   ├── Participant Management (pre-register + import)
│   ├── Certificate Template Management
│   ├── Questionnaire Management
│   └── Statistics & Reports
│
├── Public Module (token-based, /p/* dan /certificate/*)
│   ├── QR Scan → Check-in Page
│   ├── Staff Check-in Flow
│   ├── Walk-in Registration Flow
│   ├── Questionnaire Page
│   └── Certificate Download
│
└── Background Jobs (Queue)
    ├── GenerateCertificateJob
    ├── SendCertificateEmailJob
    └── BlastCertificateLinkJob
```

---

## Key Design Decisions

### 1. Token-Based Public Access
- Peserta awam tidak login.
- Semua akses public guna `token` atau Laravel Signed URL.
- QR code bawa ke `/p/{qr_token}` — token UUID 64 char, bukan ID.
- Certificate download guna `/certificate/{cert_token}` — UUID unik per sijil.
- Questionnaire link guna `participant.uuid` dalam signed URL.

### 2. Participant Identity
- `no_kp` adalah pengecam unik peserta dalam sistem.
- Jika peserta hadir program berbeza, rekod `participants` dikongsi (cari by `no_kp`).
- Satu peserta boleh ada banyak `program_participants` dan `attendances`.

### 3. Certificate Generation Strategy
- **On-demand**: Sijil dijana semasa peserta minta download buat pertama kali.
- Flow: Soalselidik selesai → dispatch `GenerateCertificateJob` → simpan PNG → wrap PDF.
- Jika `certificate.file_path` sudah ada, terus serve — tidak jana semula.
- Gagal generate: simpan `status = failed`, log error ringkas.

### 4. Queue Strategy
- Development: `QUEUE_CONNECTION=database` (simpan dalam `jobs` table).
- Production: cadang `QUEUE_CONNECTION=redis` (perlu Redis server).
- Queue worker perlu jalan sebagai service (Supervisor di Linux / Task Scheduler di Windows).

### 5. File Storage
- Semua fail dalam `storage/app/private/` — tidak boleh akses direct.
- Download melalui controller dengan `Storage::download()`.
- QR code images dalam `storage/app/public/qrcodes/` (boleh akses via symlink).
- Certificate template dalam `storage/app/private/templates/`.
- Generated certificates dalam `storage/app/private/certificates/{program_uuid}/`.

### 6. Font untuk Certificate
- Guna `.ttf` font file dalam `storage/app/fonts/` atau `resources/fonts/`.
- Cadang bundel **Noto Sans** (Google Fonts, open source, sokong Malay charset).
- Font size perlu auto-scale berdasarkan panjang nama peserta.

### 7. Admin Auth
- Standard Laravel auth (email + password).
- Guna Laravel Breeze (Blade stack) untuk scaffolding.
- Semua `/admin/*` route dilindungi middleware `auth`.
- Satu role sahaja buat masa ini: `admin` (users table dengan is_admin flag atau role enum).

---

## Security Architecture

```
Request Layer:
  - Rate limiting: /p/* (60/min), /certificate/* (30/min), /admin/* (unlimited)
  - CSRF protection: semua POST form
  - Input validation: FormRequest classes

Auth Layer:
  - Admin: session-based Laravel auth
  - Public: token validation + signed URL verification

Data Layer:
  - no_kp: TIDAK dalam URL — guna UUID/token sahaja
  - Sensitive files: dalam storage/app/private (tidak boleh direct access)
  - Database: prepared statements (Eloquent ORM)

Audit Layer:
  - audit_logs table: admin actions (create/update program, upload template, dll)
  - email_logs table: semua email attempt
  - certificates table: track generated_at, emailed_at, downloaded_at
```

---

## Directory Structure (Cadangan)

```
app/
├── Http/
│   ├── Controllers/
│   │   ├── Admin/           ← semua admin controller
│   │   └── Public/          ← semua public controller
│   ├── Requests/            ← FormRequest validation
│   └── Middleware/
├── Models/
├── Jobs/
│   ├── GenerateCertificateJob.php
│   └── SendCertificateEmailJob.php
├── Mail/
│   └── CertificateReadyMail.php
├── Services/
│   ├── CertificateService.php   ← image manipulation logic
│   ├── QrCodeService.php
│   └── AttendanceService.php
└── Imports/
    └── ParticipantImport.php    ← CSV import logic

resources/
├── views/
│   ├── admin/               ← semua admin views
│   ├── public/              ← public check-in, questionnaire, download
│   ├── emails/              ← email templates
│   └── layouts/
│       ├── admin.blade.php
│       └── public.blade.php
├── fonts/                   ← TTF fonts untuk certificate
└── js/ + css/

storage/app/
├── public/qrcodes/          ← QR code images (accessible via symlink)
├── private/
│   ├── templates/           ← certificate template images
│   ├── certificates/        ← generated certificates
│   └── imports/             ← temporary CSV uploads
```
