/**
* Social Media Dashboard API Server
*
* Main Express.js server for the Social Media Dashboard API. Handles authentication,
* social media platform integrations, and provides RESTful endpoints for the frontend.
*
* Features:
* - JWT-based authentication
* - OAuth integration with multiple social platforms
* - Rate limiting and security middleware
* - CORS configuration for frontend communication
* - Swagger API documentation
*
* @author Ignas Panavas
* @version 1.0.0
*/
const express = require('express');
const cors = require('cors');
const helmet = require('helmet');
const rateLimit = require('express-rate-limit');
const path = require('path');
require('dotenv').config();
const connectDB = require('./config/database');
const authRoutes = require('./routes/auth');
const socialRoutes = require('./routes/social');
const userRoutes = require('./routes/users');
const app = express();
const PORT = process.env.PORT || 5000;
// Security middleware
app.use(helmet());
app.use(cors({
origin: [
process.env.CORS_ORIGIN,
process.env.CLIENT_URL,
'https://docs.ignaspanavas.com',
'http://localhost:3000',
].filter(Boolean),
credentials: true
}));
// If running behind a reverse proxy (e.g., Nginx/Cloudflare) that terminates TLS,
// trust the proxy so req.secure is set correctly and secure cookies are honored.
app.set('trust proxy', 1);
// Rate limiting
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100 // limit each IP to 100 requests per windowMs
});
app.use(limiter);
// Body parsing middleware
app.use(express.json({ limit: '10mb' }));
app.use(express.urlencoded({ extended: true }));
// Session middleware for OAuth state persistence
const session = require('express-session');
app.use(session({
secret: process.env.SESSION_SECRET || 'change-me',
resave: false,
saveUninitialized: true,
cookie: {
secure: 'auto', // secure when behind HTTPS, non-secure on HTTP
sameSite: 'lax'
}
}));
// Routes
app.use('/api/auth', authRoutes);
app.use('/api/social', socialRoutes);
app.use('/api/users', userRoutes);
// Docs are deployed separately at https://docs.ignaspanavas.com
// Swagger docs (dynamic from JSDoc annotations)
const swaggerUi = require('swagger-ui-express');
const swaggerJSDoc = require('swagger-jsdoc');
const swaggerSpec = swaggerJSDoc({
definition: {
openapi: '3.0.3',
info: { title: 'SocialMediaDashboard API', version: '1.0.0' },
servers: [
{ url: `${process.env.API_BASE_URL}/api` },
],
components: {
securitySchemes: {
bearerAuth: { type: 'http', scheme: 'bearer', bearerFormat: 'JWT' },
},
},
},
apis: [
__dirname + '/routes/*.js',
],
});
app.use('/api/docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec));
app.get('/api/docs.json', (req, res) => {
res.json(swaggerSpec);
});
// Health check endpoint
app.get('/api/health', (req, res) => {
res.json({ status: 'OK', timestamp: new Date().toISOString() });
});
// Instagram webhook verification endpoint
app.get('/api/instagram/webhook', (req, res) => {
const mode = req.query['hub.mode'];
const token = req.query['hub.verify_token'];
const challenge = req.query['hub.challenge'];
// Verify the webhook
if (mode === 'subscribe' && token === process.env.INSTAGRAM_VERIFY_TOKEN) {
console.log('Instagram webhook verified');
res.status(200).send(challenge);
} else {
console.log('Instagram webhook verification failed');
res.status(403).send('Forbidden');
}
});
// Instagram webhook endpoint for receiving updates
app.post('/api/instagram/webhook', (req, res) => {
console.log('Instagram webhook received:', req.body);
res.status(200).send('OK');
});
// Error handling middleware
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({
message: 'Something went wrong!',
error: process.env.NODE_ENV === 'development' ? err.message : {}
});
});
// 404 handler - catch all unmatched routes
app.use((req, res) => {
res.status(404).json({ message: 'Route not found' });
});
// Connect to MongoDB
connectDB();
app.listen(PORT, () => {
console.log(`🚀 Server running on port ${PORT}`);
console.log(`📊 Social Media Dashboard API ready`);
});
module.exports = app;
Source