Lewati ke isi

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_URL dicomment
  • [ ] GitHub workflow: tidak set VITE_API_URL
  • [ ] Build: verify baseURL:"/api" di output
  • [ ] Build menghasilkan dist/version.json
  • [ ] Nginx/cache: index.html dan version.json harus no-cache; /assets/* boleh immutable karena memakai hash
  • [ ] Nginx dev.gcgscola.id: proxy /api/ dan /web aktif
  • [ ] 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