0% found this document useful (0 votes)
4 views24 pages

Backend Complete Guide Main

This document provides a comprehensive code guide for setting up the backend of an AI-powered DevOps monitoring platform. It outlines the necessary steps, including configuring package.json, environment variables, database connection, socket setup, and middleware for error handling and authentication. Additionally, it details the structure of models for predictions and utility functions for token generation and pagination.

Uploaded by

ishanpatelraj3
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
4 views24 pages

Backend Complete Guide Main

This document provides a comprehensive code guide for setting up the backend of an AI-powered DevOps monitoring platform. It outlines the necessary steps, including configuring package.json, environment variables, database connection, socket setup, and middleware for error handling and authentication. Additionally, it details the structure of models for predictions and utility functions for token generation and pagination.

Uploaded by

ishanpatelraj3
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

5/17/26, 8:02 PM Untitled

AI DevOps Monitoring Platform — Backend


Code Guide
Build files in the order listed. Each section explains why the file exists before showing the
code.

⚠️ One Note Before You Start


Your existing [Link] is not listed in your new structure, but do not delete it —
[Link] imports it. Either:

Keep it as models/[Link] (easiest), or


Rename it to models/[Link] and update the import in [Link]

STEP 1 — [Link]
Defines all dependencies. Run npm install after creating this.

{
"name": "devops-monitor-backend",
"version": "1.0.0",
"description": "AI-Powered DevOps Monitoring Platform Backend",
"main": "src/[Link]",
"scripts": {
"start": "node src/[Link]",
"dev": "nodemon src/[Link]"
},
"dependencies": {
"axios": "^1.6.0",
"bcryptjs": "^2.4.3",
"cookie-parser": "^1.4.6",
"cors": "^2.8.5",
"dotenv": "^16.3.1",
"express": "^4.18.2",
"jsonwebtoken": "^9.0.2",
"mongoose": "^8.0.0",
"[Link]": "^4.6.1"
},
"devDependencies": {
"nodemon": "^3.0.1"

about:blank 1/24
5/17/26, 8:02 PM Untitled

}
}

STEP 2 — .env

Never commit this file to Git. Add .env to your .gitignore .

# Server
PORT=5000
NODE_ENV=development

# MongoDB
MONGO_URI=mongodb://localhost:27017/devops-monitor

# JWT
JWT_SECRET=your_super_secret_jwt_key_change_this_in_production
JWT_EXPIRE=7d

# ML Service (Python FastAPI)


ML_SERVICE_URL=[Link]

# Frontend URL (for CORS)


CLIENT_URL=[Link]

STEP 3 — src/config/[Link]

Connects Express to MongoDB using Mongoose.


Called once when the server starts.

const mongoose = require("mongoose");

const connectDB = async () => {


try {
const conn = await [Link]([Link].MONGO_URI);
[Link](`✅ MongoDB Connected: ${[Link]}`);
} catch (error) {
[Link](`❌ MongoDB connection error: ${[Link]}`);
// Exit the process if DB connection fails — no point running without DB
[Link](1);
}
};

[Link] = connectDB;

about:blank 2/24
5/17/26, 8:02 PM Untitled

STEP 4 — src/config/[Link]
Sets up [Link] so the backend can push live updates to the React frontend.
We export the io instance so any controller can emit events.

const { Server } = require("[Link]");

let io; // We store io here so other files can import and use it

const initSocket = (httpServer) => {


io = new Server(httpServer, {
cors: {
origin: [Link].CLIENT_URL || "[Link]
methods: ["GET", "POST"],
},
});

[Link]("connection", (socket) => {


[Link](`🔌 Client connected: ${[Link]}`);

[Link]("disconnect", () => {
[Link](`🔌 Client disconnected: ${[Link]}`);
});
});

return io;
};

// Other files import getIO() to emit events


const getIO = () => {
if (!io) {
throw new Error("[Link] not initialized! Call initSocket first.");
}
return io;
};

[Link] = { initSocket, getIO };

STEP 5 — src/models/[Link]
Stores ML prediction results (anomaly scores, failure probabilities).
This is the only model not yet created.

const mongoose = require("mongoose");

