# Panduan Deploy ke cPanel

Panduan ini memasang aplikasi **Presentasi 3D Kontraktor** di hosting cPanel yang memiliki menu
**Setup Node.js App** (CloudLinux / Phusion Passenger) dan database **MySQL/MariaDB**.

> Prinsipnya: semua proses berat (build frontend) dikerjakan di komputer Anda. Server hosting hanya
> menjalankan hasil build, sehingga aman untuk RAM/CPU shared hosting yang terbatas.

---

## Ringkasan

| Langkah | Di mana |
|---|---|
| 1. Build paket deploy | Komputer lokal |
| 2. Buat database MySQL | cPanel → MySQL® Database Wizard |
| 3. Upload & extract file | cPanel → File Manager |
| 4. Buat aplikasi Node.js | cPanel → Setup Node.js App |
| 5. Isi environment variables | Setup Node.js App |
| 6. Install dependensi | Setup Node.js App → Run NPM Install |
| 7. Migrasi & data awal | Setup Node.js App → Run JS script |
| 8. Jalankan & cek | Browser |

---

## Prasyarat

- Hosting cPanel dengan menu **Setup Node.js App** dan **Node.js versi 20 atau lebih baru**.
- **Domain atau subdomain khusus** untuk aplikasi, misalnya `3d.namakontraktor.com`.
  Aplikasi harus berada di **root** domain/subdomain (bukan di sub-folder seperti `namakontraktor.com/3d`).
- **SSL/HTTPS aktif** untuk domain tersebut (cPanel → SSL/TLS Status → AutoSSL). Sangat disarankan.
- Di komputer lokal: Node.js 20+ dan source code proyek ini.

Di seluruh panduan, ganti `USER` dengan username cPanel Anda (terlihat di pojok kanan atas cPanel
atau di path `/home/USER`).

---

## 1. Build paket deploy (di komputer lokal)

Di folder proyek, jalankan:

```bash
npm install
npm run build:deploy
```

Hasilnya:

- folder `deploy/` berisi semua file yang perlu diupload, dan
- `deploy.zip` (arsip dari folder tersebut) — bila sistem Anda mendukung pembuatan zip otomatis.
  Bila tidak, kompres isi folder `deploy/` secara manual menjadi zip.

Isi paket: `app.js` (startup file), `dist/` (server), `client/dist/` (tampilan web), `drizzle/` (migrasi
database), `package.json` produksi, `package-lock.json`, `.env.example`, dan panduan ini.
Folder `node_modules` **tidak** ikut — dependensi diinstal di server (langkah 6).

### Buat SESSION_SECRET

Siapkan juga string acak untuk `SESSION_SECRET` (dipakai di langkah 5):

```bash
node -e "console.log(require('crypto').randomBytes(48).toString('hex'))"
```

Simpan hasilnya (96 karakter) — jangan dibagikan.

---

## 2. Buat database MySQL

1. Buka **cPanel → MySQL® Database Wizard**.
2. **Step 1 – Create a Database**: isi nama, misalnya `kontraktor3d` → *Next Step*.
   Nama lengkapnya akan menjadi `USER_kontraktor3d`.
3. **Step 2 – Create Database Users**: isi username (mis. `app3d`) dan password kuat → *Create User*.
   Nama lengkapnya `USER_app3d`. **Catat password-nya.**
4. **Step 3 – Add User to the Database**: centang **ALL PRIVILEGES** → *Make Changes*.

Catat tiga nilai ini untuk langkah 5:

| Variabel | Contoh |
|---|---|
| `DB_NAME` | `USER_kontraktor3d` |
| `DB_USER` | `USER_app3d` |
| `DB_PASSWORD` | password dari Step 2 |

---

## 3. Upload & extract file

1. Buka **cPanel → File Manager**.
2. Di folder home (`/home/USER`), klik **+ Folder** dan buat folder aplikasi: `kontraktor3d`.
   > Folder ini **di luar** `public_html`. Jangan menaruh aplikasi di dalam `public_html`.
3. Buat juga folder untuk file upload (model 3D & logo): `kontraktor3d-storage`.
   > Dipisah dari folder aplikasi agar tidak ikut terhapus saat update versi.
4. Masuk ke folder `kontraktor3d` → **Upload** → pilih `deploy.zip`.
5. Klik kanan `deploy.zip` → **Extract** → extract ke `/home/USER/kontraktor3d`.
6. Pastikan `app.js` dan `package.json` berada langsung di `/home/USER/kontraktor3d/`
   (bukan di sub-folder `deploy/`). Setelah itu `deploy.zip` boleh dihapus.

Struktur yang benar:

