Files
starr-philproperties/server.js
T
2026-05-05 23:18:47 +08:00

115 lines
5.7 KiB
JavaScript

/***********************************************************************************************************************************************************************
* File Name: server.js
* Type of Program: Application Entry Point
* Description: Bootstraps the Express application.
* Registers global middleware (CORS, rate-limit, cookie-parser,
* session, Passport) and mounts all route groups.
* Syncs Sequelize models to the database on startup.
*
* Author: rgrgogu
* Date Created: Oct. 6, 2025
***********************************************************************************************************************************************************************
* HOW TO RUN:
* 1. cp .env.example .env (fill in your values)
* 2. npm install
* 3. npm run dev (development)
* npm start (production)
***********************************************************************************************************************************************************************/
require('dotenv').config();
const express = require('express');
const cors = require('cors');
const cookieParser = require('cookie-parser');
const session = require('express-session');
const passport = require('./config/passport.config');
const sequelize = require('./config/db.config');
// ── Middleware ──────────────────────────────────────────────────────────────────
const { globalLimiter } = require('./middleware/rateLimiter.middleware');
const { csrfErrorHandler } = require('./middleware/csrf.middleware');
// ── Routes ─────────────────────────────────────────────────────────────────────
const authRoutes = require('./routes/auth.routes');
const clientRoutes = require('./routes/client/client.routes');
const staffRoutes = require('./routes/staff/staff.routes');
const adminRoutes = require('./routes/admin/admin.routes');
// ── Models (ensure associations are loaded) ────────────────────────────────────
require('./models/users/users.mdl');
require('./models/users/user_sessions.mdl');
require('./models/users/user_groups.mdl');
const app = express();
const PORT = process.env.PORT || 3000;
// ──────────────────────────────────────────────────────────────────────────────
// Global Middleware Stack
// ──────────────────────────────────────────────────────────────────────────────
app.set('trust proxy', 1); // Required for rate-limiter behind proxies/load balancers
app.use(cors({
origin: process.env.APP_URL || '*',
credentials: true,
}));
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cookieParser());
// Session — used only by csurf; JWT handles auth state
app.use(session({
secret: process.env.SESSION_SECRET || 'change-me',
resave: false,
saveUninitialized: false,
cookie: { secure: process.env.NODE_ENV === 'production', httpOnly: true, sameSite: 'strict' },
}));
app.use(passport.initialize());
// Global rate limiter (1000 req / 15 min)
app.use(globalLimiter);
// ──────────────────────────────────────────────────────────────────────────────
// Routes
// ──────────────────────────────────────────────────────────────────────────────
app.use('/api/auth', authRoutes);
app.use('/api/client', clientRoutes);
app.use('/api/staff', staffRoutes);
app.use('/api/admin', adminRoutes);
// Health check
app.get('/api/health', (req, res) => {
res.json({ status: 'ok', timestamp: new Date().toISOString(), env: process.env.NODE_ENV });
});
// 404 handler
app.use((req, res) => {
res.status(404).json({ status: 'error', message: 'Route not found.' });
});
// CSRF error handler (must be after routes)
app.use(csrfErrorHandler);
// Global error handler
app.use((err, req, res, next) => {
console.error('[UNHANDLED ERROR]', err);
res.status(500).json({ status: 'error', message: 'Internal server error.' });
});
// ──────────────────────────────────────────────────────────────────────────────
// Database Sync + Listen
// ──────────────────────────────────────────────────────────────────────────────
(async () => {
try {
await sequelize.authenticate();
console.log('✅ Database connected.');
app.listen(PORT, () => {
console.log(`🚀 STARR Server running on http://localhost:${PORT}`);
console.log(` Environment : ${process.env.NODE_ENV}`);
});
} catch (err) {
console.error('❌ Failed to start server:', err);
process.exit(1);
}
})();