const predictionSchema = new [Link]({


about:blank 3/24
5/17/26, 8:02 PM Untitled

// Which server this prediction is about


serverId: {
type: String,
required: [true, "Server ID is required"],
index: true, // Index for faster queries by server
},

// Type of ML prediction performed


predictionType: {
type: String,
enum: ["anomaly", "failure", "log_classification"],
required: true,
},

// The result/output from the ML model


result: {
type: String, // e.g., "ANOMALY_DETECTED", "NORMAL", "HIGH_RISK"
required: true,
},

// Confidence score from the ML model (0 to 1)


confidence: {
type: Number,
min: 0,
max: 1,
default: 0,
},

// Raw details returned by the ML service


details: {
type: [Link], // Allows any shape of data
default: {},
},

timestamp: {
type: Date,
default: [Link],
},
});

[Link] = [Link]("Prediction", predictionSchema);

STEP 6 — src/utils/[Link]
A single place to store magic strings and numbers.
Changing a constant here updates it everywhere.

about:blank 4/24
5/17/26, 8:02 PM Untitled

// HTTP Status Codes — use these instead of raw numbers


const STATUS = {
OK: 200,
CREATED: 201,
BAD_REQUEST: 400,
UNAUTHORIZED: 401,
FORBIDDEN: 403,
NOT_FOUND: 404,
SERVER_ERROR: 500,
};

// Severity levels used across Logs and Alerts


const SEVERITY = {
INFO: "INFO",
WARNING: "WARNING",
ERROR: "ERROR",
CRITICAL: "CRITICAL",
};

// Alert types
const ALERT_TYPES = {
CPU: "CPU",
MEMORY: "MEMORY",
DISK: "DISK",
SERVICE_DOWN: "SERVICE_DOWN",
ML_ANOMALY: "ML_ANOMALY",
};

// Prediction types (must match Prediction model enum)


const PREDICTION_TYPES = {
ANOMALY: "anomaly",
FAILURE: "failure",
LOG_CLASSIFICATION: "log_classification",
};

[Link] = { STATUS, SEVERITY, ALERT_TYPES, PREDICTION_TYPES };

STEP 7 — src/utils/[Link]
Creates a signed JWT token for a user.
Called during register and login.

const jwt = require("jsonwebtoken");

/**
* Generates a JWT and sets it as an HTTP-only cookie on the response.
* HTTP-only means JavaScript on the frontend cannot read the cookie

about:blank 5/24
5/17/26, 8:02 PM Untitled

* (protects against XSS attacks).


*
* @param {Object} res - Express response object
* @param {string} userId - The MongoDB _id of the user
*/
const generateToken = (res, userId) => {
const token = [Link](
{ id: userId }, // Payload: what we store inside the token
[Link].JWT_SECRET,
{ expiresIn: [Link].JWT_EXPIRE || "7d" }
);

[Link]("token", token, {
httpOnly: true, // Not accessible via JavaScript
secure: [Link].NODE_ENV === "production", // HTTPS only in production
sameSite: "strict", // Prevents CSRF attacks
maxAge: 7 * 24 * 60 * 60 * 1000, // 7 days in milliseconds
});

return token;
};

[Link] = generateToken;

STEP 8 — src/utils/[Link]

Reusable helper for paginated MongoDB queries.


Pass it a Mongoose Model + query params and it returns paginated results.

/**
* Generic pagination helper.
*
* Usage in a controller:
* const result = await paginate(Log, [Link], { serviceName: "api" });
*
* Query params supported: ?page=1&limit=20
*
* @param {Model} Model - A Mongoose model (e.g., Log, Metric)
* @param {Object} query - [Link] from Express
* @param {Object} filter - MongoDB filter object (e.g., { severity: "ERROR" })
* @returns {Object} { data, currentPage, totalPages, totalCount }
*/
const paginate = async (Model, query = {}, filter = {}) => {
const page = parseInt([Link]) || 1; // Default: page 1
const limit = parseInt([Link]) || 20; // Default: 20 items per page
const skip = (page - 1) * limit; // How many documents to skip

about:blank 6/24
5/17/26, 8:02 PM Untitled

// Run both queries in parallel for speed


const [data, totalCount] = await [Link]([
[Link](filter).sort({ timestamp: -1 }).skip(skip).limit(limit),
[Link](filter),
]);

return {
data,
currentPage: page,
totalPages: [Link](totalCount / limit),
totalCount,
};
};

[Link] = paginate;

STEP 9 — src/middleware/[Link]
Wraps async controller functions to catch errors automatically.
Without this you'd need try/catch in every single controller.