```
/home/USER/
├── kontraktor3d/            ← Application root
│   ├── app.js
│   ├── package.json
│   ├── dist/
│   ├── client/dist/
│   └── drizzle/
├── kontraktor3d-storage/    ← UPLOAD_DIR (model 3D & logo)
└── public_html/             ← tidak dipakai aplikasi ini
```

---

## 4. Buat aplikasi Node.js

1. Buka **cPanel → Setup Node.js App** → **CREATE APPLICATION**.
2. Isi:

| Kolom | Isi |
|---|---|
| **Node.js version** | 20.x atau lebih baru (pilih versi tertinggi yang ≥ 20) |
| **Application mode** | `Production` |
| **Application root** | `kontraktor3d` |
| **Application URL** | pilih domain/subdomain Anda, **kosongkan** kolom path di sebelahnya |
| **Application startup file** | `app.js` |
| **Passenger log file** (bila ada) | `/home/USER/logs/kontraktor3d.log` |

3. Klik **CREATE**. Jangan tutup halaman ini — langkah 5–7 dilakukan di sini.

> Jangan mengupload folder `node_modules` sendiri. cPanel membuat `node_modules` di application root
> sebagai tautan ke virtual environment Node.js-nya.

---

## 5. Isi environment variables

Di halaman aplikasi (Setup Node.js App → klik ikon pensil pada aplikasi), bagian
**Environment variables** → **ADD VARIABLE** untuk setiap baris berikut, lalu **SAVE**:

| Nama | Nilai | Keterangan |
|---|---|---|
| `NODE_ENV` | `production` | |
| `DB_HOST` | `localhost` | |
| `DB_PORT` | `3306` | |
| `DB_NAME` | `USER_kontraktor3d` | dari langkah 2 |
| `DB_USER` | `USER_app3d` | dari langkah 2 |
| `DB_PASSWORD` | *(password database)* | dari langkah 2 |
| `SESSION_SECRET` | *(string acak 96 karakter)* | dari langkah 1 — wajib, jangan pakai contoh |
| `SESSION_MAX_AGE_HOURS` | `72` | lama staf tetap login |
| `COOKIE_SECURE` | `true` | `false` hanya bila situs belum HTTPS |
| `TRUST_PROXY` | `1` | |
| `UPLOAD_DIR` | `/home/USER/kontraktor3d-storage` | path absolut, di luar `public_html` |
| `MAX_UPLOAD_MB` | `50` | batas ukuran file GLB |
| `SEED_COMPANY_NAME` | nama perusahaan Anda | dipakai sekali saat seed |
| `SEED_ADMIN_NAME` | nama admin | dipakai sekali saat seed |
| `SEED_ADMIN_EMAIL` | email login admin | dipakai sekali saat seed |
| `SEED_ADMIN_PASSWORD` | password awal admin (min. 8 karakter) | ganti setelah login pertama |

> **Alternatif:** buat file `.env` di `/home/USER/kontraktor3d/` dengan isi yang sama
> (contoh format ada di `.env.example`). Bila keduanya diisi, nilai di halaman cPanel yang dipakai.

---

## 6. Install dependensi

Masih di halaman aplikasi, klik **Run NPM Install** dan tunggu sampai selesai (bisa 1–3 menit).

`package.json` di paket deploy hanya berisi dependensi produksi (tanpa alat build), dan tidak ada
yang perlu dikompilasi di server.

<details>
<summary>Cara lewat Terminal (bila tombol tidak tersedia)</summary>

Di bagian atas halaman aplikasi ada perintah *"Enter to the virtual environment"*, kira-kira:

```bash
source /home/USER/nodevenv/kontraktor3d/20/bin/activate && cd /home/USER/kontraktor3d
```

Jalankan di **cPanel → Terminal**, lalu:

```bash
npm install --omit=dev
```

</details>

---

## 7. Migrasi database & data awal

Di halaman aplikasi, bagian **Run JS script**:

1. Pilih **`db:migrate`** → **Run JS script**. Tunggu sampai muncul `Migrasi selesai.`
   Ini membuat semua tabel.
2. **Hanya pada instalasi pertama**: pilih **`db:seed`** → **Run JS script**.
   Ini membuat perusahaan, akun admin (dari `SEED_ADMIN_*`), dan satu klien contoh.

Lewat Terminal (setelah masuk virtual environment seperti di langkah 6):

```bash
npm run db:migrate
npm run db:seed
```

> Tabel `sessions` (login staf) dibuat otomatis saat aplikasi pertama kali berjalan.

---

## 8. Jalankan & cek

1. Klik **RESTART** di halaman aplikasi.
2. Buka `https://domain-anda/api/health` — harus tampil:
   ```json
   {"ok":true,"db":true}
   ```
