gigafibre-fsm/quasar.config.js
louispaulb af42c6082e feat: auth gate, GPS hybrid tracking, tech CRUD modal, ERPNext API proxy
Authentication:
- Add App.vue login gate (v-if auth.loading / v-else-if !auth.user / router-view)
- Fix auth.checkSession with try/finally to always reset loading
- Fix generate_keys method name for Frappe v16 (generate_keys, not generate_keys_for_api_user)
- Auto-generate API token on cookie-based auth (Authentik SSO support)
- Remove duplicate checkSession from DispatchV2Page (was causing infinite mount/unmount loop)

GPS Tracking — Hybrid REST + WebSocket:
- Initial REST fetch per-device in parallel (Traccar API only supports one deviceId per request)
- WebSocket real-time updates via wss://dispatch.gigafibre.ca/traccar/api/socket
- Auto-fallback to 30s polling if WebSocket fails, with exponential backoff reconnect
- Module-level guards (__gpsStarted, __gpsPolling) to prevent loops on component remount
- Only update tech.gpsCoords when value actually changes (prevents unnecessary reactive triggers)

Tech Management (GPS Modal):
- Add/delete technicians directly from GPS modal → persists to ERPNext
- Inline edit: double-click name to rename, phone field, status select
- Auto-generate technician_id (TECH-N+1)
- Unlink jobs before delete to avoid ERPNext LinkExistsError
- Added phone/email custom fields to Dispatch Technician doctype

Infrastructure:
- Nginx proxy: /api/ → ERPNext (same-origin, eliminates all CORS issues)
- Nginx proxy: /traccar/ WebSocket support (Upgrade headers, 86400s timeout)
- No-cache headers on index.html and sw.js for instant PWA updates
- BASE_URL switched to empty string in production (same-origin via proxy)

Bug fixes:
- ERPNext Number Card PostgreSQL fix (ORDER BY on aggregate queries)
- Traccar fetchPositions: parallel per-device calls (API ignores multiple deviceId params)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 12:02:04 -04:00

76 lines
2.0 KiB
JavaScript

/* eslint-env node */
const { configure } = require('quasar/wrappers')
module.exports = configure(function (ctx) {
return {
boot: ['pinia'],
css: ['app.scss'],
extras: ['roboto-font', 'material-icons'],
build: {
target: {
browser: ['es2019', 'edge88', 'firefox78', 'chrome87', 'safari13.1'],
node: 'node20',
},
vueRouterMode: 'hash',
// Base path = where the app is deployed under ERPNext
// Change this if you move the app to a different path
extendViteConf (viteConf) {
viteConf.base = process.env.DEPLOY_BASE || '/assets/dispatch-app/'
},
},
devServer: {
open: false,
// Listen on all interfaces so the container port is reachable from the host
host: '0.0.0.0',
port: 9000,
proxy: {
// Proxy ERPNext API calls to the frontend container
// host.docker.internal resolves to the Docker host on Mac / Windows
'/api': {
target: 'http://host.docker.internal:8080',
changeOrigin: true,
cookieDomainRewrite: 'localhost',
},
'/assets': {
target: 'http://host.docker.internal:8080',
changeOrigin: true,
},
},
},
framework: {
config: {},
// Only load what we actually use — add more as needed
plugins: ['Notify', 'Loading', 'LocalStorage'],
},
animations: [],
pwa: {
workboxMode: 'generateSW',
injectPwaMetaTags: true,
swFilename: 'sw.js',
manifestFilename: 'manifest.json',
useCredentialForManifestTag: false,
workboxOptions: {
skipWaiting: true,
clientsClaim: true,
},
extendManifestJson (json) {
json.name = 'Dispatch'
json.short_name = 'Dispatch'
json.description = 'Dispatch & Field Service'
json.display = 'standalone'
json.orientation = 'portrait'
json.background_color = '#ffffff'
json.theme_color = '#6366f1'
json.start_url = '.'
},
},
}
})