๐Ÿš€ Self-Learning Roadmap

Node.js
Mastery Plan

4 Weeks ยท 5 Days/Week ยท 1โ€“2 Hours Daily

20Study Days
3Mini Projects
1Capstone
4Weeks
Before You Start

Required Tools

  • Node.js (runtime)
  • VS Code (editor)
  • MongoDB + Compass
  • Postman (API testing)

Verify Install

Open your terminal and run:

node -v
npm -v

Both should print version numbers.

โšก Learning Rules

1
Follow one day at a time
Don't jump ahead. Each day builds on the previous.
2
Do not skip practice
Reading is not enough. You must write and run every example.
3
Always run your code
Even if you think it works, run it. See the actual output.
4
Debug errors yourself โ€” this is crucial
Read the error message. Google it. Try to fix it. Only ask for help after 20 minutes of trying.
Days 01โ€“05

Week 1 โ€” JavaScript Fundamentals

Build a strong JavaScript foundation required for backend development
JS BASICS
DAY 01 Setup + First Program โ–ผ
What is Node.js Running JS outside browser Terminal basics
What is Node.js?
Node.js is a JavaScript runtime built on Chrome's V8 engine. Before Node.js, JavaScript could only run inside a web browser. Node allows you to run JavaScript on your computer โ€” which means you can use it to build servers, APIs, command-line tools, and much more.

Think of it this way: Browser JavaScript controls web pages. Node.js JavaScript controls your server and computer.
How to create and run a file
1. Open VS Code, create a new folder called node-practice
2. Inside it, create a file called app.js
3. Open the integrated terminal in VS Code (Ctrl + `)
4. Run your file with node app.js
app.js
// console.log() prints output to the terminal
console.log("Hello Node.js");

// You can log any type of value
console.log(42);
console.log(true);
console.log([1, 2, 3]);
Expected Output: When you run node app.js, you should see Hello Node.js printed in the terminal. If you see an error, make sure Node.js is installed properly.
โœ๏ธ Your Task
  • Print your name using console.log()
  • Print your age and city on separate lines
  • Try printing a number and a boolean too
DAY 02 Variables & Data Types โ–ผ
var vs let vs const String Number Boolean null & undefined
var vs let vs const โ€” What's the Difference?
var โ€” Old style. Avoid using it. Has confusing scoping rules.

let โ€” Use for values that will change over time. For example: a counter, a user's score, a loop variable.

const โ€” Use for values that should never change. For example: a user's name after it's set, a configuration value. This is what you'll use most often.
variables.js
// String: text wrapped in quotes
const name = "Hafeez";

// Number: integers or decimals
let age = 22;
let height = 5.9;

// Boolean: true or false only
let isDeveloper = true;

// null: intentionally empty
let middleName = null;

// undefined: declared but no value yet
let country;

console.log(name, age, height, isDeveloper);
console.log(typeof name);     // "string"
console.log(typeof age);      // "number"
console.log(typeof isDeveloper); // "boolean"
โœ๏ธ Your Task
  • Create 5 variables: name, age, city, isStudent, gpa
  • Print them all using console.log()
  • Use typeof to check what type each variable is
  • Try changing a const โ€” what error do you see?
DAY 03 Functions & Conditions โ–ผ
Function declaration Arrow functions Parameters & return if / else if / else
Why Functions?
Functions let you wrap a block of code and reuse it without rewriting it. Instead of writing the same 10 lines in 5 places, you write a function once and call it 5 times.

Parameters are inputs your function receives. return is the output it gives back.
functions.js
// Traditional function declaration
function checkAge(age) {
  if (age >= 18) {
    console.log("Adult โœ“");
  } else if (age >= 13) {
    console.log("Teenager");
  } else {
    console.log("Child");
  }
}

checkAge(20);  // Adult โœ“
checkAge(15);  // Teenager
checkAge(8);   // Child

// Arrow function (modern syntax) โ€” same thing, shorter
const greet = (name) => {
  return `Hello, ${name}!`;
};
console.log(greet("John")); // Hello, John!
โœ๏ธ Your Task
  • Create a function checkEvenOdd(number) that prints "Even" or "Odd"
  • Create a function getGrade(score) that prints A/B/C/D/F based on the score
  • Rewrite both using arrow function syntax
DAY 04 Arrays & Loops โ–ผ
Arrays for loop forEach map / filter push / pop
Arrays โ€” Storing Multiple Values
An array is a list of values stored in a single variable. You access items by their index, which starts at 0. Arrays are the most common data structure you'll use in backend development โ€” for example, a list of users, products, or orders.
arrays.js
const users = ["John", "Sarah", "Tom", "Priya"];

// Access by index (starts at 0)
console.log(users[0]); // John

// for loop โ€” classic way
for (let i = 0; i < users.length; i++) {
  console.log(i + 1, users[i]);
}

// forEach โ€” modern, cleaner
users.forEach((user, index) => {
  console.log(`${index + 1}. ${user}`);
});

// map โ€” create a new array by transforming each item
const upperUsers = users.map(u => u.toUpperCase());

// filter โ€” keep only items that match a condition
const numbers = [1, 2, 3, 4, 5, 6];
const evens = numbers.filter(n => n % 2 === 0); // [2, 4, 6]

// Adding/removing items
users.push("Alex");   // add to end
users.pop();           // remove from end
โœ๏ธ Your Task
  • Create an array of 5 Indian cities and print them with forEach
  • Filter the array to show only cities with more than 5 characters
  • Use map to create a new array where each city is in UPPERCASE
  • Add and remove a city using push and pop
DAY 05 Objects & Classes โ–ผ
Objects Properties & Methods Classes Constructor this keyword
Objects vs Classes
An object is a collection of key-value pairs. It represents a "thing" with properties. A class is like a blueprint for creating multiple objects that have the same structure. When you call new User(), the class creates a fresh object with all the defined properties and methods.
objects.js
// Plain object
const user = {
  name: "Sarah",
  age: 25,
  city: "Bangalore",
  greet() {
    console.log(`Hi I'm ${this.name}`);
  }
};
user.greet();

