-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathserver.js
More file actions
126 lines (110 loc) · 3.66 KB
/
server.js
File metadata and controls
126 lines (110 loc) · 3.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
import express from 'express';
import cors from 'cors';
import dotenv from 'dotenv';
import { initializeDatabase } from './db/database.js';
import { redis } from './services/redis.js';
// Import routes
import authRoutes from './routes/auth.js';
import servicesRoutes from './routes/services.js';
import slotsRoutes from './routes/slots.js';
import reservationsRoutes from './routes/reservations.js';
dotenv.config();
const app = express();
const PORT = process.env.PORT || 3000;
// Middleware
app.use(cors());
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// Request logging
app.use((req, res, next) => {
console.log(`${new Date().toISOString()} - ${req.method} ${req.path}`);
next();
});
// Health check endpoint
app.get('/health', async (req, res) => {
try {
// Test Redis connection
await redis.ping();
res.json({
status: 'healthy',
timestamp: new Date().toISOString(),
services: {
database: 'connected',
redis: 'connected'
}
});
} catch (error) {
res.status(503).json({
status: 'unhealthy',
error: error.message
});
}
});
// API Routes
app.use('/api/auth', authRoutes);
app.use('/api/services', servicesRoutes);
app.use('/api/slots', slotsRoutes);
app.use('/api/reservations', reservationsRoutes);
// Root endpoint
app.get('/', (req, res) => {
res.json({
name: 'Bookd API',
version: '1.0.0',
description: 'Reservation system with RBAC and concurrency control',
endpoints: {
health: '/health',
auth: '/api/auth',
services: '/api/services',
slots: '/api/slots',
reservations: '/api/reservations'
}
});
});
// 404 handler
app.use((req, res) => {
res.status(404).json({ error: 'Not found' });
});
// Global error handler
app.use((err, req, res, next) => {
console.error('Global error handler:', err);
res.status(err.status || 500).json({
error: err.message || 'Internal server error',
...(process.env.NODE_ENV === 'development' && { stack: err.stack })
});
});
// Initialize database and start server
async function startServer() {
try {
console.log('🚀 Starting Bookd server...\n');
// Initialize database schema
await initializeDatabase();
// Start Express server
app.listen(PORT, () => {
console.log(`\n✓ Server running on http://localhost:${PORT}`);
console.log(`✓ Environment: ${process.env.NODE_ENV || 'development'}`);
console.log(`✓ PostgreSQL: ${process.env.DB_HOST}:${process.env.DB_PORT}`);
console.log(`✓ Redis: ${process.env.REDIS_HOST}:${process.env.REDIS_PORT}`);
console.log('\n📚 API Documentation:');
console.log(` Health: http://localhost:${PORT}/health`);
console.log(` Auth: http://localhost:${PORT}/api/auth`);
console.log(` Services: http://localhost:${PORT}/api/services`);
console.log(` Slots: http://localhost:${PORT}/api/slots`);
console.log(` Reservations: http://localhost:${PORT}/api/reservations\n`);
});
} catch (error) {
console.error('Failed to start server:', error);
process.exit(1);
}
}
// Handle graceful shutdown
process.on('SIGTERM', async () => {
console.log('SIGTERM received, shutting down gracefully...');
await redis.quit();
process.exit(0);
});
process.on('SIGINT', async () => {
console.log('\nSIGINT received, shutting down gracefully...');
await redis.quit();
process.exit(0);
});
startServer();