0% found this document useful (0 votes)
3 views16 pages

MERN Complete Setup Guide

This document provides a comprehensive step-by-step setup guide for a MERN stack task manager application, covering both frontend and backend configurations. It details the technologies used, installation of required packages, configuration of Tailwind CSS, TypeScript path aliases, and the structure of the backend with Express and MongoDB. Additionally, it includes code snippets for server setup, database connection, authentication, and task management functionalities.

Uploaded by

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

MERN Complete Setup Guide

This document provides a comprehensive step-by-step setup guide for a MERN stack task manager application, covering both frontend and backend configurations. It details the technologies used, installation of required packages, configuration of Tailwind CSS, TypeScript path aliases, and the structure of the backend with Express and MongoDB. Additionally, it includes code snippets for server setup, database connection, authentication, and task management functionalities.

Uploaded by

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

MERN Stack Task Manager

Complete Step-by-Step Setup Guide


Frontend + Backend + Architecture + All Commands

PART 1 — FRONTEND SETUP


Tech: React + TypeScript + Vite + Tailwind CSS + Shadcn UI + Bun

STEP 1 Create Vite + React + TypeScript Project

cd Mern_Stack_Project
bun create vite@latest frontend -- --template react-ts
cd frontend
bun install

📝 This creates a React + TypeScript project using Vite build tool.

STEP 2 Install Required Packages

bun add react-router-dom axios


bun add -d tailwindcss@3 postcss autoprefixer
bunx tailwindcss init -p

Package breakdown:
• react-router-dom — page navigation (Login → Dashboard)
• axios — backend API calls (better than fetch)
• tailwindcss@3 — CSS framework (v3, NOT v4 — v4 has no init command)
• postcss — Tailwind CSS processor
• autoprefixer — cross-browser CSS fix
• -d flag — devDependency, not needed in production

STEP 3 Configure Tailwind CSS

[Link] — replace content:


export default {
content: [
"./[Link]",
"./src/**/*.{js,jsx,ts,tsx}",
],
theme: { extend: {} },
plugins: [],
}

src/[Link] — delete everything, add only:


@tailwind base;
@tailwind components;
@tailwind utilities;

📝 Yellow underline in VS Code is normal — add '[Link]: false' in settings to remove it.

STEP 4 Configure TypeScript Path Aliases

[Link] — replace full content:


{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "[Link]"],
"module": "ESNext",
"skipLibCheck": true,
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"strict": true
},
"include": ["src"],
"references": [{ "path": "./[Link]" }]
}

[Link] — add inside compilerOptions:


"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}

[Link] — replace full content:


{
"compilerOptions": {
"composite": true,
"skipLibCheck": true,
"module": "ESNext",
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true
},
"include": ["[Link]"]
}

STEP 5 Configure Vite Path Alias

bun add -d @types/node

[Link] — replace full content:


import path from "path"
import { defineConfig } from "vite"
import react from "@vitejs/plugin-react"

export default defineConfig({


plugins: [react()],
resolve: {
alias: {
"@": [Link](__dirname, "./src"),
},
},
})

