| # Deploy Guide — Render.com |
|
|
| Step-by-step deploy TKI-KOS ke Render.com (free tier). |
|
|
| ## Prerequisites |
|
|
| - [x] Repo public di GitHub: https://github.com/DYmazeh/TKI-KOS |
| - [x] Render account (sign up free di https://render.com) |
| - [x] Connect GitHub account ke Render (Account Settings -> Connect GitHub) |
| - [x] Scraping done -> data ready: `data/processed/corpus.json` exists |
| - [x] Indexes done: `data/indexes/{tfidf.pkl, bm25.pkl, indobert/}` |
|
|
| ## Critical Question — How to Get Indexes ke Render? |
|
|
| Indexes (TF-IDF pickle, BM25 pickle, IndoBERT embeddings + FAISS) BUTUH ada |
| di Render file system supaya backend bisa load saat startup. Tiga opsi: |
|
|
| | Opsi | Pros | Cons | |
| |------|------|------| |
| | **A: Commit indexes ke git** | Simplest, auto-deploy via render.yaml | Repo bloat (~30-50MB), GitHub warning di 50MB | |
| | **B: Build saat deploy** | Repo clean | Build time lama (~5 min IndoBERT encode), bisa exceed Render free tier 15-min build timeout | |
| | **C: External storage (HF Datasets / R2 / GDrive)** | Repo clean, fleksibel | Setup complex, butuh download step di lifespan | |
|
|
| **Rekomendasi untuk student project: Opsi A**, asal total `data/indexes/` < |
| 50MB. Untuk corpus 3000 listing dengan MiniLM, total biasanya 20-30MB. |
|
|
| ### Step untuk Opsi A: |
|
|
| 1. Temporary remove `data/indexes/*.pkl` etc dari `.gitignore`: |
| ```diff |
| -data/indexes/*.pkl |
| -data/indexes/*.index |
| -data/indexes/*.bin |
| -data/indexes/*.faiss |
| -data/indexes/*.npy |
| ``` |
|
|
| 2. Commit indexes: |
| ```bash |
| git add data/indexes data/processed/corpus.json |
| git commit -m "data: add prebuilt indexes for deploy" |
| git push |
| ``` |
|
|
| 3. NOTE: kalau kamu rebuild indexes (e.g., tune hyperparameter), harus commit |
| ulang. Auto-deploy via render.yaml pickup yang ada di git. |
|
|
| ## Step 1: Deploy via Blueprint (recommended) |
|
|
| `render.yaml` di root repo sudah ada — Render baca dan auto-create 3 services. |
|
|
| 1. Login ke Render Dashboard |
| 2. **New +** -> **Blueprint** |
| 3. Connect repo `DYmazeh/TKI-KOS` |
| 4. Render parse `render.yaml`, show preview 3 services: |
| - `tki-kos-pg` (PostgreSQL) |
| - `tki-kos-backend` (Web Service) |
| - `tki-kos-frontend` (Static Site) |
| 5. Click **Apply** |
|
|
| Render mulai provisioning. Order: |
| 1. PG database (~30 detik) |
| 2. Backend deploy (~5-10 menit — pip install heavy deps termasuk torch/sentence-transformers) |
| 3. Frontend deploy (~2-3 menit — npm install + vite build) |
|
|
| ## Step 2: Update CORS + API URL (post-deploy) |
|
|
| Setelah deploy selesai, Render kasih URL aktual seperti: |
| - Backend: `https://tki-kos-backend-xxxx.onrender.com` |
| - Frontend: `https://tki-kos-frontend-xxxx.onrender.com` |
|
|
| Update env vars di kedua service supaya saling kenal: |
|
|
| ### Backend env: `CORS_ORIGINS` |
| 1. Render Dashboard -> Backend service -> Environment tab |
| 2. Edit `CORS_ORIGINS`: |
| ```json |
| ["https://tki-kos-frontend-xxxx.onrender.com"] |
| ``` |
| 3. Save -> service auto-redeploy |
|
|
| ### Frontend env: `VITE_API_URL` |
| 1. Render Dashboard -> Frontend service -> Environment tab |
| 2. Edit `VITE_API_URL`: |
| ``` |
| https://tki-kos-backend-xxxx.onrender.com |
| ``` |
| 3. Save -> trigger manual redeploy (env var change perlu rebuild) |
|
|
| ## Step 3: Run Migrations (DB Schema) |
|
|
| Render PG empty by default. Buka **Shell** di backend service: |
|
|
| ```bash |
| cd /opt/render/project/src/backend |
| alembic upgrade head |
| ``` |
|
|
| Output expected: |
| ``` |
| INFO [alembic.runtime.migration] Running upgrade -> 001, initial schema |
| ``` |
|
|
| ## Step 4: Seed Database |
|
|
| Upload `data/raw/mamikos.jsonl` ke backend service (via Render Shell or curl |
| endpoint kalau ada upload route). Atau, kalau JSONL sudah di-commit: |
|
|
| ```bash |
| cd /opt/render/project/src/backend |
| python -m scripts.seed_db --input ../data/raw/mamikos.jsonl |
| ``` |
|
|
| Output expected: |
| ``` |
| [load] 1542 listings raw |
| [filter] 1487/1542 listings pass quality bar |
| [insert] 1487 listings upserted |
| ``` |
|
|
| ## Step 5: Verify Deploy |
|
|
| 1. Hit health check: |
| ```bash |
| curl https://tki-kos-backend-xxxx.onrender.com/health |
| # -> {"status":"ok","service":"tki-kos-backend"} |
| ``` |
|
|
| 2. Hit Swagger UI: |
| - Browser: `https://tki-kos-backend-xxxx.onrender.com/docs` |
| - Test `/search?q=kos putra dekat unila&model=bm25` |
|
|
| 3. Frontend: |
| - Browser: `https://tki-kos-frontend-xxxx.onrender.com` |
| - Should load TKI-KOS search UI |
| - Try search "kos putra dekat unila" |
| - Verify result cards muncul |
|
|
| ## Cold Start Mitigation |
|
|
| Free tier backend spin down setelah 15 menit idle. Cold start ~30s + index |
| load ~30-60s = total 60-90s. **Bad untuk demo presentasi.** |
|
|
| ### Option A: Keep service warm dengan UptimeRobot |
|
|
| 1. Sign up free di https://uptimerobot.com |
| 2. Add new monitor: HTTP(s), URL = `https://tki-kos-backend.onrender.com/health`, interval = 5 menit |
| 3. Free tier UptimeRobot = 50 monitors, 5-min interval -> total 12 ping/hour cukup |
|
|
| **Cost:** UptimeRobot ping count towards Render free tier 750 hours/month |
| (720 hours = sebulan penuh). Aman tapi sempit. Kalau idle 14 jam/hari, total |
| ~310 hours/month idle saved. |
|
|
| ### Option B: Pre-warm sebelum demo |
|
|
| 15 menit sebelum presentasi, akses backend URL di browser. Service spin up, |
| warm sampai ~30 menit setelah last request. |
|
|
| ### Option C: Switch ke Render Starter plan ($7/month) |
|
|
| Always-on, no spin down. Worth it kalau project akan demo berulang kali. |
|
|
| ## Troubleshooting |
|
|
| ### Backend deploy fail: "out of memory" saat pip install |
|
|
| Render free tier hanya 512MB RAM. `sentence-transformers` + `faiss-cpu` + |
| `torch` (dependency) total ~600MB di build cache. |
|
|
| **Fix:** swap `requirements.txt` untuk separate `requirements-prod.txt` |
| tanpa heavy deps yang gak digunakan, atau upgrade ke paid plan. |
|
|
| ### Backend startup timeout |
|
|
| Kalau index loading >5 menit, Render anggap unhealthy dan restart. |
|
|
| **Fix:** |
| - Pakai MiniLM (118MB) instead of IndoBERT-base (440MB) |
| - Precompute FAISS index, commit ke git supaya tinggal load dari disk |
| - Tambah `app.state.tfidf_loaded` flag dan return 503 dari `/search` sampai ready |
|
|
| ### Frontend can't reach backend (CORS error di browser console) |
|
|
| **Fix:** verify `CORS_ORIGINS` di backend env match frontend URL exactly |
| (include `https://`, no trailing slash). Restart backend. |
|
|
| ### Postgres free tier expired (after 90 days) |
|
|
| Render kasih warning 7 hari sebelum expire. Backup data: |
| ```bash |
| pg_dump $DATABASE_URL > backup.sql |
| ``` |
|
|
| Create new free PG instance, restore: |
| ```bash |
| psql $NEW_DATABASE_URL < backup.sql |
| ``` |
|
|
| Atau upgrade ke paid plan ($7/month basic) — recommended untuk after course |
| selesai kalau project mau di-keep up. |
|
|
| ## Monitoring Post-Deploy |
|
|
| Render Dashboard kasih: |
| - **Logs**: real-time stream service logs (stdout/stderr) |
| - **Metrics**: CPU/RAM/Network usage (free tier limited) |
| - **Events**: deploy history, restarts, crashes |
|
|
| Tambah lagi: |
| - **UptimeRobot**: external uptime monitor |
| - **Sentry** (free tier): error tracking (kalau ada budget waktu di Week 4) |
|
|
| ## Manual Re-Deploy |
|
|
| Setelah commit baru ke main, Render auto-deploy. Untuk **manual trigger**: |
| - Dashboard -> Service -> **Manual Deploy** -> **Deploy latest commit** |
|
|
| Useful kalau auto-deploy gagal dan kamu udah fix issue di repo. |
|
|
| ## Summary Checklist |
|
|
| - [ ] PostgreSQL provisioned, connection string captured |
| - [ ] Backend deployed, `/health` returns 200 |
| - [ ] Frontend deployed, accessible via public URL |
| - [ ] CORS_ORIGINS updated dengan frontend URL |
| - [ ] VITE_API_URL updated dengan backend URL |
| - [ ] Migrations run via Shell (`alembic upgrade head`) |
| - [ ] DB seeded (`python -m scripts.seed_db --input ...`) |
| - [ ] Indexes available (committed ke git atau download script) |
| - [ ] Search end-to-end works dari frontend |
| - [ ] UptimeRobot configured (kalau perlu warm) |
| - [ ] Screenshot UI live untuk laporan / slide |
| - [ ] URL ditulis di root README |
|
|