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>
This commit is contained in:
201
docs/architecture.md
Normal file
201
docs/architecture.md
Normal file
@@ -0,0 +1,201 @@
|
||||
# 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
|
||||
```
|
||||
Reference in New Issue
Block a user