> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sertifikasitrainer.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Alur sertifikat

> Sertifikat TrainerHub otomatis dan upload BNSP manual.

Ada **dua jenis** sertifikat: PDF **TrainerHub** (otomatis setelah kursus selesai) dan **BNSP** (upload file resmi).

## Tipe sertifikat

| Tipe           | Cara dapat                            | Format           |
| -------------- | ------------------------------------- | ---------------- |
| **TrainerHub** | Progress kursus 100% → generate di UI | PDF + nomor + QR |
| **BNSP**       | Admin/peserta upload                  | PDF/image di R2  |

## Alur TrainerHub (otomatis)

```mermaid theme={null}
flowchart TD
  watch["Tonton lesson\nlesson_progress"] --> prog["Hitung progress %"]
  prog --> check{progress = 100%?}
  check -->|belum| wait["Tombol generate disabled"]
  check -->|ya| btn["POST /certificates/generate/:courseId"]
  btn --> pdf["Render PDF + QR"]
  pdf --> r2["Upload ke R2"]
  r2 --> db["Insert sertifikat row"]
  db --> dl["Download di /:slug/sertifikat"]
```

### Syarat generate

| Syarat                          | Error code            |
| ------------------------------- | --------------------- |
| User punya profil `peserta`     | `PESERTA_NOT_FOUND`   |
| Progress kursus 100%            | `COURSE_NOT_COMPLETE` |
| Belum ada sertifikat kursus ini | return existing       |
| Request dari workspace context  | `WORKSPACE_REQUIRED`  |

Kode: `apps/api/src/certificates/certificate.service.ts`

## Nomor sertifikat

Format dibangun dari tahun + judul kursus + urutan tahun itu:

```
buildCertificateNumber({ year, courseTitle, sequence })
```

QR mengarah ke: `{FRONTEND_URL}/validate/{certificateNumber}`

## Validasi publik

Tanpa login:

```
GET /api/certificates/validate/:certificateNumber
```

Mengembalikan data peserta, kursus, tanggal selesai — untuk verifikasi pihak ketiga.

## API peserta

| Endpoint                                | Fungsi                                      |
| --------------------------------------- | ------------------------------------------- |
| `GET /sertifikat/me`                    | List sertifikat workspace (scoped)          |
| `GET /certificates/me`                  | Legacy list by user                         |
| `GET /certificates/eligible-courses`    | Kursus + progress + sudah punya sertifikat? |
| `POST /certificates/generate/:courseId` | Generate PDF (butuh workspace header)       |

Frontend route: `/:slug/sertifikat` → `Sertifikat.tsx`

## BNSP upload

Admin atau peserta bisa upload sertifikat BNSP resmi:

* File disimpan di R2 path `peserta/{id}/sertifikat/`
* Field opsional: `nomorSertifikat`, `lsp`
* Satu record BNSP per peserta (update jika sudah ada)

## Sequence generate

```mermaid theme={null}
sequenceDiagram
  participant U as Peserta
  participant API as CertificateService
  participant DB
  participant PDF as CertificatePdfService
  participant R2

  U->>API: generate(courseId, workspaceId)
  API->>DB: cek progress = 100%
  API->>DB: hitung sequence tahun
  API->>PDF: render(nama, kursus, QR)
  PDF-->>API: buffer PDF
  API->>R2: upload
  API->>DB: createTrainerhubCertificate
  API-->>U: fileUrl signed/public
```

## Halaman terkait

* [Alur pembuatan kursus](/architecture/alur-kursus)
* [Alur video Mux](/architecture/alur-video) — progress dari menonton lesson
* [Glossarium](/architecture/glossarium#sertifikat)
