# eCert MBIP — Route Plan

## Admin Routes (Authenticated)

```
Prefix: /admin
Middleware: auth, verified (optional)
```

### Auth
```
GET    /login                                    → Auth\AuthenticatedSessionController@create
POST   /login                                    → Auth\AuthenticatedSessionController@store
POST   /logout                                   → Auth\AuthenticatedSessionController@destroy
```

### Dashboard
```
GET    /admin/dashboard                          → Admin\DashboardController@index
```

### Programs
```
GET    /admin/programs                           → Admin\ProgramController@index
GET    /admin/programs/create                    → Admin\ProgramController@create
POST   /admin/programs                           → Admin\ProgramController@store
GET    /admin/programs/{program:uuid}            → Admin\ProgramController@show
GET    /admin/programs/{program:uuid}/edit       → Admin\ProgramController@edit
PUT    /admin/programs/{program:uuid}            → Admin\ProgramController@update
DELETE /admin/programs/{program:uuid}            → Admin\ProgramController@destroy
POST   /admin/programs/{program:uuid}/publish    → Admin\ProgramController@publish
POST   /admin/programs/{program:uuid}/close      → Admin\ProgramController@close
```

### QR Code
```
GET    /admin/programs/{program:uuid}/qr             → Admin\QrCodeController@show
POST   /admin/programs/{program:uuid}/qr/generate    → Admin\QrCodeController@generate
GET    /admin/programs/{program:uuid}/qr/download    → Admin\QrCodeController@download
POST   /admin/programs/{program:uuid}/qr/deactivate  → Admin\QrCodeController@deactivate
```

### Participants (Pre-registered)
```
GET    /admin/programs/{program:uuid}/participants        → Admin\ParticipantController@index
GET    /admin/programs/{program:uuid}/participants/create → Admin\ParticipantController@create
POST   /admin/programs/{program:uuid}/participants        → Admin\ParticipantController@store
DELETE /admin/programs/{program:uuid}/participants/{pp}   → Admin\ParticipantController@destroy
GET    /admin/programs/{program:uuid}/participants/import → Admin\ParticipantController@importForm
POST   /admin/programs/{program:uuid}/participants/import → Admin\ParticipantController@import
GET    /admin/programs/{program:uuid}/participants/export → Admin\ParticipantController@export
```

### Certificate Template
```
GET    /admin/programs/{program:uuid}/template           → Admin\CertificateTemplateController@show
POST   /admin/programs/{program:uuid}/template           → Admin\CertificateTemplateController@store
PUT    /admin/programs/{program:uuid}/template/config    → Admin\CertificateTemplateController@updateConfig
DELETE /admin/programs/{program:uuid}/template           → Admin\CertificateTemplateController@destroy
GET    /admin/programs/{program:uuid}/template/preview   → Admin\CertificateTemplateController@preview
POST   /admin/programs/{program:uuid}/template/test      → Admin\CertificateTemplateController@testGenerate
```

### Questionnaire (Attachment to Program)
```
GET    /admin/programs/{program:uuid}/questionnaire         → Admin\ProgramQuestionnaireController@show
POST   /admin/programs/{program:uuid}/questionnaire/attach  → Admin\ProgramQuestionnaireController@attach
POST   /admin/programs/{program:uuid}/questionnaire/confirm → Admin\ProgramQuestionnaireController@confirm
DELETE /admin/programs/{program:uuid}/questionnaire/detach  → Admin\ProgramQuestionnaireController@detach
```

### Statistics
```
GET    /admin/programs/{program:uuid}/statistics         → Admin\StatisticsController@show
GET    /admin/programs/{program:uuid}/statistics/export  → Admin\StatisticsController@export
```

### Questionnaire Sets (Reusable)
```
GET    /admin/questionnaires                             → Admin\QuestionnaireSetController@index
GET    /admin/questionnaires/create                      → Admin\QuestionnaireSetController@create
POST   /admin/questionnaires                             → Admin\QuestionnaireSetController@store
GET    /admin/questionnaires/{set}                       → Admin\QuestionnaireSetController@show
GET    /admin/questionnaires/{set}/edit                  → Admin\QuestionnaireSetController@edit
PUT    /admin/questionnaires/{set}                       → Admin\QuestionnaireSetController@update
DELETE /admin/questionnaires/{set}                       → Admin\QuestionnaireSetController@destroy
POST   /admin/questionnaires/{set}/publish               → Admin\QuestionnaireSetController@publish
POST   /admin/questionnaires/{set}/archive               → Admin\QuestionnaireSetController@archive
```

### Questionnaire Questions
```
POST   /admin/questionnaires/{set}/questions             → Admin\QuestionController@store
PUT    /admin/questions/{question}                       → Admin\QuestionController@update
DELETE /admin/questions/{question}                       → Admin\QuestionController@destroy
POST   /admin/questions/reorder                          → Admin\QuestionController@reorder
```

### Certificate Generation (Admin Trigger)
```
POST   /admin/programs/{program:uuid}/certificates/generate-all  → Admin\CertificateController@generateAll
POST   /admin/programs/{program:uuid}/certificates/email-all     → Admin\CertificateController@emailAll
GET    /admin/programs/{program:uuid}/certificates               → Admin\CertificateController@index
```

---

## Public Routes (Token-based, No Auth)