3. Buka `https://domain-anda/` → login dengan `SEED_ADMIN_EMAIL` / `SEED_ADMIN_PASSWORD`.
4. **Segera ganti password admin** di menu **Pengaturan → Ganti kata sandi**.
5. Uji cepat: buat klien & proyek, upload model GLB, buat link klien, lalu buka link itu di jendela
   penyamaran (incognito).

Disarankan juga mengaktifkan **cPanel → Domains → Force HTTPS Redirect** untuk domain aplikasi.

---

## Lokasi data & backup

| Data | Lokasi | Cara backup |
|---|---|---|
| Database (proyek, anotasi, komentar, dll.) | MySQL `USER_kontraktor3d` | cPanel → phpMyAdmin → Export, atau Backup Wizard |
| File model 3D & logo | `/home/USER/kontraktor3d-storage/` (`models/`, `logos/`) | File Manager → Compress → Download |

File di folder storage memakai nama acak (UUID) dan **tidak bisa diakses langsung dari internet** —
hanya lewat aplikasi yang memeriksa login staf atau link klien yang valid. Backup database dan folder
storage harus dilakukan **bersamaan** agar keduanya cocok.

---

## Update ke versi baru

1. **Lokal:** ambil source terbaru, lalu `npm install` dan `npm run build:deploy`.
2. **Backup** database & folder storage (lihat bagian sebelumnya).
3. **File Manager** → folder `kontraktor3d`: hapus folder lama `dist`, `client`, dan `drizzle`.
   > Jangan hapus `.env` (bila ada) dan jangan sentuh folder `kontraktor3d-storage`.
4. Upload `deploy.zip` baru ke `kontraktor3d` → **Extract** (timpa file lama) → hapus zip-nya.
5. **Setup Node.js App** → aplikasi Anda:
   - **Run NPM Install** (perlu bila ada dependensi baru; aman dijalankan setiap update),
   - **Run JS script → `db:migrate`** (menerapkan perubahan database, bila ada),
   - **RESTART**.
6. Cek `https://domain-anda/api/health`, lalu muat ulang halaman di browser.

Migrasi bersifat bertahap dan hanya menjalankan perubahan yang belum diterapkan, sehingga aman
dijalankan setiap kali update. **Jangan** menjalankan `db:seed` lagi.

---

## Mengatasi masalah

| Gejala | Kemungkinan penyebab & solusi |
|---|---|
| Halaman error 503 / "Incomplete response" | Aplikasi gagal start. Buka log Passenger (path di langkah 4) atau file `stderr.log` di folder aplikasi. Pesan `Konfigurasi .env tidak valid` menunjukkan variabel yang salah/kosong. |
| Log: `SESSION_SECRET masih memakai nilai contoh` | Isi `SESSION_SECRET` dengan string acak dari langkah 1, lalu RESTART. |
| `/api/health` menampilkan `"db":false` | Cek `DB_NAME`, `DB_USER`, `DB_PASSWORD` (dengan awalan `USER_`) dan pastikan user sudah diberi **ALL PRIVILEGES** di langkah 2. |
| Setelah login, kembali ke halaman login terus | Pastikan `TRUST_PROXY=1` dan domain diakses lewat alamat yang sama (mis. jangan campur `www.` dan tanpa `www.`). Hapus cookie situs di browser lalu coba lagi. |
| Upload model gagal untuk file besar | Batas aplikasi: `MAX_UPLOAD_MB`. Bila muncul halaman error hosting (bukan pesan aplikasi), batas ukuran request ditetapkan oleh hosting — kecilkan file dengan **Optimalkan otomatis** atau minta hosting menaikkan batas. |
| Tampilan web kosong / file JS tidak ditemukan (404) | Aplikasi dipasang di sub-folder URL. Pindahkan ke root domain/subdomain (Application URL tanpa path). |
| Perubahan environment variable tidak berpengaruh | Klik **RESTART** setelah menyimpan variabel. |
| `Run NPM Install` gagal | Pastikan versi Node.js ≥ 20 dan folder aplikasi tidak berisi `node_modules` hasil upload manual. Hapus `node_modules` (bila berupa folder biasa) lalu ulangi. |

---

## Catatan teknis

- **Startup file:** `app.js` menjalankan server hasil kompilasi di `dist/server/index.js`.
  Passenger mengatur port secara otomatis; variabel `PORT` hanya dipakai bila dijalankan manual.
- **Tanpa WebSocket:** komentar baru diperbarui dengan polling ±20 detik, cocok untuk shared hosting.
- **Tanpa dependensi native:** tidak ada paket yang perlu dikompilasi di server (bcryptjs, mysql2, Drizzle).
- **Waktu** disimpan dalam UTC di database dan ditampilkan sesuai zona waktu browser pengguna.
- **Kompatibilitas database:** MySQL 5.7+/8 atau MariaDB 10.3+.
