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

> Dari katalog batch, register, Scalev, sampai akses workspace.

Peserta membeli **tier** di dalam **batch** training. Pembayaran lewat **Scalev**; setelah lunas, **enrollment** aktif dan fitur tier terbuka.

## Diagram utama

```mermaid theme={null}
flowchart TD
  start(["Calon peserta"]) --> catalog["/order\nKatalog batch publik"]
  catalog --> pick["Pilih batch + tier"]
  pick --> reg["/register/:batchSlug/:tierSlug"]
  reg --> form["Form: email, WA, password\nmetode bayar"]
  form --> apiReg["API createRegistration"]
  apiReg --> account["Provision akun\nBetter Auth"]
  apiReg --> enroll["Enrollment pending"]
  apiReg --> session["payment_session pending"]
  apiReg --> scalev["Scalev create order"]
  scalev --> checkout["/payment/checkout\nQRIS / VA / e-wallet"]
  checkout --> paid{Bayar?}
  paid -->|Ya| webhook["Webhook Scalev\norder.payment_status_changed"]
  paid -->|Polling| poll["Frontend poll status"]
  webhook --> activate["enrollment paid + active"]
  poll --> activate
  activate --> success["/payment/success"]
  success --> claim["claimPayment + signInToken"]
  claim --> workspace["Workspace /:slug"]
```

## Halaman publik (frontend)

| Route                    | Fungsi                                    |
| ------------------------ | ----------------------------------------- |
| `/order`                 | Katalog batch & tier (`OrderCatalog.tsx`) |
| `/register/:batch/:tier` | Form pendaftaran (`Register.tsx`)         |
| `/payment/checkout`      | Tampilkan QR/VA/link bayar                |
| `/payment/status`        | Cek status sesi                           |
| `/payment/success`       | Sukses + claim akun                       |
| `/payment/failed`        | Gagal / expired                           |
| `/payment/callback`      | Redirect dari provider                    |

## Tahap backend

### 1. Katalog publik

`GET /api/payment/public/batches` — batch aktif + tier + harga (rate limited).

### 2. Register & buat sesi

`POST /api/payment/register` (rate limit 10 / 15 menit):

1. Validasi batch & tier (slug)
2. Cek duplikat email per batch
3. Buat / pakai akun **Better Auth** (`provisionAuthAccount`)
4. `ensurePendingEnrollmentForPayment` — baris enrollment
5. Buat `payment_session` + `claimToken`
6. Panggil **Scalev** → QRIS, VA BNI/BRI/…, OVO, GoPay, dll.
7. Return `paymentUrl`, `sessionId`, instruksi bayar

Metode bayar (schema): `qris`, `va`, `invoice`, `ovo`, `dana`, `shopeepay`, `linkaja`, `gopay`

### 3. Pembayaran Scalev

Dua jalur konfirmasi:

```mermaid theme={null}
flowchart LR
  A["Scalev webhook"] --> B["handleScalevWebhook"]
  C["Poll checkout UI"] --> D["refreshScalevPaymentStatus"]
  B --> E["updateSessionFromScalevIfNotPaid"]
  D --> E
  E --> F["activateEnrollmentIfPaid"]
```

Webhook: verifikasi secret `SCALEV_WEBHOOK_SECRET`\
Kode: `payment.service.ts` → `handleScalevWebhook`

### 4. Aktivasi enrollment

Saat `payment_session.status = paid`:

* `enrollment.paymentStatus` → `paid`
* `enrollment.status` → `active`
* Workspace peserta bisa dipakai
* `getPaidAccess()` mengembalikan `aiFeatures`, `courseIds`, `benefits`

Idempotent — webhook retry tidak double-activate.

### 5. Claim setelah bayar

`claimPayment(sessionId, claimToken)`:

* Validasi claim token (one-time)
* Aktivasi enrollment jika belum
* Issue **signInToken** Better Auth → auto login di `/payment/success`

## Tier & Scalev mapping

Admin mengatur tier di batch:

| Field tier                        | Fungsi                      |
| --------------------------------- | --------------------------- |
| `price`                           | Harga (min validasi Scalev) |
| `courseIds`                       | Kursus yang dibuka          |
| `aiFeatures`                      | Gate AI hub                 |
| `scalevVariantUniqueId`           | Produk di Scalev            |
| `scalevBundlePriceOptionUniqueId` | Opsi harga bundle           |

Health check Scalev: `getBatchScalevHealth`, resync tier — admin tier management.

Dev lokal tanpa Scalev:

```bash theme={null}
# .env.development.local
PAYMENT_PROVIDER=manual
```

## Manual mark paid (admin)

Admin bisa tandai lunas di **Daftar Peserta** — enrollment paid meski sesi Scalev masih pending; checkout poll menyelaraskan session.

## Payment provider manual

Jika `PAYMENT_PROVIDER=manual`, URL bayar mengarah ke instruksi manual (`MANUAL_PAYMENT_URL`) — untuk dev/staging.

## Duplicate registration

Email sudah terdaftar di batch yang sama:

* Sudah **paid** → error duplicate
* Masih **pending** → resume sesi bayar lama jika masih valid

## Setelah bayar — apa yang terbuka?

```mermaid theme={null}
flowchart TD
  paid["Enrollment paid"] --> ws["Workspace dashboard"]
  paid --> courses["Kursus sesuai courseIds"]
  paid --> ai{"aiFeatures"}
  ai -->|trainer| t["Trainer workspace"]
  ai -->|master| m["Master bukti"]
  ai -->|branding| b["Branding copy"]
  paid --> cert["Sertifikat\njika memenuhi syarat"]
```

## Layanan terkait

* [Scalev setup](/external/scalev)
* [Alur kursus & akses](/architecture/alur-kursus)
* [Peta produk](/architecture/alur-produk)

## File penting

| File                       | Isi                                 |
| -------------------------- | ----------------------------------- |
| `payment.service.ts`       | Register, webhook, claim, tier CRUD |
| `payment.routes.ts`        | HTTP + rate limit                   |
| `scalev.service.ts`        | Client Scalev API                   |
| `enrollment.service.ts`    | Paid access aggregation             |
| `resolve-course-access.ts` | Resolve courseIds tier              |
