diff --git a/client/src/App.tsx b/client/src/App.tsx index 47c2f8d..8d2c96b 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -69,9 +69,32 @@ export default function App() { if (token) { loadUser() } - authApi.getAppConfig().then((config: { demo_mode?: boolean; has_maps_key?: boolean }) => { + authApi.getAppConfig().then(async (config: { demo_mode?: boolean; has_maps_key?: boolean; version?: string }) => { if (config?.demo_mode) setDemoMode(true) if (config?.has_maps_key !== undefined) setHasMapsKey(config.has_maps_key) + + // Version-based cache invalidation: clear all caches on version change + if (config?.version) { + const storedVersion = localStorage.getItem('trek_app_version') + if (storedVersion && storedVersion !== config.version) { + try { + // Clear all Service Worker caches + if ('caches' in window) { + const names = await caches.keys() + await Promise.all(names.map(n => caches.delete(n))) + } + // Unregister all service workers + if ('serviceWorker' in navigator) { + const regs = await navigator.serviceWorker.getRegistrations() + await Promise.all(regs.map(r => r.unregister())) + } + } catch {} + localStorage.setItem('trek_app_version', config.version) + window.location.reload() + return + } + localStorage.setItem('trek_app_version', config.version) + } }).catch(() => {}) }, []) diff --git a/server/src/index.ts b/server/src/index.ts index c53977f..770f0c9 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -163,8 +163,16 @@ app.use('/api/backup', backupRoutes); // Serve static files in production if (process.env.NODE_ENV === 'production') { const publicPath = path.join(__dirname, '../public'); - app.use(express.static(publicPath)); + app.use(express.static(publicPath, { + setHeaders: (res, filePath) => { + // Never cache index.html so version updates are picked up immediately + if (filePath.endsWith('index.html')) { + res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate'); + } + }, + })); app.get('*', (req: Request, res: Response) => { + res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate'); res.sendFile(path.join(publicPath, 'index.html')); }); }