/**
* Wraps an async function and passes any error to Express's error handler.
*
* Instead of:
* async (req, res, next) => { try { ... } catch(e) { next(e) } }
*
* You write:
* catchAsync(async (req, res, next) => { ... })
*/
const catchAsync = (fn) => {
return (req, res, next) => {
fn(req, res, next).catch(next); // .catch(next) sends error to errorMiddleware
};
};

[Link] = catchAsync;

STEP 10 — src/middleware/[Link]
Global error handler. Express calls this whenever next(error) is called.
Keeps all error formatting in one place.

const errorMiddleware = (err, req, res, next) => {


// Use the error's status code, or default to 500
about:blank 7/24
5/17/26, 8:02 PM Untitled

let statusCode = [Link] || 500;


let message = [Link] || "Internal Server Error";

// Mongoose: CastError means an invalid MongoDB ObjectId was passed


if ([Link] === "CastError") {
statusCode = 400;
message = `Invalid ID format: ${[Link]}`;
}

// Mongoose: Duplicate key error (e.g., registering with an existing email)


if ([Link] === 11000) {
statusCode = 400;
const field = [Link]([Link])[0];
message = `${field} already exists. Please use a different value.`;
}

// Mongoose: Validation error (required fields missing, enum mismatch, etc.)


if ([Link] === "ValidationError") {
statusCode = 400;
message = [Link]([Link])
.map((e) => [Link])
.join(", ");
}

// JWT errors
if ([Link] === "JsonWebTokenError") {
statusCode = 401;
message = "Invalid token. Please log in again.";
}
if ([Link] === "TokenExpiredError") {
statusCode = 401;
message = "Token expired. Please log in again.";
}

[Link](statusCode).json({
success: false,
message,
// Only show the stack trace in development (hides internal details in production)
...([Link].NODE_ENV === "development" && { stack: [Link] }),
});
};

[Link] = errorMiddleware;

STEP 11 — src/middleware/[Link]

Protects routes. Only logged-in users with valid tokens can access protected endpoints.

about:blank 8/24
5/17/26, 8:02 PM Untitled

const jwt = require("jsonwebtoken");


const catchAsync = require("./catchAsync");
const User = require("../models/User");
const BlacklistToken = require("../models/blacklistModel"); // Your existing file

// Protect middleware — any route that needs authentication uses this


const protect = catchAsync(async (req, res, next) => {
const token = [Link];

if (!token) {
return [Link](401).json({
success: false,
message: "Not authorized. Please log in.",
});
}

// Check if this token was blacklisted (user logged out)


const isBlacklisted = await [Link]({ token });
if (isBlacklisted) {
return [Link](401).json({
success: false,
message: "Token is invalid. Please log in again.",
});
}

// Verify the token signature and decode the payload


const decoded = [Link](token, [Link].JWT_SECRET);

// Attach the full user object to the request for use in controllers
[Link] = await [Link]([Link]).select("-password");

next(); // User is authenticated — proceed to the controller


});

// Role-based access control middleware


// Usage: [Link]("/users/:id", protect, authorize("Admin"), controller)
const authorize = (...roles) => {
return (req, res, next) => {
if (![Link]([Link])) {
return [Link](403).json({
success: false,
message: `Role '${[Link]}' is not allowed to perform this action.`,
});
}
next();
};
};

[Link] = { protect, authorize };

about:blank 9/24
5/17/26, 8:02 PM Untitled

STEP 12 — src/ml/[Link]

A simple HTTP client that calls your Python FastAPI ML service.


Keeps all ML communication in one place.

const axios = require("axios");

// Base URL for the Python ML microservice


const ML_BASE_URL = [Link].ML_SERVICE_URL || "[Link]

/**
* Send metric data to the ML service for anomaly detection.
* Returns prediction result from the ML model.
*
* @param {Object} metricData - { serverId, cpuUsage, memoryUsage, diskUsage }
*/
const detectAnomaly = async (metricData) => {
try {
const response = await [Link](`${ML_BASE_URL}/predict/anomaly`, metricData, {
timeout: 5000, // 5 second timeout — don't block the API if ML is slow
});
return [Link];
} catch (error) {
// If ML service is down, log the error but don't crash the main API
[Link]("⚠️ ML Service (anomaly) unavailable:", [Link]);
return null; // Return null so the caller can handle gracefully
}
};

