# Deployment — typing.khoerulmuhlisin.my.id

Target hosting: **cPanel + Setup Node.js App (Passenger)**, satu domain untuk aplikasi dan API (`/api`).

Frontend (Vite) dan backend (Express) berjalan dalam **satu proses Node**. Express menyajikan `dist/` dan API sekaligus, jadi tidak perlu subdomain API maupun konfigurasi CORS antar-domain.

---

## 1. Build di komputer lokal

```bash
npm ci
npm --prefix server ci
npm run build:prod
```

Hasil build:

- `dist/` — frontend statis
- `server/dist/` — backend JavaScript (tidak butuh `tsx` di hosting)

---

## 2. Siapkan database di cPanel

1. Buka **cPanel → MySQL® Databases**.
2. Buat database, misalnya `globin_typing`.
3. Buat user MySQL dan beri **All Privileges** pada database tersebut.
4. Catat:
   - nama database (di shared hosting biasanya berprefix, contoh `user_globin_typing`),
   - user (contoh `user_globin`),
   - password.

---

## 3. Upload aplikasi

Ekstrak isi ZIP ke **document root domain**:

```
/home/USER/public_html/typing.khoerulmuhlisin.my.id
```

Struktur akhir yang diharapkan:

```
public_html/typing.khoerulmuhlisin.my.id/
├── dist/                     # hasil build frontend
├── DEPLOYMENT.md
└── server/
    ├── dist/                 # hasil build backend
    ├── sql/schema.sql
    ├── .htaccess             # memblokir akses langsung ke file backend
    ├── package.json
    ├── package-lock.json
    └── .env                  # dibuat di server, jangan di-commit
```

> `node_modules`, `src/`, dan file pengembangan lain tidak perlu diunggah.
> Jika memakai Git di cPanel, clone repo lalu jalankan build di server (butuh devDependencies).
> Pastikan `server/.htaccess` ikut terunggah (File Manager terkadang menyembunyikan file titik).

---

## 4. Buat `server/.env`

Buat file `/home/USER/public_html/typing.khoerulmuhlisin.my.id/server/.env`:

```ini
PORT=3000

DB_HOST=localhost
DB_PORT=3306
DB_USER=user_globin
DB_PASSWORD=password-database
DB_NAME=user_globin_typing

# Buat dengan: openssl rand -base64 48
JWT_SECRET=ganti-dengan-string-acak-panjang
JWT_EXPIRES_IN=12h

ADMIN_EMAIL=admin@domain-anda.com
ADMIN_PASSWORD=password-admin-yang-kuat

CORS_ORIGIN=https://typing.khoerulmuhlisin.my.id
```

Catatan:

- `FRONTEND_DIST` tidak perlu diisi. Default-nya otomatis menunjuk ke `../../dist` relatif terhadap `server/dist/index.js`.
- `server/.htaccess` yang disertakan memblokir akses HTTP langsung ke `.env`, source, dan file backend lain. Pastikan file tersebut tetap ada setelah upload.
- Ganti `JWT_SECRET` dan password admin **sebelum** aplikasi dipakai.

---

## 5. Install dependensi backend

Lewat **cPanel → Terminal**:

```bash
cd /home/USER/public_html/typing.khoerulmuhlisin.my.id/server
npm ci --omit=dev
```

Hanya dependensi backend yang dipasang. `node_modules` frontend tidak diperlukan karena frontend sudah berbentuk file statis.

---

## 6. Jalankan migrasi database

```bash
cd /home/USER/public_html/typing.khoerulmuhlisin.my.id
node server/dist/scripts/setup-db.js
```

Skrip ini akan:

- membuat tabel dan index,
- menambahkan kolom baru (`perfect_words`, `attempted_words`, `examiner_name`, dll.),
- membuat akun admin awal bila belum ada,
- mengisi data contoh hanya jika database masih kosong.

Jika user MySQL tidak punya izin `CREATE DATABASE`, skrip akan memberi peringatan lalu lanjut memakai database yang sudah dibuat di cPanel.

### Mengganti password admin yang sudah ada

`setup-db` tidak menimpa admin yang sudah ada. Untuk mereset:

```bash
# hapus admin lama lewat phpMyAdmin, atau:
mysql -u USER -p DB_NAME -e "DELETE FROM admins WHERE email='admin@domain-anda.com';"
node server/dist/scripts/setup-db.js
```

---

## 7. Buat Node.js App di cPanel

Buka **cPanel → Setup Node.js App → Create Application**:

| Pengaturan | Nilai |
|---|---|
| Node.js version | 20 atau 22 (minimal 18) |
| Application mode | Production |
| Application root | `public_html/typing.khoerulmuhlisin.my.id` |
| Application URL | `typing.khoerulmuhlisin.my.id` |
| Application startup file | `server/dist/index.js` |

Tambahkan environment variable bila belum terbaca dari `.env`:

```
NODE_ENV=production
```

Lalu klik **Create** / **Restart**.

> Passenger menjalankan `server/dist/index.js` dari root aplikasi. Frontend dibaca dari `dist/` dan API dari `/api` pada domain yang sama.

---

## 8. Aktifkan HTTPS

1. Buka **cPanel → SSL/TLS Status**.
2. Jalankan **AutoSSL** untuk domain `typing.khoerulmuhlisin.my.id`.
3. Setelah sertifikat aktif, pastikan aplikasi diakses lewat `https://`.

---

## 9. Verifikasi

Buka berurutan:

1. `https://typing.khoerulmuhlisin.my.id/` → halaman aplikasi tampil.
2. `https://typing.khoerulmuhlisin.my.id/api/health` → `{"ok":true,...}`.
3. Login admin.
4. Buka **Pengaturan Sistem → Identitas Laporan**, isi **Nama Penguji**, simpan.
5. Selesaikan satu tes, unduh PDF:
   - ukuran normal ±7–25 KB,
   - tanda tangan kiri **Penguji**, kanan **Peserta**,
   - tidak ada teks keluar border.
6. Refresh halaman `/results` atau `/admin` langsung → tidak 404 (SPA fallback aktif).

---

## 10. Update aplikasi berikutnya

Di lokal:

```bash
npm run build:prod
```

Upload ulang:

- seluruh isi `dist/`,
- seluruh isi `server/dist/`.

Jika dependensi berubah:

```bash
cd /home/USER/public_html/typing.khoerulmuhlisin.my.id/server
npm ci --omit=dev
```

Terakhir, **Restart** aplikasi dari cPanel → Setup Node.js App.

> Service worker PWA memakai `autoUpdate`. Jika pengguna masih melihat versi lama, lakukan hard reload (Ctrl+Shift+R) sekali.

---

## Troubleshooting

| Gejala | Penyebab umum | Solusi |
|---|---|---|
| 503 / Application failed to start | Startup file salah atau dependency kurang | Pastikan startup `dist/index.js`, jalankan `npm ci --omit=dev` di `server/` |
| `ER_ACCESS_DENIED_ERROR` | User/password/database salah | Periksa `server/.env`, pastikan user punya akses ke DB |
| Halaman hanya JSON 404 | `dist/` tidak ditemukan | Pastikan folder `dist/index.html` ada di document root domain |
| Asset 404 setelah update | Upload `dist/` tidak lengkap | Upload ulang seluruh folder `dist/` |
| API 500 setelah migrasi | Kolom baru belum ada | Jalankan `node server/dist/scripts/setup-db.js` |
| Tidak bisa login admin | Admin lama masih memakai password lama | Reset admin seperti langkah 6 |
| PDF lama masih terunduh | Cache service worker | Hard reload / hapus cache situs |
