const express = require('express'); const cors = require('cors'); const helmet = require('helmet'); const morgan = require('morgan'); const session = require('express-session'); const passport = require('passport'); require('dotenv').config(); const database = require('./config/database'); const PassportConfig = require('./config/passport'); const unhashRequestIds = require('./middleware/unhashRequest'); const hashResponseIds = require('./middleware/hashResponse'); const app = express(); const PORT = process.env.PORT || 3010; // Middleware app.use(helmet()); app.use(cors({ origin: process.env.FRONTEND_URL || 'http://localhost:5010', credentials: true })); app.use(express.json()); app.use(express.urlencoded({ extended: true })); app.use(morgan('dev')); // Session für Passport (OAuth) app.use(session({ secret: process.env.SESSION_SECRET || 'session-secret-change-in-production', resave: false, saveUninitialized: false, cookie: { secure: process.env.NODE_ENV === 'production', maxAge: 24 * 60 * 60 * 1000 // 24 Stunden } })); // Passport initialisieren app.use(passport.initialize()); app.use(passport.session()); PassportConfig.initialize(); // Routes app.get('/api/health', (req, res) => { res.json({ status: 'ok', message: 'TimeClock API v3.0.0', timestamp: new Date().toISOString() }); }); // Auth routes (öffentlich) - OHNE ID-Hashing const authRouter = require('./routes/auth'); app.use('/api/auth', authRouter); // ID-Hashing Middleware (nur für geschützte Routes) app.use(unhashRequestIds); app.use(hashResponseIds); // Time entries routes (geschützt) - MIT ID-Hashing const timeEntriesRouter = require('./routes/timeEntries'); const { authenticateToken } = require('./middleware/auth'); app.use('/api/time-entries', authenticateToken, timeEntriesRouter); // Week overview routes (geschützt) - MIT ID-Hashing const weekOverviewRouter = require('./routes/weekOverview'); app.use('/api/week-overview', authenticateToken, weekOverviewRouter); // Timefix routes (geschützt) - MIT ID-Hashing const timefixRouter = require('./routes/timefix'); app.use('/api/timefix', authenticateToken, timefixRouter); // Vacation routes (geschützt) - MIT ID-Hashing const vacationRouter = require('./routes/vacation'); app.use('/api/vacation', authenticateToken, vacationRouter); // Sick routes (geschützt) - MIT ID-Hashing const sickRouter = require('./routes/sick'); app.use('/api/sick', authenticateToken, sickRouter); // Workdays routes (geschützt) - MIT ID-Hashing const workdaysRouter = require('./routes/workdays'); app.use('/api/workdays', authenticateToken, workdaysRouter); // Calendar routes (geschützt) - MIT ID-Hashing const calendarRouter = require('./routes/calendar'); app.use('/api/calendar', authenticateToken, calendarRouter); // Holidays routes (geschützt, nur Admin) - MIT ID-Hashing const holidaysRouter = require('./routes/holidays'); app.use('/api/holidays', authenticateToken, holidaysRouter); // Profile routes (geschützt) - MIT ID-Hashing const profileRouter = require('./routes/profile'); app.use('/api/profile', authenticateToken, profileRouter); // Error handling middleware app.use((err, req, res, next) => { console.error(err.stack); res.status(500).json({ error: 'Etwas ist schiefgelaufen!', message: process.env.NODE_ENV === 'development' ? err.message : undefined }); }); // 404 handler app.use((req, res) => { res.status(404).json({ error: 'Route nicht gefunden' }); }); // Datenbank initialisieren und Server starten database.initialize() .then(() => { app.listen(PORT, () => { console.log(`🕐 TimeClock Server läuft auf Port ${PORT}`); console.log(`📍 API verfügbar unter http://localhost:${PORT}/api`); }); }) .catch(error => { console.error('❌ Server konnte nicht gestartet werden:', error.message); process.exit(1); }); // Graceful Shutdown process.on('SIGTERM', async () => { console.log('SIGTERM empfangen, fahre Server herunter...'); await database.close(); process.exit(0); }); process.on('SIGINT', async () => { console.log('\nSIGINT empfangen, fahre Server herunter...'); await database.close(); process.exit(0); }); module.exports = app;