/**
* Send metric data to the ML service for failure prediction.
* Returns crash probability and recommendation.
*
* @param {Object} metricData - { serverId, cpuUsage, memoryUsage, diskUsage }
*/
const predictFailure = async (metricData) => {
try {
const response = await [Link](`${ML_BASE_URL}/predict/failure`, metricData, {
timeout: 5000,
});
return [Link];
} catch (error) {
[Link]("⚠️ ML Service (failure) unavailable:", [Link]);
return null;
}
};

about:blank 10/24
5/17/26, 8:02 PM Untitled

/**
* Send a log message to the ML service for classification.
* Returns the log category (e.g., "Database Error", "Network Issue").
*
* @param {string} logMessage - The raw log message text
*/
const classifyLog = async (logMessage) => {
try {
const response = await [Link](
`${ML_BASE_URL}/predict/classify-log`,
{ message: logMessage },
{ timeout: 5000 }
);
return [Link];
} catch (error) {
[Link]("⚠️ ML Service (classify) unavailable:", [Link]);
return null;
}
};

[Link] = { detectAnomaly, predictFailure, classifyLog };

STEP 13 — src/controllers/[Link]
Handles CRUD operations for logs.

const Log = require("../models/Log");


const catchAsync = require("../middleware/catchAsync");
const paginate = require("../utils/pagination");
const { getIO } = require("../config/socket");

// GET /api/logs
// Returns paginated logs. Supports ?page=1&limit=20&severity=ERROR
const getLogs = catchAsync(async (req, res) => {
// Build a filter from query params
const filter = {};
if ([Link]) [Link] = [Link];
if ([Link]) [Link] = [Link];

const result = await paginate(Log, [Link], filter);

[Link](200).json({ success: true, ...result });


});

// GET /api/logs/:id
const getLogById = catchAsync(async (req, res) => {
const log = await [Link]([Link]);

about:blank 11/24
5/17/26, 8:02 PM Untitled

if (!log) {
return [Link](404).json({ success: false, message: "Log not found" });
}

[Link](200).json({ success: true, data: log });


});

// POST /api/logs
// Called by the Python monitoring agent to push new logs
const createLog = catchAsync(async (req, res) => {
const { serviceName, severity, message } = [Link];

const log = await [Link]({ serviceName, severity, message });

// Emit the new log to all connected frontend clients in real time
try {
getIO().emit("new_log", log);
} catch (e) {
// Socket not critical — don't fail the request if it errors
}

[Link](201).json({ success: true, data: log });


});

// DELETE /api/logs/:id — Admin only


const deleteLog = catchAsync(async (req, res) => {
const log = await [Link]([Link]);

if (!log) {
return [Link](404).json({ success: false, message: "Log not found" });
}

[Link](200).json({ success: true, message: "Log deleted successfully" });


});

[Link] = { getLogs, getLogById, createLog, deleteLog };

STEP 14 — src/controllers/[Link]

Handles server hardware metrics (CPU, memory, disk).

const Metric = require("../models/Metric");


const catchAsync = require("../middleware/catchAsync");
const paginate = require("../utils/pagination");
const { getIO } = require("../config/socket");
const { detectAnomaly } = require("../ml/mlService");

about:blank 12/24
5/17/26, 8:02 PM Untitled

const Alert = require("../models/Alert");

// GET /api/metrics
// Supports filtering by ?serverId=server-01
const getMetrics = catchAsync(async (req, res) => {
const filter = {};
if ([Link]) [Link] = [Link];

const result = await paginate(Metric, [Link], filter);

[Link](200).json({ success: true, ...result });


});

// GET /api/metrics/server/:serverId
// Returns the latest metric reading for a specific server
const getLatestMetricByServer = catchAsync(async (req, res) => {
const metric = await [Link]({ serverId: [Link] }).sort({
timestamp: -1,
});

if (!metric) {
return res
.status(404)
.json({ success: false, message: "No metrics found for this server" });
}

[Link](200).json({ success: true, data: metric });


});

