# Panduan Publish NEO ERP API ke IDCloudHost Elite Pro

Panduan ini mengikuti pola upload ZIP, Setup Python App, dan Passenger di
cPanel seperti panduan WEB_LAYANAN2. Perbedaannya: proyek ini menggunakan
FastAPI (ASGI), bukan Django (WSGI). Adapter Passenger menjalankan lifecycle
FastAPI sebelum menerima request agar session database tersedia.

## 1. Ringkasan arsitektur deploy

```text
Client desktop / mobile / web
  -> HTTPS api.domainanda.com
  -> Web server hosting + Passenger
  -> passenger_wsgi.py:application
  -> adapter WSGI ke ASGI + lifecycle FastAPI
  -> app.main:app
  -> MariaDB / MySQL NEO ERP di server database yang sudah ada
```

Tidak perlu Docker, VPS, Nginx manual, atau menjalankan Uvicorn di terminal.
Passenger mengelola proses aplikasi. Jalankan aplikasi di root subdomain,
bukan di subpath seperti `/neoerp`, agar URL API tetap sama.

Pastikan paket hosting Anda benar-benar menyediakan **Setup Python App**,
Python **3.11 atau lebih baru**, instalasi dependency melalui terminal/panel,
serta akses database. Nama paket saja tidak menjamin fitur tersebut tersedia.
Jika dependency `asyncmy` tidak dapat dipasang atau resource dibatasi hosting,
minta bantuan penyedia; jangan mengganti driver dengan driver sinkron.

## 2. Yang perlu disiapkan

1. Akses cPanel dan File Manager.
2. Subdomain API, misalnya `api.domainanda.com`, dengan HTTPS aktif.
3. Username akun cPanel, misalnya `username`.
4. Host, port, nama database, user, dan password untuk koneksi ke server
   database NEO ERP yang sudah digunakan.
5. Akun NEO ERP untuk uji login.

Deployment ini hanya mengunggah API; database tetap di server yang sudah ada.
Tidak perlu membuat database/user baru, mengunggah dump, import, atau migrasi.
Database tidak dibuat atau dimigrasikan otomatis oleh API. Jangan menjalankan
`manage.py migrate`, `collectstatic`, atau seed akun demo dari panduan Django.
API ini tidak memiliki perintah tersebut.

## 3. Membuat paket upload di Windows

Dari root proyek:

```powershell
.\scripts\build_cpanel_package.ps1
```

Hasilnya `deploy\neoerp-api-cpanel.zip`. Script menolak menimpa ZIP yang sudah
ada; pindahkan atau hapus file lama sebelum membuat paket baru.

Bisa menentukan nama lain:

```powershell
.\scripts\build_cpanel_package.ps1 -DestinationPath "D:\upload\neoerp-api-cpanel-v2.zip"
```

Folder tujuan harus sudah ada. ZIP hanya berisi kode aplikasi Python, file
startup, dependency manifest, template environment, dan panduan ini.
`.env` lokal, `.venv`, cache, test, backup database, dan credential lokal
tidak ikut dipaketkan. Template `.env.cpanel.example` bukan credential asli.

## 4. Menyiapkan domain dan folder aplikasi

Di cPanel:

1. Buka **Domains**, lalu buat `api.domainanda.com`.
2. Aktifkan SSL/AutoSSL untuk subdomain tersebut.
3. Gunakan folder aplikasi di luar `public_html`, misalnya
   `/home/username/neoerp_api`.
4. Document root publik dikelola oleh pemetaan Python App. Jangan menyalin
   `.env` atau source aplikasi ke folder publik hanya agar domain terbuka.

Struktur setelah ZIP diekstrak:

```text
/home/username/neoerp_api/
  passenger_wsgi.py
  pyproject.toml
  requirements.txt
  Readme.md
  app/
  deploy/
    passenger.py
    passenger_wsgi.py
    .env.cpanel.example
  docs/
    deploy-idcloudhost-elite-pro.md
```

File startup yang dipilih di panel adalah `passenger_wsgi.py` di **root**.
Folder `deploy` tetap diperlukan; jangan hanya upload file startup.

## 5. Membuat Python App di cPanel

Buka **Setup Python App** atau **Python App**, lalu **Create Application**:

| Field | Nilai contoh |
|---|---|
| Python version | `3.11` atau lebih baru yang tersedia |
| Application root | `neoerp_api` |
| Application URL | `api.domainanda.com`, tanpa tambahan subpath |
| Application startup file | `passenger_wsgi.py` |
| Application entry point | `application` |
| Application mode, jika tersedia | `Production` |

