Scola Frontend API Architecture¶
Catatan: Mulai dari scola-fe-v2/docs/AI Guidelines/AGENTIC_AI_APP_DEV_GUIDE.md untuk panduan agentic AI end-to-end.
Arsitektur: Same-Origin Proxy¶
Frontend menggunakan same-origin proxy untuk menghindari masalah CORS.
┌─────────────────────────────────────────────────────────────┐
│ dev.gcgscola.id │
├─────────────────────────────────────────────────────────────┤
│ / → serve /var/www/dev-scola/dist (frontend) │
│ /api/* → proxy to localhost:8074 (Odoo) │
│ /web/* → proxy to localhost:8074 (Odoo) │
└─────────────────────────────────────────────────────────────┘
Mengapa Same-Origin?¶
Problem dengan Cross-Origin:
- Frontend di dev.gcgscola.id memanggil be-dev.gcgscola.id → butuh CORS
- withCredentials: true (untuk session cookies) + cors='*' = TIDAK KOMPATIBEL
- Browser menolak response jika Access-Control-Allow-Origin: * dengan credentials
Solusi Same-Origin:
- Semua API calls melalui dev.gcgscola.id/api/
- Nginx proxy ke Odoo backend
- Tidak ada cross-origin request → tidak perlu CORS
Konfigurasi Penting¶
1. .env.production - JANGAN DIUBAH!¶
# Backend URL untuk API calls (tanpa trailing slash)
# Same-origin proxy: leave empty so all calls go through dev.gcgscola.id/api/
# VITE_API_URL="https://be-dev.gcgscola.id" # <-- HARUS DICOMMENT!
PENTING: VITE_API_URL harus dikosongkan/dicomment agar frontend pakai relative URL /api.
2. src/api/apiServices.js¶
const apiClient = axios.create({
baseURL: import.meta.env.VITE_API_URL
? `${import.meta.env.VITE_API_URL}/api`
: "/api", // <-- Jika VITE_API_URL kosong, pakai /api (same-origin)
withCredentials: true,
// ...
});
3. Nginx dev.gcgscola.id¶
server {
server_name dev.gcgscola.id;
root /var/www/dev-scola/dist;
index index.html;
# SPA Routing
location / {
try_files $uri $uri/ /index.html;
}
# API Proxy - PENTING!
location /api/ {
proxy_pass http://127.0.0.1:8074;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# Web Proxy for Odoo standard endpoints
location /web {
proxy_pass http://127.0.0.1:8074;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
4. GitHub Actions Workflow¶
- name: 🔧 Build project
run: npm run build
env:
# VITE_API_URL intentionally not set - use same-origin proxy
NODE_OPTIONS: "--max-old-space-size=4096"
JANGAN set VITE_API_URL di workflow atau GitHub secrets.
Troubleshooting¶
Error: CORS policy blocked¶
Gejala:
Access to XMLHttpRequest at 'https://be-dev.gcgscola.id/api/...'
has been blocked by CORS policy
Penyebab: Frontend memanggil cross-origin (be-dev.gcgscola.id)
Solusi:
1. Pastikan .env.production tidak punya VITE_API_URL aktif
2. Rebuild dengan VITE_API_URL="" npm run build
3. Verify build: grep 'baseURL' dist/assets/index-*.js → harus /api
Error: 502 Bad Gateway¶
Penyebab: Odoo tidak running
Solusi:
# Check Odoo
ps aux | grep odoo-bin
# Start Odoo
/home/scola/odoo/odoo-bin -c /home/scola/odoo/odoo-devscola.conf &
Error: Double slash //api¶
Gejala: URL seperti https://be-dev.gcgscola.id//api/...
Penyebab: VITE_API_URL punya trailing slash
Solusi: Hapus trailing slash atau comment out VITE_API_URL
Checklist Deployment¶
- [ ]
.env.production:VITE_API_URLdicomment - [ ] GitHub workflow: tidak set
VITE_API_URL - [ ] Build: verify
baseURL:"/api"di output - [ ] Build menghasilkan
dist/version.json - [ ] Nginx/cache:
index.htmldanversion.jsonharusno-cache;/assets/*boleh immutable karena memakai hash - [ ] Nginx dev.gcgscola.id: proxy
/api/dan/webaktif - [ ] Odoo running di port 8074
Handling Frontend Updates During Active Sessions¶
Jika frontend dideploy saat user masih membuka tab lama, bundle JS lama bisa tidak cocok dengan chunk baru di server. Gejalanya biasanya menu/submenu tidak bereaksi, lazy route gagal dimuat, atau browser baru pulih setelah hard refresh.
Kontrak frontend:
- vite.config.js menulis dist/version.json setiap build.
- Runtime menyimpan versi build aktif melalui import.meta.env.VITE_APP_VERSION.
- src/composables/useAppVersionCheck.js mengecek /version.json berkala dan saat tab kembali aktif.
- Jika versi server berbeda, atau ada error dynamic import/chunk load, AppUpdatePrompt menampilkan pesan "Pembaruan aplikasi tersedia" dan tombol "Muat ulang".
Kontrak cache server:
- version.json: Cache-Control: no-cache, no-store, must-revalidate
- index.html: Cache-Control: no-cache
- /assets/*.js dan /assets/*.css: boleh Cache-Control: public, max-age=31536000, immutable
Terakhir diupdate: 2026-01-20 Issue yang diselesaikan: Login gagal karena CORS