# WorkPulse — Infrastruktur `apiwork.rycroftapparel.com` (TLS, Apache, FE)

Dokumen ini menjawab error browser **`net::ERR_CERT_COMMON_NAME_INVALID`** pada `https://apiwork.rycroftapparel.com` dan kegagalan **`wss://`** — serta membedakan **data dummy di FE** vs **kesalahan sertifikat / vhost**.

---

## 1. Apa arti `ERR_CERT_COMMON_NAME_INVALID`?

Browser memverifikasi bahwa **nama host** yang Anda buka (`apiwork.rycroftapparel.com`) tercantum di sertifikat TLS (CN atau **Subject Alternative Name**).

Pengecekan di server (contoh):

```bash
echo | openssl s_client -connect apiwork.rycroftapparel.com:443 -servername apiwork.rycroftapparel.com 2>/dev/null \
  | openssl x509 -noout -subject -ext subjectAltName
```

Jika yang keluar misalnya **`CN = admin.rycroft.id`** dan SAN **tidak** memuat `apiwork.rycroftapparel.com`, maka **Apache (atau default SSL vhost)** sedang menyajikan **sertifikat domain lain** untuk permintaan ke host tersebut.

**Ini bukan bug kode Gin / Nuxt secara logika bisnis**, melainkan **konfigurasi TLS + virtual host** yang belum benar untuk subdomain API.

Dampak:

- Semua **`fetch` / `$fetch` / WebSocket** ke host itu **gagal** di browser (terblokir sebelum sampai ke handler Gin).

---

## 2. Perbaikan yang harus dilakukan di server (checklist)

1. **DNS**  
   Pastikan `apiwork.rycroftapparel.com` mengarah ke IP server yang sama dengan layanan lain (record **A** / **AAAA**).

2. **Apache — vhost terpisah**  
   - `ServerName apiwork.rycroftapparel.com`  
   - `ProxyPass` / `ProxyPassReverse` ke proses Gin (mis. `127.0.0.1:<PORT>`).  
   - **Jangan** mengubah vhost domain lain; hanya **tambah** file baru di `sites-available` + `a2ensite`.

3. **HTTP untuk ACME**  
   Port **:80** untuk host ini: izinkan `/.well-known/acme-challenge/` lalu redirect sisanya ke HTTPS (sama pola seperti `work.rycroftapparel.com`).

4. **Let’s Encrypt khusus host ini**  

   ```bash
   sudo certbot certonly --webroot -w /var/www/html/wp-system/BE/deploy/acme-challenge \
     -d apiwork.rycroftapparel.com --non-interactive --agree-tos -m info@rycroftapparel.com
   ```

5. **Vhost SSL**  
   Gunakan **hanya** file di bawah ini (contoh):

   - `SSLCertificateFile /etc/letsencrypt/live/apiwork.rycroftapparel.com/fullchain.pem`  
   - `SSLCertificateKeyFile /etc/letsencrypt/live/apiwork.rycroftapparel.com/privkey.pem`  
   - `Include /etc/letsencrypt/options-ssl-apache.conf`

6. **WebSocket di Apache**  
   Pastikan modul **`proxy_wstunnel`** aktif dan ada aturan **Upgrade** ke `ws://127.0.0.1:<PORT>/...` **sama path** dengan yang dipakai Gin (mis. `/api/v1/ws` — harus **satu kesepakatan** FE, BE, Apache).

7. **Verifikasi**  

   ```bash
   curl -sI https://apiwork.rycroftapparel.com/healthz
   echo | openssl s_client -connect apiwork.rycroftapparel.com:443 -servername apiwork.rycroftapparel.com 2>/dev/null | openssl x509 -noout -subject -ext subjectAltName
   ```

   Harus terlihat **SAN: DNS:apiwork.rycroftapparel.com** (atau wildcard yang mencakup subdomain itu).

---

## 3. Perilaku FE saat ini (bukan “API 100%”)

- **Dashboard / chart / angka** di banyak halaman masih **data statis / placeholder** di komponen Vue (belum di-bind ke `GET /api/v1/...`). Itu **bukan** hasil dari BE sampai tim menghubungkan halaman ke endpoint nyata.
- **`POST /api/v1/auth/logout`** dan **WebSocket** dari FE **hanya dijalankan** jika `NUXT_PUBLIC_WORKPULSE_API_BASE` diset (lihat `nuxt.config` + PM2).  
  Default **base URL kosong** = **tidak** memanggil host API (supaya konsol bersih **sampai TLS benar**).
- Setelah TLS & CORS siap, set di PM2 misalnya:

  ```bash
  NUXT_PUBLIC_WORKPULSE_API_BASE=https://apiwork.rycroftapparel.com
  NUXT_PUBLIC_WORKPULSE_WS_PATH=/api/v1/ws
  ```

  lalu `npm run build` + `pm2 restart workpulse-fe`.

---

## 4. BE (Gin) — yang perlu selaras setelah TLS jalan

- **CORS**: izinkan origin `https://work.rycroftapparel.com` (dan dev), header `Authorization`, method `POST`, `GET`, dll.; jika pakai cookie, `Access-Control-Allow-Credentials: true`.
- **Path logout**: `POST /api/v1/auth/logout` (sudah dijelaskan di `BE_WORKPULSE_LOGOUT_SESSION.md`).
- **WebSocket**: path & auth (ticket / token) sama dengan yang di-proxy Apache.

---

## 5. Hydration mismatch (konsol Nuxt)

Auth UI memakai **cookie** `workpulse-auth` agar nilai login konsisten antara SSR dan klien (mengurangi peringatan hydration vs `localStorage` murni). Satu kali migrasi dari `localStorage` ke cookie di plugin klien.

---

## 6. Ringkas: salah FE atau BE?

| Gejala | Penyebab |
|--------|----------|
| `ERR_CERT_COMMON_NAME_INVALID` | **Infrastruktur TLS / vhost** untuk `apiwork.*`, bukan logika FE/BE. |
| `WebSocket failed` ke host yang sama | Umumnya **akibat TLS** atau path/proxy WS. |
| Angka di dashboard “tetap contoh” | **FE masih dummy** sampai dihubungkan ke API. |

---

*File: `docs/BE_INFRA_APIWORK_TLS.md`*