// Class โ€” blueprint for multiple users
class User {
  constructor(name, age, city) {
    this.name = name;
    this.age = age;
    this.city = city;
  }

  introduce() {
    console.log(`Hi, I'm ${this.name}, ${this.age} years old from ${this.city}`);
  }
}

const user1 = new User("John", 25, "Mumbai");
const user2 = new User("Priya", 22, "Delhi");

user1.introduce();
user2.introduce();
โœ๏ธ Your Task
  • Create a Student class with: name, age, grade, school properties
  • Add a method study() that prints "[name] is studying"
  • Create 3 student instances and call study() on each
Days 06โ€“10

Week 2 โ€” Async JavaScript + Node

Understand asynchronous behavior and Node.js core modules
ASYNC + NODE
DAY 06 Callbacks โ–ผ
Callbacks setTimeout Asynchronous execution
What is Asynchronous Code?
Normal code runs line by line โ€” one after another. But some operations take time (reading a file, calling an API, waiting for a database). You don't want your program to freeze and wait.

A callback is a function you pass to another function, and it gets called when the slow operation finishes. This lets your program keep running while waiting.
callbacks.js
// setTimeout simulates a delayed operation (like a DB call)
function fetchData(callback) {
  console.log("Fetching data...");
  setTimeout(() => {
    // This runs after 1 second
    callback("Data received!");
  }, 1000);
}

fetchData((data) => {
  console.log(data); // Data received!
});
console.log("This runs immediately"); // Prints before callback!
Key Insight: "This runs immediately" prints BEFORE "Data received!" โ€” even though it's written after. This is asynchronous behavior.
โœ๏ธ Your Task
  • Create a function greetLater(name, callback) that waits 2 seconds then calls callback with a greeting message
  • Call it and print the greeting when ready