Klik **Create** dan catat perintah aktivasi virtualenv yang diberikan panel.
Jika panel membuat contoh file startup, gantikan dengan file dari paket ini
saat upload.

## 6. Upload dan extract

1. Buka File Manager, lalu folder `/home/username/neoerp_api`.
2. Upload `neoerp-api-cpanel.zip`.
3. Extract isi ZIP langsung ke folder aplikasi, bukan ke subfolder tambahan.
4. Pastikan `app`, `deploy`, dan `passenger_wsgi.py` berada sejajar.
5. Hapus ZIP dari hosting setelah extract selesai.

## 7. Install dependency

Aktifkan virtualenv dengan perintah dari panel. Contoh di terminal **hosting
Linux**, bukan PowerShell Windows:

```bash
source /home/username/virtualenv/neoerp_api/3.11/bin/activate
cd /home/username/neoerp_api
python -m pip install -r requirements.txt
python -m pip check
```

Sesuaikan username dan versi Python dengan panel. Jangan upload `.venv`
Windows ke hosting.

Alternatif jika memilih instalasi project dari `pyproject.toml`:

```bash
python -m pip install ".[hosting]"
```

Extra `hosting` memasang `a2wsgi` dan `asgi-lifespan`. Instalasi biasa tanpa
extra tetap cocok untuk Uvicorn/VPS, tetapi belum cukup untuk Passenger.

## 8. Menghubungkan database yang sudah ada

Database NEO ERP tetap berjalan di server lain seperti sebelumnya.
Tidak ada database atau dump SQL di dalam paket upload.

Isi konfigurasi koneksi API menggunakan nilai yang sudah digunakan:

1. `DB_HOST`: alamat IP atau hostname server database, bukan `localhost`
   hosting API.
2. `DB_PORT`: port database yang berlaku.
3. `DB_NAME`: nama database NEO ERP yang sudah ada.
4. `DB_USER` dan `DB_PASSWORD`: credential database yang diizinkan untuk API.

Tidak perlu menu **MySQL Databases** cPanel, import backup, membuat ulang
tabel/procedure, atau mengubah schema. Pertahankan konfigurasi server database
yang sudah berfungsi. Verifikasi `/health/ready` setelah API dipindahkan;
jika IP hosting baru belum diizinkan, izinkan hanya sumber koneksi API tersebut
sesuai kebijakan akses yang ada, bukan membuka port untuk semua IP.

## 9. Environment produksi

Salin template di terminal hosting:

```bash
cd /home/username/neoerp_api
cp deploy/.env.cpanel.example .env
chmod 600 .env
```

Edit `.env` melalui File Manager/terminal. Atau masukkan nilai yang sama pada
**Environment Variables** di Python App; nilai panel mengalahkan `.env`.
Jika mengisi JSON melalui panel, masukkan object JSON tanpa kutip pembungkus.

| Variabel | Pengaturan |
|---|---|
| `APP_ENV` | `production` |
| `APP_DEBUG` | `false` |
| `AUTH_ENABLED` | `true` |
| `TRUSTED_HOSTS` | `api.domainanda.com`, tanpa skema, path, atau wildcard |
| `JWT_SECRET_KEY` | Secret acak panjang, bukan nilai contoh/default |
| `AUTH_API_KEYS_JSON` | Object JSON berisi hash SHA-256 token dan principal |
| `DB_HOST`, `DB_PORT` | Host/port database yang sebenarnya |
| `DB_USER`, `DB_PASSWORD`, `DB_NAME` | Credential dan schema NEO ERP |
| `DB_POOL_SIZE`, `DB_MAX_OVERFLOW` | Awali `2` dan `1` untuk hosting terbatas |
| Ketiga flag `ENABLE_*_WRITE_API` | Tetap `false` pada deployment pertama |

Pool berlaku **per proses Passenger**. Sesuaikan batas koneksi database dan
jumlah proses hosting sebelum menaikkan pool.

Untuk membuat secret JWT, jalankan di terminal hosting:

```bash
python -c "import secrets; print(secrets.token_urlsafe(48))"
```

Simpan hasilnya sebagai `JWT_SECRET_KEY`, bukan di source code.

Runtime produksi saat ini juga membutuhkan `AUTH_API_KEYS_JSON` yang tidak
kosong, meskipun client menggunakan login JWT. Buat token API acak di password
manager. Hitung hash tanpa menuliskan token pada command line:

```bash
python -c "import getpass, hashlib; print(hashlib.sha256(getpass.getpass('Token API: ').encode('utf-8')).hexdigest())"
```

