Files
rentall-app/backend/server.js
2025-10-06 15:41:48 -04:00

159 lines
4.4 KiB
JavaScript

// Load environment-specific config
const env = process.env.NODE_ENV || "dev";
const envFile = `.env.${env}`;
require("dotenv").config({
path: envFile,
});
const express = require("express");
const cors = require("cors");
const bodyParser = require("body-parser");
const path = require("path");
const helmet = require("helmet");
const { sequelize } = require("./models"); // Import from models/index.js to ensure associations are loaded
const { cookieParser } = require("./middleware/csrf");
const logger = require("./utils/logger");
const morgan = require("morgan");
const authRoutes = require("./routes/auth");
const userRoutes = require("./routes/users");
const itemRoutes = require("./routes/items");
const rentalRoutes = require("./routes/rentals");
const messageRoutes = require("./routes/messages");
const itemRequestRoutes = require("./routes/itemRequests");
const stripeRoutes = require("./routes/stripe");
const mapsRoutes = require("./routes/maps");
const conditionCheckRoutes = require("./routes/conditionChecks");
const PayoutProcessor = require("./jobs/payoutProcessor");
const RentalStatusJob = require("./jobs/rentalStatusJob");
const ConditionCheckReminderJob = require("./jobs/conditionCheckReminder");
const app = express();
// Import security middleware
const {
enforceHTTPS,
securityHeaders,
addRequestId,
sanitizeError,
} = require("./middleware/security");
const { generalLimiter } = require("./middleware/rateLimiter");
const errorLogger = require("./middleware/errorLogger");
const apiLogger = require("./middleware/apiLogger");
// Apply security middleware
app.use(enforceHTTPS);
app.use(addRequestId);
app.use(securityHeaders);
// Security headers with Helmet
app.use(
helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
styleSrc: ["'self'", "https://cdn.jsdelivr.net"],
fontSrc: ["'self'"],
scriptSrc: ["'self'", "https://accounts.google.com"],
imgSrc: ["'self'"],
connectSrc: ["'self'"],
frameSrc: ["'self'", "https://accounts.google.com"],
},
},
})
);
// Cookie parser for CSRF
app.use(cookieParser);
// HTTP request logging
app.use(morgan("combined", { stream: logger.stream }));
// API request/response logging
app.use("/api/", apiLogger);
// General rate limiting for all routes
app.use("/api/", generalLimiter);
// CORS with security settings
app.use(
cors({
origin: process.env.FRONTEND_URL || "http://localhost:3000",
credentials: true,
optionsSuccessStatus: 200,
})
);
// Body parsing with size limits
app.use(
bodyParser.json({
limit: "1mb",
verify: (req, res, buf) => {
// Store raw body for webhook verification
req.rawBody = buf;
},
})
);
app.use(
bodyParser.urlencoded({
extended: true,
limit: "1mb",
parameterLimit: 100, // Limit number of parameters
})
);
// Serve static files from uploads directory
app.use("/uploads", express.static(path.join(__dirname, "uploads")));
app.use("/api/auth", authRoutes);
app.use("/api/users", userRoutes);
app.use("/api/items", itemRoutes);
app.use("/api/rentals", rentalRoutes);
app.use("/api/messages", messageRoutes);
app.use("/api/item-requests", itemRequestRoutes);
app.use("/api/stripe", stripeRoutes);
app.use("/api/maps", mapsRoutes);
app.use("/api/condition-checks", conditionCheckRoutes);
app.get("/", (req, res) => {
res.json({ message: "CommunityRentals.App API is running!" });
});
// Error handling middleware (must be last)
app.use(errorLogger);
app.use(sanitizeError);
const PORT = process.env.PORT || 5000;
sequelize
.sync({ alter: true })
.then(() => {
logger.info("Database synced successfully");
// Start the payout processor
const payoutJobs = PayoutProcessor.startScheduledPayouts();
logger.info("Payout processor started");
// Start the rental status job
const rentalStatusJobs = RentalStatusJob.startScheduledStatusUpdates();
logger.info("Rental status job started");
// Start the condition check reminder job
const conditionCheckJobs = ConditionCheckReminderJob.startScheduledReminders();
logger.info("Condition check reminder job started");
app.listen(PORT, () => {
logger.info(`Server is running on port ${PORT}`, {
port: PORT,
environment: env,
});
});
})
.catch((err) => {
logger.error("Unable to sync database", {
error: err.message,
stack: err.stack,
});
});