# Error `GET .../_nuxt/... net::ERR_ABORTED 500`

## Error halaman SSR: `Cannot find module '.../team-XXXX.mjs'`

Gejala: buka `/team` (atau route lain) → **500** dengan teks mirip:

`Cannot find module '.../FE/.output/server/chunks/build/team-XXXX.mjs' imported from .../server.mjs`

**Artinya:** file `server.mjs` hasil build **mengacu** ke chunk `team-XXXX.mjs`, tetapi file itu **tidak ada** di folder yang sama. Bukan bug Vue per baris; ini **artefak build / deploy tidak utuh**:

- build terputus, `rm -rf .output` sebagian, atau **rsync/scp** yang tidak menyalin seluruh `.output/server/chunks/build/`;
- dua kali `npm run build` bersamaan ke direktori yang sama;
- salin `.output` dari mesin lain tanpa set folder.

**Perbaikan di server:**

```bash
cd /var/www/html/wp-system/FE
rm -rf .nuxt .output
npm ci
npm run build
npm run verify:output
HOME=/root PM2_HOME=/root/.pm2 pm2 restart workpulse-fe
```

Sebelum `exec node`, PM2 memanggil **`scripts/verify-nitro-server-chunks.sh`** lewat **`workpulse-fe-pm2-entry.sh`**. Jika chunk tidak lengkap, proses **sengaja tidak start** (log PM2 menjelaskan) agar tidak melayani 500 diam-diam.

---

## Artinya apa?

Browser memuat halaman login, lalu meminta **file JavaScript/CSS hasil build Nuxt** di path `/_nuxt/...`. **500** atau **ERR_ABORTED** di situ artinya **file bundle itu tidak berhasil dikirim** dari server ke browser.

- **Bukan** error login (email/password) dan **bukan** API Gin/PostgreSQL.
- **Tanpa** file `/_nuxt/*` yang sukses (**200**), Vue/Nuxt di browser **tidak jalan** → tombol Sign In, validasi form, dan navigasi SPA tidak bisa diandalkan.

---

## Penyebab paling sering: **proses Node lama masih listen port 3020**

Sering terjadi setelah `npm run build` + `pm2 restart`:

1. **HTML** sudah dari build **baru** (nama file `/_nuxt/xxxxx.js` baru).
2. Yang listen di **127.0.0.1:3020** masih proses **lama** (build lama) — atau PM2 gagal bind (`EADDRINUSE`) sementara proses yatim tetap pegang port.
3. Nitro lama **tidak punya entri** untuk hash file baru di manifest-nya → respons JSON **404** / **500** untuk URL yang sebenarnya ada di folder `.output/public/_nuxt/` di disk.

### Mitigasi otomatis di repo (PM2 + entry script)

Agar deploy tidak sering meninggalkan proses yatim di port, **`ecosystem.config.cjs`** memanggil **`scripts/workpulse-fe-pm2-entry.sh`** (interpreter **bash**): sebelum Nitro jalan, port **NITRO_PORT / PORT** (default **3020**) dibersihkan (`fuser -k …/tcp`, atau fallback `ss` + `kill`), lalu **verifikasi chunk** (`verify-nitro-server-chunks.sh`), lalu `exec node .output/server/index.mjs`.

**Setelah `git pull` di server deploy:** pastikan skrip **Unix LF** (bukan CRLF Windows — jika `bash -n` error di `$'{\r'`, jalankan `sed -i 's/\r$//' scripts/workpulse-fe-pm2-entry.sh`), lalu:

```bash
chmod +x /var/www/html/wp-system/FE/scripts/workpulse-fe-pm2-entry.sh
cd /var/www/html/wp-system/FE && npm run build:clean && npm run verify:output
HOME=/root PM2_HOME=/root/.pm2 pm2 delete workpulse-fe 2>/dev/null || true
HOME=/root PM2_HOME=/root/.pm2 pm2 start ecosystem.config.cjs && pm2 save
```

Satu kali **`delete` + `start`** membantu PM2 mengambil `script` / `interpreter` baru; `restart` saja kadang tidak mengganti definisi app.

**Cek cepat:**

```bash
ss -tlnp | grep 3020
HOME=/root PM2_HOME=/root/.pm2 pm2 describe workpulse-fe | grep pid
```

PID di `ss` harus **sama** dengan PID proses `workpulse-fe` di PM2. Jika beda, hentikan proses orphan (`kill <pid_dari_ss>`), lalu `pm2 restart workpulse-fe`.

