diff --git a/backend/src/server.ts b/backend/src/server.ts index 46d8b75..853fed3 100644 --- a/backend/src/server.ts +++ b/backend/src/server.ts @@ -93,7 +93,7 @@ if (frontendBuildPath) { } // Root route -app.get('/', (req, res) => { +app.get('/', apiLimiter, (req, res) => { if (!frontendBuildPath) { return res.status(500).send('Frontend build not found'); } @@ -110,7 +110,7 @@ app.get('/', (req, res) => { }); // Client-side routing fallback -app.get('*', (req, res) => { +app.get('*', apiLimiter, (req, res) => { // Ignoriere API Routes if (req.path.startsWith('/api/')) { return res.status(404).json({ error: 'API endpoint not found' }); @@ -137,12 +137,34 @@ app.get('*', (req, res) => { } }); +// Production error handling - don't leak stack traces +app.use((err: any, req: express.Request, res: express.Response, next: express.NextFunction) => { + console.error('Error:', err); + + if (process.env.NODE_ENV === 'production') { + res.status(500).json({ + error: 'Internal server error', + message: 'Something went wrong' + }); + } else { + res.status(500).json({ + error: 'Internal server error', + message: err.message, + stack: err.stack + }); + } +}); + // Error handling middleware app.use((err: any, req: express.Request, res: express.Response, next: express.NextFunction) => { console.error('Unhandled error:', err); res.status(500).json({ error: 'Internal server error' }); }); +app.use('*', (req, res) => { + res.status(404).json({ error: 'Endpoint not found' }); +}); + // Initialize the application const initializeApp = async () => { try { diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index bc4cbd7..42b0ea7 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -1,45 +1,60 @@ -import { defineConfig } from 'vite' +import { defineConfig, loadEnv } from 'vite' import react from '@vitejs/plugin-react' import { resolve } from 'path' // https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react()], - server: { - port: 3003, - host: true, - open: true, - proxy: { - '/api': { - target: 'http://localhost:3002', - changeOrigin: true, - secure: false, +export default defineConfig(({ mode }) => { + // Load env file based on `mode` in the current directory + const env = loadEnv(mode, process.cwd(), '') + + // Only expose specific environment variables to the client + const clientEnv = { + NODE_ENV: mode, + ENABLE_PRO: env.ENABLE_PRO || 'false', + VITE_APP_TITLE: env.VITE_APP_TITLE || 'Shift Planning App', + // Add other client-safe variables here + } + + return { + plugins: [react()], + server: { + port: 3003, + host: true, + open: mode === 'development', + proxy: { + '/api': { + target: 'http://localhost:3002', + changeOrigin: true, + secure: false, + } } - } - }, - build: { - outDir: 'dist', - sourcemap: true, - rollupOptions: { - input: { - main: resolve(__dirname, 'index.html') + }, + build: { + outDir: 'dist', + sourcemap: mode === 'development', + minify: mode === 'production' ? 'terser' : false, + terserOptions: mode === 'production' ? { + compress: { + drop_console: true, + }, + } : undefined, + }, + resolve: { + alias: { + '@': resolve(__dirname, './src'), + '@/components': resolve(__dirname, './src/components'), + '@/pages': resolve(__dirname, './src/pages'), + '@/contexts': resolve(__dirname, './src/contexts'), + '@/models': resolve(__dirname, './src/models'), + '@/utils': resolve(__dirname, './src/utils'), + '@/services': resolve(__dirname, './src/services'), + '@/design': resolve(__dirname, './src/design') } - } - }, - resolve: { - alias: { - '@': resolve(__dirname, './src'), - '@/components': resolve(__dirname, './src/components'), - '@/pages': resolve(__dirname, './src/pages'), - '@/contexts': resolve(__dirname, './src/contexts'), - '@/models': resolve(__dirname, './src/models'), - '@/utils': resolve(__dirname, './src/utils'), - '@/services': resolve(__dirname, './src/services'), - '@/design': resolve(__dirname, './src/design') - } - }, - // Define environment variables - define: { - 'process.env': process.env + }, + // ✅ SICHER: Nur explizit definierte Variablen + define: Object.keys(clientEnv).reduce((acc, key) => { + acc[`process.env.${key}`] = JSON.stringify(clientEnv[key]) + return acc + }, {} as Record) } }) \ No newline at end of file