Isi JSON dengan hash hasil perintah tadi:

```text
AUTH_API_KEYS_JSON={"HASH_SHA256_64_KARAKTER":{"user_code":"OWNER","user_name":"API Owner","role":"OWNER"}}
```

Ganti placeholder dengan hash asli. Simpan token mentah di password manager;
jangan menyimpannya di repository, ZIP, screenshot publik, atau log.

## 10. Validasi dan restart

Setelah dependency dan environment terisi, cek startup dari terminal hosting:

```bash
cd /home/username/neoerp_api
python -c "from passenger_wsgi import application; print('Startup Passenger berhasil')"
```

Perintah ini memeriksa import, konfigurasi produksi, dan lifecycle FastAPI,
tetapi **belum membuktikan koneksi database**. Readiness check berikut yang
memeriksa database.

Kembali ke Python App, klik **Restart**. Restart lagi setiap ada perubahan
kode, dependency, atau environment. Tidak perlu `uvicorn --reload`.

## 11. Verifikasi hasil publish

| Pemeriksaan | Hasil yang diharapkan |
|---|---|
| `GET https://api.domainanda.com/health` | HTTP 200, `{"status":"ok"}` |
| `GET https://api.domainanda.com/health/ready` | HTTP 200, `{"status":"ready"}`; menjalankan `SELECT 1` |
| `GET https://api.domainanda.com/docs` | Swagger terbuka melalui HTTPS |
| `GET /api/order-penjualan` tanpa token | HTTP 401 |
| `POST /api/auth/login` dengan akun NEO ERP valid | Token JWT dan profil pengguna |
| `GET /api/auth/me` dengan token | Profil sesuai akun login |
| Endpoint read dengan token | Data dan pembatasan role sesuai akun |

Contoh body login:

```json
{
  "username": "KODE_AKUN_ANDA",
  "password": "PASSWORD_AKUN_ANDA",
  "app_type": "WEB"
}
```

Gunakan `Authorization: Bearer <access_token>` pada endpoint terlindungi.
Jangan membagikan token hasil login. Uji transaksi hanya pada database
nonproduksi. Aktifkan flag write setelah backup, InnoDB, stored procedure,
hak akses, integration test, dan rollback terverifikasi.

## 12. Update aplikasi

1. Buat paket ZIP baru dengan nama berbeda.
2. Backup kode versi sebelumnya dan database sesuai kebijakan operasional.
3. Upload/extract source baru tanpa menimpa `.env` produksi.
4. Jalankan ulang instalasi dependency pada virtualenv hosting.
5. Restart Python App.
6. Ulangi health, readiness, login, dan endpoint read.

Jika gagal, pulihkan source versi sebelumnya beserta dependency yang sesuai,
lalu restart. Jangan memulihkan database tanpa prosedur rollback yang jelas.

## 13. Troubleshooting

| Gejala | Pemeriksaan |
|---|---|
| `ModuleNotFoundError: a2wsgi/asgi_lifespan` | Install `requirements.txt` atau extra `hosting` di virtualenv dari panel |
| `ModuleNotFoundError: deploy/app` | Pastikan ZIP diekstrak langsung pada application root dan kedua folder ikut upload |
| HTTP 400 / Invalid host header | Sesuaikan `TRUSTED_HOSTS` dengan hostname akses, lalu restart |
| Error konfigurasi production saat startup | Periksa auth aktif, JSON hash token, debug false, dan environment panel |
| `/health` OK, `/health/ready` gagal | Periksa credential, hak akses, host/port, firewall, dan log database |
| HTTP 500/503 saat memakai endpoint transaksi | Periksa schema/procedure NEO ERP, InnoDB, flag write, dan log aplikasi |
| Login gagal | Periksa akun/password NEO ERP dan tabel autentikasi; bukan akun cPanel |
| Timeout/508 resource limit | Periksa limit proses/RAM/koneksi dari penyedia; kurangi pool atau gunakan VPS |
| Domain menampilkan index/file source | Periksa pemetaan Application URL dan document root; jangan mempublikasikan source atau `.env` |

Lihat error log/Passenger log yang disediakan panel. Error startup tidak
disembunyikan oleh adapter. Catat `X-Request-ID` untuk menelusuri error request,
tanpa menyertakan credential atau token dalam laporan.

Passenger WSGI cocok untuk endpoint HTTP REST saat ini. WebSocket dan
streaming jangka panjang tidak menjadi target pola deploy ini; untuk
kebutuhan tersebut gunakan ASGI native seperti panduan
[deployment VPS](deployment.md).