Jika setelah itu PID **masih** beda (ada proses `node .../FE/.output/server/index.mjs` yang di-start dari luar PM2 — `ppid` berbeda), kosongkan port lalu start ulang:

```bash
sudo fuser -k 3020/tcp
sleep 1
cd /var/www/html/wp-system/FE && HOME=/root PM2_HOME=/root/.pm2 pm2 restart workpulse-fe
```

**Uji chunk (ganti nama file dengan satu baris dari View Source halaman login):**

```bash
curl -sSI "http://127.0.0.1:3020/_nuxt/NAMA_FILE.js" | head -3
# Harus: HTTP/1.1 200 OK
```

**Uji manifest build Nuxt** (nama file UUID ikut berubah tiap `npm run build`):

```bash
ls .output/public/_nuxt/builds/meta/
curl -sSI "http://127.0.0.1:3020/_nuxt/builds/meta/ISI_UUID_DARI_LS.json" | head -3
# Harus: HTTP/1.1 200 OK
```

### Error `[nuxt] Error fetching app manifest` → `/_nuxt/builds/meta/<uuid>.json` 500

- **UUID di URL** harus **sama** dengan file yang ada di `.output/public/_nuxt/builds/meta/` setelah build terakhir. Kalau browser masih memuat **HTML lama** (tab tertinggal, cache), HTML itu mengacu ke **UUID lama** → server balas **404** (Nuxt kadang menampilkan sebagai **500** di konsol).
- **Perbaikan di browser:** hard refresh / **Clear site data** untuk domain `work.rycroftapparel.com`, lalu buka ulang `/login`.
- **Perbaikan di server:** pastikan tidak ada **proses orphan** di port 3020 (lihat atas); manifest untuk UUID **saat ini** harus **200** lewat `curl` di atas.

---

## Penyebab umum di server

### 1. Port **3020** dipakai lebih dari satu proses (`EADDRINUSE`)

Gejala di log PM2 / error Node: `listen EADDRINUSE: address already in use 127.0.0.1:3020`.

**Perbaikan:**

```bash
# Lihat siapa yang listen 3020
ss -tlnp | grep 3020

# Pastikan hanya SATU app Nitro WorkPulse (PM2)
HOME=/root PM2_HOME=/root/.pm2 pm2 list
# Jika ada duplikat / proses yatim, hapus yang salah lalu:
HOME=/root PM2_HOME=/root/.pm2 pm2 delete workpulse-fe
cd /var/www/html/wp-system/FE && HOME=/root PM2_HOME=/root/.pm2 pm2 start ecosystem.config.cjs
HOME=/root PM2_HOME=/root/.pm2 pm2 save
```

Jangan menjalankan **dua kali** `pm2 start` untuk FE yang sama tanpa `delete` dulu.

### 2. Build tidak ada / tidak lengkap

Setelah `git pull` atau ubah kode:

```bash
cd /var/www/html/wp-system/FE
npm run build:clean
npm run verify:output
# Pastikan folder ada:
ls .output/public/_nuxt | head
```

Lalu restart PM2 seperti di atas.

### 3. HTML / cache browser memuat **hash file lama**

Setelah deploy baru, nama file `/_nuxt/*.js` berubah. Cache lama bisa meminta file yang sudah tidak ada → error di jaringan (kadang tampil sebagai gagal muat).

**Perbaikan:** hard refresh (Ctrl+F5), atau **Clear site data** untuk `work.rycroftapparel.com`.

### 4. Cek log saat error

```bash
HOME=/root PM2_HOME=/root/.pm2 pm2 logs workpulse-fe --lines 80 --nostream
sudo tail -n 80 /var/log/apache2/work.rycroftapparel.com_ssl_error.log
```

Uji langsung ke Nitro (dari server):

```bash
curl -sS -o /dev/null -w "%{http_code}\n" http://127.0.0.1:3020/_nuxt/CHmRg-9z.js
# Ganti nama file dengan salah satu yang ada di .output/public/_nuxt/ — harus 200
```

---

## Ringkas

| Gejala | Bukan ini | Ini |
|--------|-----------|-----|
| 500 pada `/_nuxt/...` | BE PostgreSQL / JWT | Nitro, port 3020, build, proxy Apache |

Apache untuk `work` harus mem-proxy ke **satu** listener `http://127.0.0.1:3020/` (lihat `deploy/apache/work.rycroftapparel.com-ssl.conf`).