📝 @/* alias lets you write: import Button from '@/components/Button' instead of
'../../../components/Button'

STEP 6 Setup Shadcn UI

bunx shadcn@4.9.0 init


# Select: Radix → Nova preset

# Fix [Link] after shadcn init (remove shadcn imports):


# Keep only the 3 tailwind lines

# Add components:
bunx shadcn@4.9.0 add button input card label

📝 Use shadcn@4.9.0 specifically — latest v4 has workspace config issues with Bun.
📝 After init, check src/[Link] — remove any @import lines shadcn added, keep only @tailwind
lines.

STEP 7 Create Folder Structure

Create these folders and empty files inside src/:


src/
├── components/
├── pages/
│ ├── [Link]
│ ├── [Link]
│ └── [Link]
├── services/
│ ├── [Link]
│ └── [Link]
├── hooks/
│ └── [Link]
├── utils/
│ └── [Link]
└── routes/
└── [Link]

STEP 8 Test Frontend

bun run dev

Open browser: [Link]


Should show 'Task Manager' text — frontend setup complete.
PART 2 — BACKEND SETUP
Tech: [Link] + Express + MongoDB + JWT + bcrypt + Bun

STEP 9 Install Backend Dependencies

cd Mern_Stack_Project/backend

bun add express mongoose dotenv bcryptjs jsonwebtoken cors

bun add -d @types/express @types/cors @types/bcryptjs


@types/jsonwebtoken nodemon

Package breakdown:
• express — web server framework
• mongoose — MongoDB ODM (Object Document Mapper)
• dotenv — read .env file variables
• bcryptjs — hash passwords securely
• jsonwebtoken — create and verify JWT tokens
• cors — allow frontend to call backend API
• nodemon — auto-restart server on file change (dev only)

STEP 10 Configure [Link]

backend/[Link] — final version:


{
"type": "module",
"scripts": {
"dev": "nodemon [Link]",
"start": "node [Link]"
},
"dependencies": {
"bcryptjs": "^3.0.3",
"cors": "^2.8.6",
"dotenv": "^17.4.2",
"express": "^5.2.1",
"jsonwebtoken": "^9.0.3",
"mongoose": "^9.6.3"
},
"devDependencies": {
"@types/bcryptjs": "^3.0.0",
"@types/cors": "^2.8.19",
"@types/express": "^5.0.6",
"@types/jsonwebtoken": "^9.0.10",
"nodemon": "^3.1.14"
}
}

📝 "type": "module" allows import/export syntax instead of require().

STEP 11 MongoDB Atlas Setup

1. Go to: [Link]
2. Create free account → Create cluster (Free tier M0)
3. Cluster name: TaskManager, Region: Mumbai (ap-south-1), Provider: AWS
4. Create database user — save username and password
5. Network Access → Add IP → [Link]/0 (allow all)
6. Connect → Drivers → Copy connection string
7. Add database name in string:

# Before:
mongodb+srv://user:pass@[Link]/?appName=TaskManager

# After (add /taskmanager before ?):


mongodb+srv://user:pass@[Link]/taskmanager?appName=TaskManager

STEP 12 Create .env File

backend/.env:
PORT=5000
MONGO_URI=mongodb+srv://user:pass@[Link]/taskmanager?
appName=TaskManager
JWT_SECRET=taskmanager_super_secret_key_2024

📝 Never push .env to GitHub — add it to .gitignore.

STEP 13 Create Backend Folder Structure

Create these folders and empty files inside backend/src/:


backend/
├── src/
│ ├── common/
│ │ ├── db/
│ │ │ └── [Link]
│ │ ├── middleware/
│ │ │ └── [Link]
│ │ └── utils/
│ │ ├── [Link]
│ │ └── [Link]
│ ├── modules/
│ │ ├── auth/
│ │ │ ├── [Link]
│ │ │ ├── [Link]
│ │ │ ├── [Link]
│ │ │ └── [Link]
│ │ └── tasks/
│ │ ├── [Link]
│ │ ├── [Link]
│ │ ├── [Link]
│ │ └── [Link]
│ └── [Link]
├── [Link]
├── .env
├── .gitignore
└── [Link]

STEP 14 Create .gitignore Files

Root .gitignore (Mern_Stack_Project/.gitignore):


node_modules
**/node_modules
.env
**/.env
.[Link]
**/.[Link]
dist
**/dist
*.log
.DS_Store
[Link]
PART 3 — BACKEND CODE FILES

[Link]
import app from "./src/[Link]"
import dotenv from "dotenv"
import connectDB from "./src/common/db/[Link]"

[Link]()

const PORT = [Link] || 5000