DAY 07 Promises โ–ผ
Promise resolve / reject .then() / .catch() Promise chaining
Why Promises? Solving "Callback Hell"
Callbacks get messy when you need to do multiple async things in sequence (callback inside callback inside callback...). Promises are a cleaner way to handle async code.

A Promise is an object that represents a future value. It's either pending, resolved (success), or rejected (failure).
promises.js
// Creating a promise
const fetchUser = new Promise((resolve, reject) => {
  setTimeout(() => {
    const success = true;
    if (success) {
      resolve({ name: "John", age: 25 });
    } else {
      reject("User not found");
    }
  }, 1000);
});

// Using the promise
fetchUser
  .then((user) => {
    console.log("Got user:", user);
    return user.name; // chain to next .then()
  })
  .then((name) => {
    console.log("Name is:", name);
  })
  .catch((err) => {
    console.log("Error:", err);
  });
โœ๏ธ Your Task
  • Create a promise that resolves with "Login successful" after 2 seconds
  • Create another that randomly resolves or rejects
  • Handle both .then() and .catch()
DAY 08 Async / Await โ–ผ
async function await keyword try / catch fetch API
async/await โ€” Promises Made Beautiful
async/await is just a cleaner way to write Promise code. Instead of chaining .then(), you write async code that looks synchronous but behaves asynchronously. It's the modern standard โ€” you'll use this constantly when building APIs.
async-await.js
// Mark the function as async
async function getData() {
  return "Hello from async";
}

async function main() {
  const data = await getData(); // wait for it
  console.log(data);
}
main();