// POST /api/metrics
// Called by the Python monitoring agent every few seconds
const createMetric = catchAsync(async (req, res) => {
const { serverId, cpuUsage, memoryUsage, diskUsage } = [Link];

// Save the metric to MongoDB


const metric = await [Link]({ serverId, cpuUsage, memoryUsage, diskUsage });

// Emit to frontend for real-time dashboard update


try {
getIO().emit("new_metric", metric);
} catch (e) {}

// --- Simple threshold-based alerting ---


// If CPU usage is very high, create an alert automatically
if (cpuUsage > 90) {
const alert = await [Link]({
type: "CPU",
message: `High CPU usage detected on server ${serverId}: ${cpuUsage}%`,
severity: "CRITICAL",
});

about:blank 13/24
5/17/26, 8:02 PM Untitled

try {
getIO().emit("new_alert", alert);
} catch (e) {}
}

// --- ML-based anomaly detection (runs in background, non-blocking) ---


// We don't await this so it doesn't slow down the API response
detectAnomaly({ serverId, cpuUsage, memoryUsage, diskUsage })
.then((mlResult) => {
if (mlResult && [Link]) {
[Link]({
type: "ML_ANOMALY",
message: `ML anomaly detected on ${serverId}: ${[Link]}`,
severity: "WARNING",
}).then((alert) => {
try {
getIO().emit("new_alert", alert);
} catch (e) {}
});
}
})
.catch(() => {}); // Silently ignore ML errors

[Link](201).json({ success: true, data: metric });


});

[Link] = { getMetrics, getLatestMetricByServer, createMetric };

STEP 15 — src/controllers/[Link]

Handles alert retrieval and resolution.

const Alert = require("../models/Alert");


const catchAsync = require("../middleware/catchAsync");
const paginate = require("../utils/pagination");

// GET /api/alerts
// Supports ?resolved=false&severity=CRITICAL
const getAlerts = catchAsync(async (req, res) => {
const filter = {};

// Filter by resolved status — "false" string from query param needs conversion
if ([Link] !== undefined) {
[Link] = [Link] === "true";
}
if ([Link]) [Link] = [Link];

about:blank 14/24
5/17/26, 8:02 PM Untitled

const result = await paginate(Alert, [Link], filter);

[Link](200).json({ success: true, ...result });


});

// GET /api/alerts/:id
const getAlertById = catchAsync(async (req, res) => {
const alert = await [Link]([Link]);

if (!alert) {
return [Link](404).json({ success: false, message: "Alert not found" });
}

[Link](200).json({ success: true, data: alert });


});

// POST /api/alerts
// Manually create an alert (can also be triggered by metricController automatically)
const createAlert = catchAsync(async (req, res) => {
const { type, message, severity } = [Link];

const alert = await [Link]({ type, message, severity });

[Link](201).json({ success: true, data: alert });


});

// PATCH /api/alerts/:id/resolve
// Mark an alert as resolved (done investigating)
const resolveAlert = catchAsync(async (req, res) => {
const alert = await [Link](
[Link],
{ resolved: true },
{ new: true } // Return the updated document
);

if (!alert) {
return [Link](404).json({ success: false, message: "Alert not found" });
}

[Link](200).json({ success: true, data: alert });


});

[Link] = { getAlerts, getAlertById, createAlert, resolveAlert };

STEP 16 — src/controllers/[Link]
Calls the ML service and saves predictions to MongoDB.

about:blank 15/24
5/17/26, 8:02 PM Untitled

const Prediction = require("../models/Prediction");


const catchAsync = require("../middleware/catchAsync");
const paginate = require("../utils/pagination");
const { detectAnomaly, predictFailure } = require("../ml/mlService");

// GET /api/predictions
// Supports ?serverId=server-01&predictionType=anomaly
const getPredictions = catchAsync(async (req, res) => {
const filter = {};
if ([Link]) [Link] = [Link];
if ([Link]) [Link] = [Link];

const result = await paginate(Prediction, [Link], filter);

[Link](200).json({ success: true, ...result });


});

// POST /api/predictions/analyze
// Manually trigger an ML analysis for a server
// Body: { serverId, cpuUsage, memoryUsage, diskUsage, predictionType }
const analyzeServer = catchAsync(async (req, res) => {
const { serverId, cpuUsage, memoryUsage, diskUsage, predictionType } = [Link];

if (!serverId || !predictionType) {
return [Link](400).json({
success: false,
message: "serverId and predictionType are required",
});
}

const metricData = { serverId, cpuUsage, memoryUsage, diskUsage };

let mlResult = null;

// Call the correct ML function based on prediction type


if (predictionType === "anomaly") {
mlResult = await detectAnomaly(metricData);
} else if (predictionType === "failure") {
mlResult = await predictFailure(metricData);
} else {
return [Link](400).json({
success: false,
message: "predictionType must be 'anomaly' or 'failure'",
});
}

// ML service was unavailable


if (!mlResult) {
return [Link](503).json({

about:blank 16/24
5/17/26, 8:02 PM Untitled

success: false,
message: "ML service is currently unavailable. Please try again later.",
});
}

// Save the prediction result to the database


const prediction = await [Link]({
serverId,
predictionType,
result: [Link] || "UNKNOWN",
confidence: [Link] || 0,
details: mlResult,
});

[Link](201).json({ success: true, data: prediction });


});