connectDB().then(() => {
[Link](PORT, () => {
[Link](`Server running on [Link]
})
})

src/[Link]
import express from "express"
import cors from "cors"
import authRoutes from "./modules/auth/[Link]"
import taskRoutes from "./modules/tasks/[Link]"

const app = express()

[Link](cors())
[Link]([Link]())

[Link]("/api/auth", authRoutes)
[Link]("/api/tasks", taskRoutes)

export default app

src/common/db/[Link]
import mongoose from "mongoose"

const connectDB = async () => {


try {
const conn = await [Link]([Link].MONGO_URI)
[Link](`MongoDB connected: ${[Link]}`)
} catch (error) {
[Link](`DB Error: ${[Link]}`)
[Link](1)
}
}

export default connectDB


src/common/utils/[Link]
import jwt from "jsonwebtoken"

const generateToken = (userId) => {


return [Link]({ id: userId }, [Link].JWT_SECRET, {
expiresIn: "7d"
})
}

export default generateToken

src/common/utils/[Link]
export const successResponse = (res, data, message = "Success", status = 200) => {
return [Link](status).json({ success: true, message, data })
}

export const errorResponse = (res, message = "Error", status = 500) => {


return [Link](status).json({ success: false, message })
}

src/common/middleware/[Link]
import jwt from "jsonwebtoken"
import { errorResponse } from "../utils/[Link]"

const authMiddleware = (req, res, next) => {


const token = [Link]?.split(" ")[1]
if (!token) return errorResponse(res, "No token provided", 401)

try {
const decoded = [Link](token, [Link].JWT_SECRET)
[Link] = decoded
next()
} catch (error) {
return errorResponse(res, "Invalid token", 401)
}
}

export default authMiddleware

src/modules/auth/[Link]
import mongoose from "mongoose"
import bcrypt from "bcryptjs"

const userSchema = new [Link]({


name: { type: String, required: true },
email: { type: String, required: true, unique: true, lowercase: true },
password: { type: String, required: true },
role: { type: String, default: "user" }
}, { timestamps: true })

[Link]("save", async function (next) {


if (![Link]("password")) return next()
[Link] = await [Link]([Link], 10)
next()
})

const User = [Link]("User", userSchema)


export default User

src/modules/tasks/[Link]
import mongoose from "mongoose"

const taskSchema = new [Link]({


title: { type: String, required: true },
description: { type: String, default: "" },
status: { type: String, enum: ["pending","completed"], default: "pending" },
userId: { type: [Link], ref: "User", required:
true }
}, { timestamps: true })

const Task = [Link]("Task", taskSchema)


export default Task
src/modules/auth/[Link]
import User from "./[Link]"
import bcrypt from "bcryptjs"
import generateToken from "../../common/utils/[Link]"
import { successResponse, errorResponse } from "../../common/utils/[Link]"

export const register = async (req, res) => {


try {
const { name, email, password } = [Link]
if (!name || !email || !password)
return errorResponse(res, "All fields required", 400)

const existing = await [Link]({ email })


if (existing) return errorResponse(res, "Email already exists", 400)

const user = await [Link]({ name, email, password })


const token = generateToken(user._id)
return successResponse(res, { token, user: { name: [Link], email: [Link]
} }, "Registered", 201)
} catch (err) {
return errorResponse(res, [Link])
}
}

export const login = async (req, res) => {


try {
const { email, password } = [Link]
if (!email || !password) return errorResponse(res, "All fields required", 400)

const user = await [Link]({ email })


if (!user) return errorResponse(res, "Invalid credentials", 401)

const isMatch = await [Link](password, [Link])


if (!isMatch) return errorResponse(res, "Invalid credentials", 401)

const token = generateToken(user._id)


return successResponse(res, { token, user: { name: [Link], email: [Link]
} })
} catch (err) {
return errorResponse(res, [Link])
}
}

src/modules/auth/[Link]
import express from "express"
import { register, login } from "./[Link]"

const router = [Link]()

[Link]("/register", register)
[Link]("/login", login)

export default router


src/modules/tasks/[Link]
import Task from "./[Link]"
import { successResponse, errorResponse } from "../../common/utils/[Link]"

export const getTasks = async (req, res) => {


try {
const tasks = await [Link]({ userId: [Link] }).sort({ createdAt: -1 })
return successResponse(res, tasks)
} catch (err) { return errorResponse(res, [Link]) }
}

export const createTask = async (req, res) => {


try {
const { title, description } = [Link]
if (!title) return errorResponse(res, "Title required", 400)
const task = await [Link]({ title, description, userId: [Link] })
return successResponse(res, task, "Task created", 201)
} catch (err) { return errorResponse(res, [Link]) }
}

export const updateTask = async (req, res) => {


try {
const task = await [Link](
{ _id: [Link], userId: [Link] },
[Link], { new: true }
)
if (!task) return errorResponse(res, "Task not found", 404)
return successResponse(res, task)
} catch (err) { return errorResponse(res, [Link]) }
}

export const deleteTask = async (req, res) => {


try {
const task = await [Link]({ _id: [Link], userId:
[Link] })
if (!task) return errorResponse(res, "Task not found", 404)
return successResponse(res, null, "Task deleted")
} catch (err) { return errorResponse(res, [Link]) }
}

export const toggleTask = async (req, res) => {


try {
const task = await [Link]({ _id: [Link], userId: [Link] })
if (!task) return errorResponse(res, "Task not found", 404)
[Link] = [Link] === "pending" ? "completed" : "pending"
await [Link]()
return successResponse(res, task)
} catch (err) { return errorResponse(res, [Link]) }
}

src/modules/tasks/[Link]
import express from "express"
import { getTasks, createTask, updateTask, deleteTask, toggleTask } from
"./[Link]"
import authMiddleware from "../../common/middleware/[Link]"

const router = [Link]()

[Link](authMiddleware)

[Link]("/", getTasks)
[Link]("/", createTask)
[Link]("/:id", updateTask)
[Link]("/:id", deleteTask)
[Link]("/:id", toggleTask)

export default router


PART 4 — FRONTEND CODE FILES

src/utils/[Link]
import axios from "axios"

const axiosInstance = [Link]({


baseURL: [Link].VITE_API_URL || "[Link]
})

[Link]((config) => {
const token = [Link]("token")
if (token) [Link] = `Bearer ${token}`
return config
})

export default axiosInstance

src/services/[Link]
import axiosInstance from "../utils/axiosInstance"

export const registerUser = async (data: { name: string; email: string; password:
string }) => {
const res = await [Link]("/auth/register", data)
return [Link]
}

export const loginUser = async (data: { email: string; password: string }) => {
const res = await [Link]("/auth/login", data)
return [Link]
}

src/services/[Link]
import axiosInstance from "../utils/axiosInstance"

export const getTasks = async () => (await [Link]("/tasks")).data


export const createTask = async (data: { title: string; description?: string }) =>
(await [Link]("/tasks", data)).data
export const updateTask = async (id: string, data: object) =>
(await [Link](`/tasks/${id}`, data)).data
export const deleteTask = async (id: string) =>
(await [Link](`/tasks/${id}`)).data
export const toggleTask = async (id: string) =>
(await [Link](`/tasks/${id}`)).data

src/routes/[Link]
import { Navigate } from "react-router-dom"
const ProtectedRoute = ({ children }: { children: [Link] }) => {
const token = [Link]("token")
return token ? <>{children}</> : <Navigate to="/login" />
}

export default ProtectedRoute

src/[Link]
import { BrowserRouter, Routes, Route, Navigate } from "react-router-dom"
import Login from "./pages/Login"
import Register from "./pages/Register"
import Dashboard from "./pages/Dashboard"
import ProtectedRoute from "./routes/ProtectedRoute"

function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Navigate to="/login" />} />
<Route path="/login" element={<Login />} />
<Route path="/register" element={<Register />} />
<Route path="/dashboard" element={
<ProtectedRoute><Dashboard /></ProtectedRoute>
} />
</Routes>
</BrowserRouter>
)
}

export default App

frontend/.env
VITE_API_URL=[Link]
PART 5 — RUN THE PROJECT

Terminal 1 — Start Backend


cd Mern_Stack_Project/backend
bun run dev
# Should print:
# MongoDB connected: [Link]
# Server running on [Link]

Terminal 2 — Start Frontend


cd Mern_Stack_Project/frontend
bun run dev
# Open: [Link]

Test APIs in Postman


Method URL Body / Notes
POST /api/auth/register { "name":"Prashant", "email":"p@[Link]",
"password":"123456" }

POST /api/auth/login { "email":"p@[Link]",


"password":"123456" }

GET /api/tasks Header: Authorization: Bearer <token>

POST /api/tasks { "title":"Buy milk", "description":"2


litres" }

PUT /api/tasks/:id { "title":"Updated title" }

DELETE /api/tasks/:id No body needed

PATCH /api/tasks/:id Toggles pending ↔ completed

Prashant — AvQuint Solutions Internship Assignment

You might also like