// Real-world: fetching from an API
async function fetchJoke() {
  try {
    const response = await fetch("https://official-joke-api.appspot.com/random_joke");
    const joke = await response.json();
    console.log(joke.setup);
    console.log(joke.punchline);
  } catch (err) {
    console.log("Failed to fetch:", err.message);
  }
}
fetchJoke();
โœ๏ธ Your Task
  • Fetch data from a free API (try: https://jsonplaceholder.typicode.com/users/1)
  • Print the user's name and email from the response
  • Wrap in try/catch to handle network errors
DAY 09 The Event Loop โ–ผ
Call Stack Event Queue Non-blocking I/O Single-threaded
How Node.js Handles Thousands of Requests
Node.js is single-threaded โ€” it can only do one thing at a time. But it handles massive traffic. How?

The Call Stack runs your JavaScript code. When it hits something slow (like a file read or API call), it hands it off to the background, and keeps running other code. When the slow thing finishes, the Event Queue puts the callback back in line.

The Event Loop constantly checks: "Is the call stack empty? If yes, pick the next callback from the queue."
event-loop.js
console.log("1 โ€” Start");          // Runs first

setTimeout(() => {
  console.log("3 โ€” Timeout");       // Runs last (queued)
}, 0);

Promise.resolve().then(() => {
  console.log("2 โ€” Promise");      // Runs before timeout
});

console.log("1 โ€” End");            // Runs second

// Output order: Start โ†’ End โ†’ Promise โ†’ Timeout
Concept to understand: Even with 0ms delay, setTimeout runs after Promise. This is because Promises use the "microtask queue" which has higher priority than the regular task queue.
โœ๏ธ Your Task
  • Run the code above and observe the output order
  • Watch this video: "What the heck is the event loop anyway?" by Philip Roberts on YouTube
  • Draw a diagram of how the call stack and event queue work
DAY 10 Node.js HTTP Module โ–ผ
http module createServer req / res Routes JSON response
Building Your First Server
Node.js has a built-in http module that lets you create web servers without installing anything extra. The server listens on a port (like 3000) and handles incoming HTTP requests.

req = request (what the client sent). res = response (what you send back).
server.js
const http = require("http");

const server = http.createServer((req, res) => {
  // Set response headers
  res.setHeader("Content-Type", "application/json");

  // Route handling
  if (req.url === "/") {
    res.statusCode = 200;
    res.end(JSON.stringify({ message: "Welcome to my server!" }));

  } else if (req.url === "/users") {
    res.statusCode = 200;
    res.end(JSON.stringify([
      { name: "John" },
      { name: "Sarah" }
    ]));

  } else {
    res.statusCode = 404;
    res.end(JSON.stringify({ error: "Route not found" }));
  }
});

server.listen(3000, () => {
  console.log("Server running on http://localhost:3000");
});
โœ๏ธ Your Task
  • Add a /about route that returns your name and bio as JSON
  • Add a /products route returning a list of 3 products
  • Open Postman and test all your routes
  • Check what happens when you visit a route that doesn't exist
๐Ÿ—๏ธ Mini Project 01

Basic HTTP Server

Build a Node.js HTTP server from scratch using only the built-in http module โ€” no Express yet. This reinforces everything from Week 2.

Days 11โ€“15

Week 3 โ€” Express & APIs

Build clean REST APIs using the Express framework
EXPRESS APIs
DAY 11 Express Setup โ–ผ
npm init npm install require express app.listen()
Why Express instead of raw http?
The built-in http module works but is very low-level and verbose. Express is a popular framework that wraps http with useful tools: easier routing, middleware support, cleaner syntax. It's the most widely used Node.js framework in production.
terminal
# Create a new project
mkdir my-api && cd my-api
npm init -y         # creates package.json
npm install express # installs express
index.js
const express = require("express");
const app = express();

// Middleware to parse JSON request bodies
app.use(express.json());

// GET route โ€” home
app.get("/", (req, res) => {
  res.json({ message: "Hello from Express!" });
});

// Start the server
app.listen(3000, () => {
  console.log("Server started on port 3000");
});
โœ๏ธ Your Task
  • Initialize a new Node project with npm init -y
  • Install Express and create an index.js with the code above
  • Run with: node index.js
  • Visit http://localhost:3000 in your browser and in Postman
DAY 12 Routing โ–ผ
GET / POST / PUT / DELETE Route parameters Query strings Express Router
HTTP Methods and What They Mean
GET โ€” Retrieve data (read-only, no body)
POST โ€” Create new data (send body with new item)
PUT/PATCH โ€” Update existing data
DELETE โ€” Remove data

Route params like /users/:id let you capture dynamic values from the URL.
routes.js
// Route parameter โ€” :id is dynamic
app.get("/users/:id", (req, res) => {
  const id = req.params.id; // e.g. /users/42 โ†’ "42"
  res.json({ message: `Getting user ${id}` });
});

// Query string โ€” /search?name=john&city=mumbai
app.get("/search", (req, res) => {
  const { name, city } = req.query;
  res.json({ name, city });
});

// POST โ€” receive data in req.body
app.post("/users", (req, res) => {
  const { name, email } = req.body;
  res.status(201).json({ 
    message: "User created", 
    user: { name, email } 
  });
});
โœ๏ธ Your Task
  • Add GET /products and GET /products/:id routes
  • Test with Postman: what happens with different IDs?
  • Add a search route that filters by a query param
DAY 13 Middleware โ–ผ
app.use() next() Request logging Custom middleware
What is Middleware?
Middleware is a function that runs between the incoming request and your route handler. It can read/modify the request, add data, log info, or stop the request entirely (like an auth check).

Every middleware function receives req, res, and next. Call next() to continue to the next middleware or route.
middleware.js
// Built-in middleware
app.use(express.json()); // parse JSON bodies

// Custom middleware โ€” logger
const logger = (req, res, next) => {
  console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
  next(); // must call next or request hangs
};
app.use(logger);

// Auth middleware โ€” blocks unauthorized requests
const requireAuth = (req, res, next) => {
  const token = req.headers["authorization"];
  if (!token) {
    return res.status(401).json({ error: "Unauthorized" });
  }
  next(); // token exists, continue
};

// Apply auth middleware to a specific route
app.get("/dashboard", requireAuth, (req, res) => {
  res.json({ message: "Welcome to dashboard" });
});
โœ๏ธ Your Task
  • Create a logger middleware that prints method, URL, and timestamp
  • Create an auth middleware that checks for an "x-api-key" header
  • Apply it to a protected route and test with/without the header
DAY 14 CRUD API (In-Memory) โ–ผ
Create (POST) Read (GET) Update (PUT) Delete (DELETE) Array as DB
CRUD โ€” The Core of Every API
Almost every backend API is just CRUD. Whether you're building a social media app, e-commerce, or banking system โ€” it all boils down to Create, Read, Update, Delete. Today you'll build a full CRUD API using a JavaScript array as a temporary "database."
crud-api.js
let users = []; // temporary in-memory store
let nextId = 1;

// CREATE โ€” POST /users
app.post("/users", (req, res) => {
  const user = { id: nextId++, ...req.body };
  users.push(user);
  res.status(201).json(user);
});

// READ ALL โ€” GET /users
app.get("/users", (req, res) => {
  res.json(users);
});

// READ ONE โ€” GET /users/:id
app.get("/users/:id", (req, res) => {
  const user = users.find(u => u.id === Number(req.params.id));
  if (!user) return res.status(404).json({ error: "Not found" });
  res.json(user);
});

// UPDATE โ€” PUT /users/:id
app.put("/users/:id", (req, res) => {
  const index = users.findIndex(u => u.id === Number(req.params.id));
  if (index === -1) return res.status(404).json({ error: "Not found" });
  users[index] = { ...users[index], ...req.body };
  res.json(users[index]);
});

// DELETE โ€” DELETE /users/:id
app.delete("/users/:id", (req, res) => {
  users = users.filter(u => u.id !== Number(req.params.id));
  res.json({ message: "Deleted successfully" });
});
โœ๏ธ Your Task
  • Implement all 5 routes above in one file
  • Test all of them in Postman (create, read, update, delete)
  • What happens when you restart the server? (data is lost โ€” this is why we need a DB)
DAY 15 Error Handling โ–ผ
Error middleware HTTP status codes try/catch in routes Validation
Why Error Handling Matters
Without error handling, one crash in your code takes down the entire server. A well-built API always catches errors gracefully and returns meaningful error responses โ€” never exposing raw stack traces to clients.

Common HTTP Status Codes: 200 OK, 201 Created, 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found, 500 Server Error
error-handling.js
// Async route with try/catch
app.post("/users", async (req, res, next) => {
  try {
    const { name, email } = req.body;
    // Basic validation
    if (!name || !email) {
      return res.status(400).json({ error: "Name and email required" });
    }
    // ... create user logic
    res.status(201).json({ message: "Created" });
  } catch (err) {
    next(err); // pass to error middleware
  }
});

// Global error handler โ€” must have 4 params
app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).json({
    error: "Something went wrong",
    message: err.message
  });
});