[Link] = { getPredictions, analyzeServer };

STEP 17 — src/routes/[Link]

const express = require("express");


const router = [Link]();
const {
registerUserController,
loginUserController,
logoutUserController,
getMeController,
} = require("../controllers/authController");
const { protect } = require("../middleware/authMiddleware");

// Public routes (no authentication required)


[Link]("/register", registerUserController);
[Link]("/login", loginUserController);

// Protected routes (must be logged in)


[Link]("/logout", protect, logoutUserController);
[Link]("/me", protect, getMeController);

[Link] = router;

STEP 18 — src/routes/[Link]

const express = require("express");


const router = [Link]();

about:blank 17/24
5/17/26, 8:02 PM Untitled

const {
getLogs,
getLogById,
createLog,
deleteLog,
} = require("../controllers/logController");
const { protect, authorize } = require("../middleware/authMiddleware");

// All log routes require authentication


[Link](protect);

[Link]("/").get(getLogs).post(createLog);

router
.route("/:id")
.get(getLogById)
.delete(authorize("Admin"), deleteLog); // Only Admins can delete logs

[Link] = router;

STEP 19 — src/routes/[Link]

const express = require("express");


const router = [Link]();
const {
getMetrics,
getLatestMetricByServer,
createMetric,
} = require("../controllers/metricController");
const { protect } = require("../middleware/authMiddleware");

[Link](protect);

[Link]("/").get(getMetrics).post(createMetric);

// Must come BEFORE /:id to avoid "latest" being treated as an ID


[Link]("/server/:serverId", getLatestMetricByServer);

[Link] = router;

STEP 20 — src/routes/[Link]

const express = require("express");


const router = [Link]();
const {

about:blank 18/24
5/17/26, 8:02 PM Untitled

getAlerts,
getAlertById,
createAlert,
resolveAlert,
} = require("../controllers/alertController");
const { protect } = require("../middleware/authMiddleware");

[Link](protect);

[Link]("/").get(getAlerts).post(createAlert);
[Link]("/:id").get(getAlertById);
[Link]("/:id/resolve", resolveAlert);

[Link] = router;

STEP 21 — src/routes/[Link]

const express = require("express");


const router = [Link]();
const {
getPredictions,
analyzeServer,
} = require("../controllers/predictionController");
const { protect } = require("../middleware/authMiddleware");

[Link](protect);

[Link]("/", getPredictions);
[Link]("/analyze", analyzeServer);

[Link] = router;

STEP 22 — src/[Link]

Sets up the Express app with all middleware and routes.


[Link] configures the app; [Link] actually starts it.
Keeping them separate makes testing easier later.

const express = require("express");


const cors = require("cors");
const cookieParser = require("cookie-parser");

// Import routes
const authRoutes = require("./routes/authRoutes");
const logRoutes = require("./routes/logRoutes");
about:blank 19/24
5/17/26, 8:02 PM Untitled

const metricRoutes = require("./routes/metricRoutes");


const alertRoutes = require("./routes/alertRoutes");
const predictionRoutes = require("./routes/predictionRoutes");

// Import error handler


const errorMiddleware = require("./middleware/errorMiddleware");

const app = express();

// ---- Global Middleware ----

// Allow requests from your React frontend


[Link](
cors({
origin: [Link].CLIENT_URL || "[Link]
credentials: true, // Required to send/receive cookies cross-origin
})
);

[Link]([Link]()); // Parse incoming JSON request bodies


[Link](cookieParser()); // Parse cookies (needed to read the JWT token cookie)

// ---- Routes ----


[Link]("/api/auth", authRoutes);
[Link]("/api/logs", logRoutes);
[Link]("/api/metrics", metricRoutes);
[Link]("/api/alerts", alertRoutes);
[Link]("/api/predictions", predictionRoutes);

// ---- Health Check ----


