# 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 ```