// 404 handler โ€” add AFTER all routes
app.use((req, res) => {
  res.status(404).json({ error: "Route not found" });
});
โœ๏ธ Your Task
  • Add input validation to your POST /users route
  • Add the global error handler to your app
  • Add a 404 handler at the bottom
  • Test by sending bad data and visiting non-existent routes in Postman
๐Ÿ—๏ธ Mini Project 02

Full User CRUD API

Build a complete REST API for managing users using Express. Data stays in memory for now โ€” but the API structure should be production-quality.

Days 16โ€“20

Week 4 โ€” MongoDB & Auth

Connect a real database and secure your APIs with authentication
DB + AUTH
DAY 16 MongoDB Connection โ–ผ
MongoDB Mongoose Connection string Collections
MongoDB โ€” A NoSQL Database
MongoDB stores data as documents (like JSON objects) inside collections (like folders). Unlike SQL databases with rigid tables and rows, MongoDB is flexible โ€” each document can have different fields.

Mongoose is an npm package that makes working with MongoDB in Node.js easier. It provides schema validation, models, and a clean API.
terminal + db.js
# Install mongoose
npm install mongoose
db.js
const mongoose = require("mongoose");

const connectDB = async () => {
  try {
    await mongoose.connect("mongodb://127.0.0.1:27017/myapp");
    console.log("MongoDB connected โœ“");
  } catch (err) {
    console.log("Connection failed:", err.message);
    process.exit(1); // stop the server if DB fails
  }
};