// Simple route to verify the API is running
[Link]("/api/health", (req, res) => {
[Link](200).json({ success: true, message: "API is running 🚀" });
});

// ---- 404 Handler ----


// Catches any route that doesn't match the ones above
[Link]((req, res) => {
[Link](404).json({ success: false, message: `Route ${[Link]} not found` });
});

// ---- Global Error Handler ----


// Must be LAST — Express identifies error handlers by having 4 parameters (err, req, res, next)
[Link](errorMiddleware);

[Link] = app;

STEP 23 — src/[Link]
about:blank 20/24
5/17/26, 8:02 PM Untitled

The entry point. Loads environment variables, connects to DB, starts HTTP server, and
attaches [Link].

const http = require("http");


require("dotenv").config(); // Load .env variables FIRST before importing anything else

const app = require("./app");


const connectDB = require("./config/db");
const { initSocket } = require("./config/socket");

const PORT = [Link] || 5000;

// Create an HTTP server from the Express app


// (We need the raw [Link] to attach [Link])
const server = [Link](app);

// Attach [Link] to the server


initSocket(server);

// Connect to MongoDB, then start the server


connectDB().then(() => {
[Link](PORT, () => {
[Link](`🚀 Server running in ${[Link].NODE_ENV} mode on port ${PORT}`);
});
});

// Handle unexpected crashes gracefully


[Link]("unhandledRejection", (err) => {
[Link]("❌ Unhandled Promise Rejection:", [Link]);
[Link](() => [Link](1));
});

STEP 24 — Dockerfile

Packages the [Link] backend into a Docker container.

# Use an official lightweight [Link] image


FROM node:20-alpine

# Set the working directory inside the container


WORKDIR /app

# Copy package files first (Docker caches this layer — speeds up rebuilds)
COPY package*.json ./

# Install only production dependencies


RUN npm install --production

about:blank 21/24
5/17/26, 8:02 PM Untitled

# Copy the rest of the source code


COPY . .

# The port your app listens on (must match .env PORT)


EXPOSE 5000

# Start the application


CMD ["node", "src/[Link]"]

✅ Final File Checklist


Build in this order and you won't hit any import errors:

# File Status

1 [Link] ✅ Create

2 .env ✅ Create

3 src/config/[Link] ✅ Create

4 src/config/[Link] ✅ Create

5 src/models/[Link] 🔁 Already exists

6 src/models/[Link] 🔁 Already exists

7 src/models/[Link] 🔁 Already exists

8 src/models/[Link] 🔁 Already exists

9 src/models/[Link] 🔁 Already exists — keep as-is

10 src/models/[Link] ✅ Create

11 src/utils/[Link] ✅ Create

12 src/utils/[Link] ✅ Create

13 src/utils/[Link] ✅ Create

14 src/middleware/[Link] 🔁 Already exists

15 src/middleware/[Link] ✅ Create

about:blank 22/24
5/17/26, 8:02 PM Untitled

# File Status

16 src/middleware/[Link] ✅ Create (replaces old one)

17 src/ml/[Link] ✅ Create

18 src/controllers/[Link] 🔁 Already exists

19 src/controllers/[Link] ✅ Create

20 src/controllers/[Link] ✅ Create

21 src/controllers/[Link] ✅ Create

22 src/controllers/[Link] ✅ Create

23 src/routes/[Link] ✅ Create

24 src/routes/[Link] ✅ Create

25 src/routes/[Link] ✅ Create

26 src/routes/[Link] ✅ Create

27 src/routes/[Link] ✅ Create

28 src/[Link] ✅ Create

29 src/[Link] ✅ Create

30 Dockerfile ✅ Create

🔑 Key Concepts to Understand


Why [Link] and [Link] are separate: [Link] configures Express (routes, middleware). [Link]
starts the actual HTTP server. This separation means you can import app in tests without actually
binding to a port.

Why [Link] wraps the HTTP server: [Link] needs the raw [Link] object, not the Express
app, so it can handle the WebSocket upgrade handshake.

Why detectAnomaly() isn't awaited in metricController : ML inference can be slow. By not awaiting
it, the metric is saved to MongoDB and the API responds immediately. The ML check runs in parallel.
This pattern is called "fire and forget."

about:blank 23/24
5/17/26, 8:02 PM Untitled

Why paginate() uses [Link] : Running the data query and the count query in parallel (instead
of one after the other) cuts the response time in half.

about:blank 24/24

You might also like