import 'dotenv/config'; import express from 'express'; import cors from 'cors'; import { initDatabase, pool } from './db.js'; import { requireAuth, requireRole } from './middleware/auth.js'; import authRoutes from './routes/auth.js'; import userRoutes from './routes/users.js'; import customerRoutes from './routes/customers.js'; import projectRoutes from './routes/projects.js'; import entryRoutes from './routes/entries.js'; import dashboardRoutes from './routes/dashboard.js'; import reportRoutes from './routes/reports.js'; import exportRoutes from './routes/exports.js'; import settingsRoutes from './routes/settings.js'; import directoryRoutes from './routes/directory.js'; const app = express(); const PORT = Number(process.env.PORT || 5010); const HOST = process.env.HOST || '127.0.0.1'; // Apache steht davor - fuer req.ip (Login-Bremse) die echte Client-IP nehmen. app.set('trust proxy', 'loopback'); app.disable('x-powered-by'); // Logos kommen als Data-URL. app.use(express.json({ limit: '4mb' })); app.use( cors({ origin: (process.env.CORS_ORIGINS || 'http://localhost:3110,http://127.0.0.1:3110').split(','), }) ); app.get('/api/health', async (req, res) => { try { await pool.query('SELECT 1'); res.json({ ok: true, db: 'up' }); } catch { res.status(503).json({ ok: false, db: 'down' }); } }); app.use('/api/auth', authRoutes); app.use('/api/users', requireAuth, userRoutes); app.use('/api/customers', requireAuth, requireRole('lead'), customerRoutes); app.use('/api/projects', requireAuth, projectRoutes); app.use('/api/entries', requireAuth, entryRoutes); app.use('/api/dashboard', requireAuth, requireRole('lead'), dashboardRoutes); app.use('/api/reports', requireAuth, requireRole('lead'), reportRoutes); app.use('/api/exports', requireAuth, exportRoutes); app.use('/api/settings', requireAuth, settingsRoutes); app.use('/api/directory', requireAuth, requireRole('management'), directoryRoutes); app.use('/api', (req, res) => res.status(404).json({ error: 'Endpunkt nicht gefunden.' })); app.use((err, req, res, next) => { if (res.headersSent) return next(err); if (err?.type === 'entity.parse.failed') return res.status(400).json({ error: 'Ungültige Anfrage.' }); if (err?.type === 'entity.too.large') return res.status(413).json({ error: 'Die Anfrage ist zu groß.' }); if (err?.code === 'ER_ROW_IS_REFERENCED_2') { return res.status(409).json({ error: 'Der Datensatz wird noch verwendet und kann nicht gelöscht werden.' }); } console.error('[Pulse] Unbehandelter Fehler:', err); res.status(500).json({ error: 'Interner Serverfehler.' }); }); try { await initDatabase(); app.listen(PORT, HOST, () => console.log(`[Pulse] Backend läuft auf http://${HOST}:${PORT}`)); } catch (err) { console.error('[Pulse] Start fehlgeschlagen:', err); process.exit(1); }