module.exports = connectDB;

// In your index.js, call it:
// const connectDB = require("./db");
// connectDB();
โœ๏ธ Your Task
  • Make sure MongoDB is running locally (open MongoDB Compass to check)
  • Create a db.js file with the connection logic above
  • Connect in index.js and confirm "MongoDB connected" prints on startup
DAY 17 Schema & Model โ–ผ
mongoose.Schema mongoose.model Validation Timestamps
Schema = Blueprint for Your Data
Even though MongoDB is flexible, Mongoose lets you define a schema โ€” the expected structure and types for your documents. This gives you validation so you can't accidentally save bad data. A model is the class you use to create and query documents.
models/User.js
const mongoose = require("mongoose");

const userSchema = new mongoose.Schema({
  name: {
    type: String,
    required: [true, "Name is required"],
    trim: true
  },
  email: {
    type: String,
    required: [true, "Email is required"],
    unique: true,
    lowercase: true
  },
  age: {
    type: Number,
    min: 0,
    max: 120
  },
  role: {
    type: String,
    enum: ["user", "admin"],
    default: "user"
  }
}, { timestamps: true }); // adds createdAt, updatedAt

const User = mongoose.model("User", userSchema);
module.exports = User;
โœ๏ธ Your Task
  • Create a models/ folder and User.js inside it
  • Create a Product model with: name (required), price (required), stock, category
  • Add { timestamps: true } to both models
DAY 18 CRUD with MongoDB โ–ผ
Model.create() Model.find() Model.findById() findByIdAndUpdate findByIdAndDelete
Now Your Data Persists!
This is the same CRUD from Week 3 โ€” but now data is stored in MongoDB and survives server restarts. All Mongoose methods return Promises, so use async/await throughout.
routes/users.js
const User = require("../models/User");

// CREATE
app.post("/users", async (req, res) => {
  try {
    const user = await User.create(req.body);
    res.status(201).json(user);
  } catch (err) {
    res.status(400).json({ error: err.message });
  }
});

// READ ALL
app.get("/users", async (req, res) => {
  const users = await User.find().sort({ createdAt: -1 });
  res.json(users);
});

// UPDATE
app.put("/users/:id", async (req, res) => {
  const user = await User.findByIdAndUpdate(
    req.params.id, 
    req.body,
    { new: true, runValidators: true }
  );
  if (!user) return res.status(404).json({ error: "Not found" });
  res.json(user);
});

// DELETE
app.delete("/users/:id", async (req, res) => {
  await User.findByIdAndDelete(req.params.id);
  res.json({ message: "Deleted" });
});
โœ๏ธ Your Task
  • Connect your Week 3 CRUD API to MongoDB using your User model
  • Test all routes in Postman โ€” data should survive server restarts
  • Open MongoDB Compass and see your data appear in real time
DAY 19 Authentication (JWT + bcrypt) โ–ผ
Password hashing bcrypt JWT tokens Protected routes Bearer token
How Authentication Works
Step 1 โ€” Register: User sends password โ†’ you hash it with bcrypt โ†’ store the hash (NEVER store plain passwords)

Step 2 โ€” Login: User sends password โ†’ compare with stored hash using bcrypt โ†’ if match, generate a JWT token

Step 3 โ€” Protected routes: User sends JWT token in headers โ†’ verify the token โ†’ if valid, allow access
auth.js
const bcrypt = require("bcrypt");
const jwt = require("jsonwebtoken");

const JWT_SECRET = "your-secret-key-change-this";

// REGISTER
app.post("/register", async (req, res) => {
  const { name, email, password } = req.body;
  const hashedPassword = await bcrypt.hash(password, 10);
  const user = await User.create({ name, email, password: hashedPassword });
  res.status(201).json({ message: "Registered successfully" });
});

