Source

index.js

/**
 * 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;