Files
eCert-MBIP/docs/architecture.md
Saufi 5b85822b78 chore: initial Laravel 13 project setup for eCert MBIP
- Laravel 13.9 + PHP 8.5 + MySQL
- Bootstrap 5.3 + jQuery 3.7 + Chart.js (replacing Alpine/Tailwind)
- Packages: intervention/image, dompdf, simple-qrcode, league/csv, laravel/breeze, laravel/boost
- 17 database migrations: users, programs, qr_codes, participants, attendances, certificates, questionnaires, email_logs, audit_logs
- 13 Eloquent models with full relationships
- Admin layout (Bootstrap 5 sidebar) + public layout (mobile-first)
- Rate limiters: checkin (60/min), certificate (30/min)
- Admin seeder: admin@mbip.gov.my
- Storage directories + symlink configured

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 15:44:19 +08:00

7.4 KiB

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