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

# Auth & peran

> Better Auth, role admin/peserta, session, dan auto-login setelah bayar.

Autentikasi memakai **Better Auth** dengan email/password. Session disimpan di Postgres; di production cookie secure + CSRF protection.

## Stack auth

```mermaid theme={null}
flowchart LR
  browser["Browser"] --> web["apps/web"]
  web --> auth["/api/auth/*\nBetter Auth"]
  auth --> db["sessions, users,\naccounts, verifications"]
  web --> api["/api/*\nrequireAuth middleware"]
```

Kode: `apps/api/src/auth/better-auth.ts`, `auth.middleware.ts`, `roles.ts`

## Peran

| Role di DB         | Dinormalisasi | Akses                           |
| ------------------ | ------------- | ------------------------------- |
| `admin`            | `admin`       | `/admin/*`, semua operasi admin |
| `user` atau kosong | `peserta`     | Workspace, kelas, AI hub        |
| lainnya            | ditolak       | 403 Forbidden                   |

Middleware `requireRole(['admin'])` atau `requireRole(['peserta'])` dipasang per route.

Frontend: `AdminRoute` vs `UserRoute` di `apps/web/src/routes/`.

## Flow login biasa

```mermaid theme={null}
sequenceDiagram
  participant U as User
  participant Web
  participant Auth as Better Auth
  participant DB

  U->>Web: /auth/login
  Web->>Auth: POST sign-in email+password
  Auth->>DB: validasi account
  Auth-->>Web: session cookie / bearer token
  Web->>Web: redirect by role
  Note over Web: admin → /admin/home\npeserta → /workspaces atau /:slug
```

## Auto-login setelah pembayaran

Saat peserta bayar lewat Scalev, mereka belum punya session. Flow **claim** membuat session otomatis:

```mermaid theme={null}
sequenceDiagram
  participant U as Peserta
  participant Web
  participant API as PaymentService
  participant Auth

  U->>Web: /payment/success?session=...
  Web->>API: POST claimPayment(sessionId, claimToken)
  API->>API: enrollment → paid + active
  API->>Auth: create session token (signInToken)
  Auth-->>Web: signInToken
  Web->>Auth: exchange token → session
  Web->>U: redirect ke workspace
```

Field terkait: `payment_sessions.sign_in_token`, `sign_in_token_expiry`.

Kalau token gagal/expired, UI fallback ke login manual (`requiresLogin: true`).

## Registrasi publik

`POST /api/payment/register` (dari `/register/:batchSlug/:tierSlug`):

1. Validasi batch `open` + tier aktif
2. Provision user Better Auth (email + password)
3. Buat `peserta` + `enrollment` pending
4. Buat `payment_session` + order Scalev

## Bearer token

Plugin `bearer()` aktif — API menerima `Authorization: Bearer <token>` untuk client non-browser.

<Warning>
  Token **tidak** dibaca dari query string (dihapus untuk keamanan — hindari kebocoran via log/referrer).
</Warning>

## Email terkait auth

| Event                | Provider                           |
| -------------------- | ---------------------------------- |
| Reset password       | Resend (jika `RESEND_API_KEY` set) |
| Verifikasi email     | Resend (opsional)                  |
| Invite peserta admin | `email.service.ts` templates       |

## Env

```bash theme={null}
BETTER_AUTH_SECRET=...          # min 32 char
BETTER_AUTH_URL=https://app.../api/auth
FRONTEND_URL=https://app...
```

## Halaman terkait

* [Alur pembelian](/architecture/alur-pembelian)
* [Tutorial Resend](/external/resend)
* [Glossarium — peran](/architecture/glossarium#peran)