```
Prefix: none
Middleware: throttle:60,1 (check-in), throttle:30,1 (download)
```

### Check-in Flow
```
GET    /p/{qr_token}                        → Public\CheckinController@show
                                              ↑ Papar: nama program, status, pilihan jenis peserta
                                              ↑ Redirect ke questionnaire/download jika masa download aktif

POST   /p/{qr_token}/staff                  → Public\CheckinController@staffCheckin
                                              ↑ Input: no_kp, email
                                              ↑ Semak pre-registered, rekod attendance

POST   /p/{qr_token}/external               → Public\CheckinController@externalRegister
                                              ↑ Input: name, no_kp, email, phone, agency
                                              ↑ Daftar + rekod attendance
```

### Questionnaire (Public)
```
GET    /p/{qr_token}/questionnaire/{participant_uuid}
                                            → Public\QuestionnaireController@show
                                              ↑ Semak: attendance exists, questionnaire published, belum jawab

POST   /p/{qr_token}/questionnaire/{participant_uuid}
                                            → Public\QuestionnaireController@submit
                                              ↑ Simpan responses, redirect ke certificate page
```

### Semakan Kehadiran (via QR masa download)
```
GET    /p/{qr_token}/semak                  → Public\AttendanceCheckController@show
                                              ↑ Papar form: masukkan no_kp untuk semak

POST   /p/{qr_token}/semak                  → Public\AttendanceCheckController@check
                                              ↑ Semak kehadiran, papar status sijil
```

### Certificate Download
```
GET    /certificate/{cert_token}            → Public\CertificateController@show
                                              ↑ Semak: token valid, masa download aktif, soalselidik dijawab
                                              ↑ Jika semua OK: papar download button / auto-download

POST   /certificate/{cert_token}/download   → Public\CertificateController@download
                                              ↑ Generate if not exists, serve file, increment download_count
```

---

## Route Logic / Decision Tree

### GET /p/{qr_token}
```
QR token valid?
  NO  → 404
  YES →
    Program published?
      NO  → Papar: "Program belum dibuka"
      YES →
        Masa download aktif (ecert_download_start_at <= now)?
          YES → Redirect ke /p/{qr_token}/semak
          NO  →
            Masa check-in aktif (checkin_start_at <= now <= checkin_end_at)?
              YES → Papar check-in form
              NO  → Papar: "Check-in belum dibuka" atau "Check-in sudah ditutup"
```

### POST /p/{qr_token}/staff
```
no_kp + email valid format?
  NO  → Validation error
  YES →
    Jumpa dalam program_participants (pre_registered)?
      NO  → "Tidak dijumpai dalam senarai" + pilihan daftar luar
      YES →
        Sudah check-in (attendances exists)?
          YES → "Anda sudah check-in" + papar masa check-in
          NO  →
            Rekod attendance
            Papar: "Check-in berjaya! Sijil akan dihantar ke emel selepas program."
```

### GET /certificate/{cert_token}
```
Token valid (dalam certificates table)?
  NO  → 404
  YES →
    Masa download aktif?
      NO  → Papar: "Sijil belum boleh dimuat turun. Mula dari: {datetime}"
      YES →
        Soalselidik diperlukan dan belum dijawab?
          YES → Redirect ke /p/{qr_token}/questionnaire/{participant_uuid}
          NO  →
            Sijil sudah generated?
              NO  → Dispatch GenerateCertificateJob, papar: "Sijil sedang disediakan..."
              YES → Papar download page / auto-download PDF
```

---

## Named Routes

```php
// Admin
'admin.dashboard'
'admin.programs.index'
'admin.programs.create'
'admin.programs.show'
'admin.programs.edit'
'admin.programs.qr.show'
'admin.programs.qr.generate'
'admin.programs.qr.download'
'admin.programs.participants.index'
'admin.programs.participants.import'
'admin.programs.template.show'
'admin.programs.questionnaire.show'
'admin.programs.statistics.show'
'admin.questionnaires.index'
'admin.questions.store'

// Public
'public.checkin.show'          → /p/{qr_token}
'public.checkin.staff'         → POST /p/{qr_token}/staff
'public.checkin.external'      → POST /p/{qr_token}/external
'public.questionnaire.show'    → /p/{qr_token}/questionnaire/{uuid}
'public.questionnaire.submit'  → POST /p/{qr_token}/questionnaire/{uuid}
'public.semak.show'            → /p/{qr_token}/semak
'public.semak.check'           → POST /p/{qr_token}/semak
'public.certificate.show'      → /certificate/{cert_token}
'public.certificate.download'  → POST /certificate/{cert_token}/download
```

---

## Middleware Stack

```php
// web.php
Route::middleware('auth')->prefix('admin')->name('admin.')->group(function () {
    // semua admin routes
});

Route::middleware(['throttle:checkin'])->prefix('p')->name('public.')->group(function () {
    // check-in routes
});

Route::middleware(['throttle:certificate'])->prefix('certificate')->name('public.certificate.')->group(function () {
    // download routes
});
```

Rate limiter dalam `AppServiceProvider`:
```php
RateLimiter::for('checkin', fn($req) => Limit::perMinute(60)->by($req->ip()));
RateLimiter::for('certificate', fn($req) => Limit::perMinute(30)->by($req->ip()));
```