// LOGIN
app.post("/login", async (req, res) => {
  const { email, password } = req.body;
  const user = await User.findOne({ email });
  if (!user) return res.status(401).json({ error: "Invalid credentials" });

  const isMatch = await bcrypt.compare(password, user.password);
  if (!isMatch) return res.status(401).json({ error: "Invalid credentials" });

  const token = jwt.sign({ userId: user._id }, JWT_SECRET, { expiresIn: "7d" });
  res.json({ token });
});

// AUTH MIDDLEWARE
const protect = (req, res, next) => {
  const token = req.headers.authorization?.split(" ")[1]; // "Bearer TOKEN"
  if (!token) return res.status(401).json({ error: "No token" });
  try {
    req.user = jwt.verify(token, JWT_SECRET);
    next();
  } catch {
    res.status(401).json({ error: "Invalid token" });
  }
};

// PROTECTED ROUTE
app.get("/me", protect, async (req, res) => {
  const user = await User.findById(req.user.userId).select("-password");
  res.json(user);
});
โœ๏ธ Your Task
  • Install: npm install jsonwebtoken bcrypt
  • Build register and login routes
  • Create a /me route protected by the JWT middleware
  • Test the full flow in Postman: register โ†’ login โ†’ use token โ†’ get /me
DAY 20 Review & Polish โ–ผ
Code cleanup Environment variables Folder structure API testing
Production-Ready Practices
Before calling a project done, production developers always: remove console.log debugging, move secrets to .env files, organize code into proper folders, and test all edge cases. Today, apply these to everything you've built.
Recommended Folder Structure
my-api/
โ”œโ”€โ”€ models/
โ”‚   โ””โ”€โ”€ User.js
โ”œโ”€โ”€ routes/
โ”‚   โ”œโ”€โ”€ auth.js
โ”‚   โ””โ”€โ”€ users.js
โ”œโ”€โ”€ middleware/
โ”‚   โ””โ”€โ”€ protect.js
โ”œโ”€โ”€ db.js
โ”œโ”€โ”€ .env             # secrets (never commit)
โ”œโ”€โ”€ .gitignore       # add .env and node_modules
โ””โ”€โ”€ index.js         # entry point
.env + dotenv usage
# .env file
JWT_SECRET=supersecretkey123
MONGODB_URI=mongodb://127.0.0.1:27017/myapp
PORT=3000
usage in index.js
npm install dotenv

// At the very top of index.js:
require("dotenv").config();

// Then use them as:
console.log(process.env.JWT_SECRET);
โœ๏ธ Your Task
  • Reorganize your project into the folder structure above
  • Move all secrets to .env and use dotenv
  • Remove all unnecessary console.log statements
  • Test every single route one more time in Postman
๐Ÿ—๏ธ Mini Project 03

Auth System API

Build a complete authentication system backed by MongoDB. This is the foundation of every real-world application.

๐Ÿ Final Project

Capstone: Complete Backend

Put everything together. Build a production-ready backend system with all the features you've learned.

๐Ÿ”
Authentication
โšก
CRUD APIs
๐Ÿ›’
Orders System
๐Ÿ’ณ
Payments Logic
๐Ÿ‘‘
Admin APIs
๐Ÿ—„๏ธ
MongoDB
After Completing This Plan

You Will Be Able To

  • Build REST APIs from scratch
  • Use MongoDB with Mongoose
  • Implement JWT authentication
  • Structure production-ready code
  • Debug errors independently

Tech Stack Mastered

  • Node.js + Express
  • MongoDB + Mongoose
  • JWT + bcrypt
  • Postman for testing
  • dotenv + folder structure
Next Steps After Week 4
๐Ÿ—๏ธ

MVC Architecture

Separate your code into Models, Views, and Controllers for cleaner, scalable apps.

โšก

Redis Caching

Speed up your APIs by caching frequently requested data in memory.

๐Ÿš€

Cloud Deployment

Deploy your backend to AWS, GCP, or Railway so the world can use your APIs.

๐Ÿ”จ

Build Real Projects

Apply everything to real-world apps: e-commerce backends, social platforms, SaaS APIs.