<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Mohit Menghnani - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Mohit Menghnani - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Mon, 18 May 2026 22:34:19 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/author/menghnani/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Build Production-Ready Full Stack Apps with the MERN Stack ]]>
                </title>
                <description>
                    <![CDATA[ As developers, we’re always looking for more efficient tools. The MERN stack (MongoDB, Express.js, React, and Node.js) stands out for its JavaScript-centric nature, offering a unified language across the entire application. In this guide, you'll buil... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-production-ready-full-stack-apps-with-the-mern-stack/</link>
                <guid isPermaLink="false">686bd0446349e98b57ebc099</guid>
                
                    <category>
                        <![CDATA[ full stack ]]>
                    </category>
                
                    <category>
                        <![CDATA[ software development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ clean code ]]>
                    </category>
                
                    <category>
                        <![CDATA[ best practices ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Mohit Menghnani ]]>
                </dc:creator>
                <pubDate>Mon, 07 Jul 2025 13:48:52 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1751502709499/b43b3607-f01b-45c0-9797-75eef92497c6.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>As developers, we’re always looking for more efficient tools. The MERN stack (MongoDB, Express.js, React, and Node.js) stands out for its JavaScript-centric nature, offering a unified language across the entire application.</p>
<p>In this guide, you'll build a complete Task Manager app with user authentication, protected routes, and full CRUD functionality, built with React on the frontend and Express/MongoDB on the backend.</p>
<p>This article will serve as your hands-on, code-first guide to building, securing, and deploying a MERN application, drawing from my own practical experience. Every section has code you can run, and I’ll give concise explanations along the way.</p>
<p>It doesn’t matter if you're just getting started with MERN or looking to level up your architecture and production deployment knowledge – this article is designed to get you from zero to production with confidence.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-tools-amp-tech-stack">Tools &amp; Tech Stack</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-skills-amp-setup">Skills &amp; Setup</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-project-setup-laying-the-groundwork">Project Setup: Laying the Groundwork</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-project-structure">Project Structure</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-code-quality-linting-and-formatting">Code Quality: Linting and Formatting</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-testing-ensuring-robustness">Testing: Ensuring Robustness</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-backend-testing-nodejsexpressjs">Backend Testing (Node.js/Express.js)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-frontend-testing-react-testing-library-cypress">Frontend Testing (React Testing Library + Cypress)</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-build-the-task-manager">How to Build the Task Manager</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-backend-implementation-nodejsexpressjs">Backend Implementation (Node.js/Express.js)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-frontend-implementation-react">Frontend Implementation (React)</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-deployment-from-localhost-to-live">Deployment: From</a> <a target="_blank" href="http://Localhost">Localhost</a> <a class="post-section-overview" href="#heading-deployment-from-localhost-to-live">to Live</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-backend-deployment-nodejsexpressjs">Backend Deployment (Node.js/Express.js)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-frontend-deployment-react">Frontend Deployment (React)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-database-deployment-mongodb-atlas">Database Deployment (MongoDB Atlas)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-1-env-configuration-example">1. .env Configuration Example</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-2-connect-to-mongodb-in-appjs">2. Connect to MongoDB in app.js</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-other-deployment-options">Other Deployment Options</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-security-best-practices-fortifying-your-application">Security Best Practices: Fortifying Your Application</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-setup-input-validation-and-sanitization">Setup Input Validation and Sanitization</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-add-authentication-and-authorization">Add Authentication and Authorization</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-implement-rate-limiting">Implement Rate Limiting</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-setup-cors-configuration-cross-origin-resource-sharing">Setup CORS Configuration (Cross-Origin Resource Sharing)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-use-environment-variables">Use Environment Variables</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-monitoring-and-logging-with-winston-and-morgan">Monitoring and Logging with Winston and Morgan</a></p>
<ul>
<li><a class="post-section-overview" href="#heading-frontend-error-monitoring-sentry">Frontend Error Monitoring (Sentry)</a></li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before jumping in the project, here’s what you’ll need to get the most out of this tutorial:</p>
<h3 id="heading-tools-amp-tech-stack">Tools &amp; Tech Stack</h3>
<p>You’ll be using the following technologies throughout the project:</p>
<ul>
<li><p><strong>Node.js &amp; npm</strong> – Backend runtime and package manager</p>
</li>
<li><p><strong>Express.js</strong> – Web framework for Node</p>
</li>
<li><p><strong>MongoDB Atlas</strong> – Cloud-hosted NoSQL database</p>
</li>
<li><p><strong>Mongoose</strong> – ODM for MongoDB</p>
</li>
<li><p><strong>React</strong> – Frontend UI library</p>
</li>
<li><p><strong>React Router</strong> – For client-side routing</p>
</li>
<li><p><strong>Axios</strong> – For making API requests</p>
</li>
<li><p><strong>Jest &amp; Supertest</strong> – For backend tests</p>
</li>
<li><p><strong>React Testing Library &amp; Cypress</strong> – For Frontend unit and E2E tests</p>
</li>
<li><p><strong>ESLint + Prettier</strong> – For code formatting, linting</p>
</li>
<li><p><strong>Husky</strong> – To setup pre-commit hooks</p>
</li>
<li><p><strong>Helmet, Joi, express-rate-limit, cors</strong> – For security, validation, and best practices</p>
</li>
<li><p><strong>PM2 &amp; NGINX</strong> – For backend deployment</p>
</li>
<li><p><strong>Sentry</strong> – For error monitoring</p>
</li>
</ul>
<h3 id="heading-skills-amp-setup">Skills &amp; Setup</h3>
<ul>
<li><p>Basic knowledge of JavaScript, React, and Node.js</p>
</li>
<li><p>Familiarity with REST APIs and HTTP request/response flows</p>
</li>
<li><p>Git and a GitHub account for version control</p>
</li>
<li><p>A free MongoDB Atlas account</p>
</li>
<li><p>Node.js and npm installed locally (Node 18+ recommended)</p>
</li>
</ul>
<h2 id="heading-project-setup-laying-the-groundwork"><strong>Project Setup: Laying the Groundwork</strong></h2>
<p>A well-structured project is crucial for maintainability. We'll adopt a clear separation between the front end and the back end here.</p>
<h3 id="heading-project-structure"><strong>Project Structure</strong></h3>
<p>This structure clearly separates the React front end (client/) from the Node.js/Express.js back end (server/), promoting modularity and easier management.</p>
<pre><code class="lang-javascript">my-mern-app/                # Root folder
├── client/                 # React frontend
│   ├── public/
│   ├── src/
│   │   ├── components/
│   │   ├── pages/
│   │   ├── App.js
│   │   └── index.js
│   └── package.json
├── server/                 # Node.js/Express.js backend
│   ├── config/
│   ├── controllers/
│   ├── models/
│   ├── routes/
│   ├── services/
│   ├── app.js
│   └── package.json
</code></pre>
<h3 id="heading-code-quality-linting-and-formatting"><strong>Code Quality: Linting and Formatting</strong></h3>
<p>Consistency is key when you’re building a production-grad application like this one. We'll use ESLint with Airbnb style and Prettier for automated code quality and formatting.</p>
<p>To install these tools, run this in your terminal:</p>
<pre><code class="lang-bash">npm install --save-dev eslint prettier eslint-config-airbnb-base eslint-plugin-prettier
</code></pre>
<p>And here are some setups with their recommended configurations:</p>
<p>This configuration sets up ESLint for a Node.js project using the Airbnb and Prettier style guides, with custom rules to relax strict linting constraints like allowing <code>console.log</code> and disabling mandatory function names.</p>
<h4 id="heading-eslintrcjs-server-side-example"><strong>.eslintrc.js (server-side example)</strong></h4>
<pre><code class="lang-javascript"><span class="hljs-built_in">module</span>.exports = {

  <span class="hljs-attr">env</span>: {

    <span class="hljs-attr">node</span>: <span class="hljs-literal">true</span>,

    <span class="hljs-attr">commonjs</span>: <span class="hljs-literal">true</span>,

    <span class="hljs-attr">es2021</span>: <span class="hljs-literal">true</span>,

  },

  <span class="hljs-attr">extends</span>: [<span class="hljs-string">"airbnb-base"</span>, <span class="hljs-string">"prettier"</span>],

  <span class="hljs-attr">plugins</span>: [<span class="hljs-string">"prettier"</span>],

  <span class="hljs-attr">parserOptions</span>: {

    <span class="hljs-attr">ecmaVersion</span>: <span class="hljs-number">12</span>,

  },

  <span class="hljs-attr">rules</span>: {

    <span class="hljs-string">"prettier/prettier"</span>: <span class="hljs-string">"error"</span>,

    <span class="hljs-string">"no-console"</span>: <span class="hljs-string">"off"</span>,

    <span class="hljs-string">"func-names"</span>: <span class="hljs-string">"off"</span>,

    <span class="hljs-string">"no-process-exit"</span>: <span class="hljs-string">"off"</span>,

    <span class="hljs-string">"class-methods-use-this"</span>: <span class="hljs-string">"off"</span>,

    <span class="hljs-string">"import/no-extraneous-dependencies"</span>: <span class="hljs-string">"off"</span>,

  },

};
</code></pre>
<h4 id="heading-prettierrc"><strong>.prettierrc</strong></h4>
<p>This config enforces consistent formatting: add semicolons, use trailing commas where valid, and prefer single quotes for strings.</p>
<pre><code class="lang-json">{

  <span class="hljs-attr">"semi"</span>: <span class="hljs-literal">true</span>,

  <span class="hljs-attr">"trailingComma"</span>: <span class="hljs-string">"all"</span>,

  <span class="hljs-attr">"singleQuote"</span>: <span class="hljs-literal">true</span>

}
</code></pre>
<h3 id="heading-version-control-git-essentials"><strong>Version Control: Git Essentials</strong></h3>
<p>Git is indispensable. You can use feature branches and pull requests for collaborative development, making it easier to work on large projects with coworkers. Consider using Husky for pre-commit hooks to enforce linting and testing.</p>
<h4 id="heading-install-husky">Install Husky:</h4>
<p>Install Husky to easily manage Git hooks, allowing you to automate tasks like linting and testing before commits.</p>
<pre><code class="lang-bash">npm install husky --save-dev
</code></pre>
<h4 id="heading-packagejson-add-script">package.json (add script)</h4>
<p>This <code>package.json</code> file sets up a Node.js project named <code>my-mern-app</code>, and configures a <code>prepare</code> script to install Git hooks using Husky (v7). It's ready for adding pre-commit automation, such as linting or testing.</p>
<pre><code class="lang-json">{

  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"my-mern-app"</span>,

  <span class="hljs-attr">"version"</span>: <span class="hljs-string">"1.0.0"</span>,

  <span class="hljs-attr">"description"</span>: <span class="hljs-string">""</span>,

  <span class="hljs-attr">"main"</span>: <span class="hljs-string">"index.js"</span>,

  <span class="hljs-attr">"scripts"</span>: {

    <span class="hljs-attr">"prepare"</span>: <span class="hljs-string">"husky install"</span>

  },

  <span class="hljs-attr">"keywords"</span>: [],

  <span class="hljs-attr">"author"</span>: <span class="hljs-string">""</span>,

  <span class="hljs-attr">"license"</span>: <span class="hljs-string">"ISC"</span>,

  <span class="hljs-attr">"devDependencies"</span>: {

    <span class="hljs-attr">"husky"</span>: <span class="hljs-string">"^7.0.0"</span>

  }

}
</code></pre>
<h4 id="heading-create-a-pre-commit-hook">Create a pre-commit hook</h4>
<p>The below command sets up a pre-commit hook that automatically runs your tests and linter before each commit, ensuring code quality and preventing errors from entering your codebase.</p>
<pre><code class="lang-json">npx husky add .husky/pre-commit <span class="hljs-string">"npm test &amp;&amp; npm run lint"</span>
</code></pre>
<h2 id="heading-testing-ensuring-robustness"><strong>Testing: Ensuring Robustness</strong></h2>
<p>Automated testing is vital. We'll cover unit, integration, and end-to-end testing in this guide.</p>
<h3 id="heading-backend-testing-nodejsexpressjs">Backend Testing (Node.js/Express.js)</h3>
<p>You’ll use Jest for unit testing and Supertest for API integration tests.</p>
<h5 id="heading-install-them-like-this">Install them like this:</h5>
<pre><code class="lang-bash">npm install --save-dev jest supertest
</code></pre>
<p>You’ll use Jest to write unit tests for your JavaScript code and Supertest to test HTTP requests against your Express.js API.</p>
<h4 id="heading-example-test-servertestsauthtestjs">Example Test (server/tests/auth.test.js):</h4>
<p>This test suite uses Supertest to simulate API calls for user registration and login, asserting that the responses have the expected status codes and properties.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> request = <span class="hljs-built_in">require</span>(<span class="hljs-string">'supertest'</span>);

<span class="hljs-keyword">const</span> app = <span class="hljs-built_in">require</span>(<span class="hljs-string">'../app'</span>); <span class="hljs-comment">// Your Express app instance</span>

describe(<span class="hljs-string">'Auth API'</span>, <span class="hljs-function">() =&gt;</span> {

  it(<span class="hljs-string">'should register a new user'</span>, <span class="hljs-keyword">async</span> () =&gt; {

    <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> request(app)

      .post(<span class="hljs-string">'/api/auth/register'</span>)

      .send({

        <span class="hljs-attr">username</span>: <span class="hljs-string">'testuser'</span>,

        <span class="hljs-attr">email</span>: <span class="hljs-string">'test@example.com'</span>,

        <span class="hljs-attr">password</span>: <span class="hljs-string">'password123'</span>,

      });

    expect(res.statusCode).toEqual(<span class="hljs-number">201</span>);

    expect(res.body).toHaveProperty(<span class="hljs-string">'_id'</span>);

  });


  it(<span class="hljs-string">'should login an existing user'</span>, <span class="hljs-keyword">async</span> () =&gt; {

    <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> request(app)

      .post(<span class="hljs-string">'/api/auth/login'</span>)

      .send({

        <span class="hljs-attr">email</span>: <span class="hljs-string">'test@example.com'</span>,

        <span class="hljs-attr">password</span>: <span class="hljs-string">'password123'</span>,

      });

    expect(res.statusCode).toEqual(<span class="hljs-number">200</span>);

    expect(res.headers[<span class="hljs-string">'set-cookie'</span>]).toBeDefined();

  });

});
</code></pre>
<h3 id="heading-frontend-testing-react-testing-library-cypress">Frontend Testing (React Testing Library + Cypress)</h3>
<p>You’ll use Jest and the React Testing Library for unit/integration tests, and Cypress for E2E tests.</p>
<h5 id="heading-you-can-install-these-like-this">You can install these like this:</h5>
<pre><code class="lang-bash">npm install --save-dev @testing-library/react @testing-library/jest-dom jest cypress
</code></pre>
<p>React Testing Library will help you test your React components, and Cypress will provide comprehensive end-to-end testing of your frontend application.</p>
<h4 id="heading-example-component-test-clientsrccomponentsbuttontestjs">Example Component Test (client/src/components/Button.test.js):</h4>
<p>This unit test uses the React Testing Library to render a Button component and verifies that the specified text content is present in the rendered output.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">import</span> { render, screen } <span class="hljs-keyword">from</span> <span class="hljs-string">'@testing-library/react'</span>;

<span class="hljs-keyword">import</span> Button <span class="hljs-keyword">from</span> <span class="hljs-string">'./Button'</span>;


test(<span class="hljs-string">'renders button with text'</span>, <span class="hljs-function">() =&gt;</span> {

  render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Button</span>&gt;</span>Click Me<span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span></span>);

  <span class="hljs-keyword">const</span> buttonElement = screen.getByText(<span class="hljs-regexp">/Click Me/i</span>);

  expect(buttonElement).toBeInTheDocument();

});
</code></pre>
<p>The following Cypress test simulates a complete user authentication flow, from registration to login and logout, asserting expected URL changes and page content.</p>
<pre><code class="lang-javascript">Example E2E Test (cypress/e2e/auth.cy.js)

describe(<span class="hljs-string">'Authentication Flow'</span>, <span class="hljs-function">() =&gt;</span> {

  it(<span class="hljs-string">'should allow a user to register and login'</span>, <span class="hljs-function">() =&gt;</span> {

    cy.visit(<span class="hljs-string">'/register'</span>);

    cy.get(<span class="hljs-string">'input[name="username"]'</span>).type(<span class="hljs-string">'e2euser'</span>);

    cy.get(<span class="hljs-string">'input[name="email"]'</span>).type(<span class="hljs-string">'e2e@example.com'</span>);

    cy.get(<span class="hljs-string">'input[name="password"]'</span>).type(<span class="hljs-string">'password123'</span>);

    cy.get(<span class="hljs-string">'button[type="submit"]'</span>).click();

    cy.url().should(<span class="hljs-string">'include'</span>, <span class="hljs-string">'/dashboard'</span>);

    cy.contains(<span class="hljs-string">'Welcome, e2euser'</span>);

    cy.get(<span class="hljs-string">'button'</span>).contains(<span class="hljs-string">'Logout'</span>).click();

    cy.url().should(<span class="hljs-string">'include'</span>, <span class="hljs-string">'/login'</span>);

    cy.get(<span class="hljs-string">'input[name="email"]'</span>).type(<span class="hljs-string">'e2e@example.com'</span>);

    cy.get(<span class="hljs-string">'input[name="password"]'</span>).type(<span class="hljs-string">'password123'</span>);

    cy.get(<span class="hljs-string">'button[type="submit"]'</span>).click();

    cy.url().should(<span class="hljs-string">'include'</span>, <span class="hljs-string">'/dashboard'</span>);

  });

});
</code></pre>
<h2 id="heading-how-to-build-the-task-manager"><strong>How to Build the Task Manager</strong></h2>
<p>We'll build a simple Task Manager with user authentication and CRUD operations for tasks so you can see how the whole thing comes together.</p>
<h3 id="heading-backend-implementation-nodejsexpressjs">Backend Implementation (Node.js/Express.js)</h3>
<h4 id="heading-dependencies">Dependencies</h4>
<p>Start by installing our core backend libraries: Express for routing, Mongoose for MongoDB interactions, dotenv for environment variables, bcrypt/jsonwebtoken/cookie-parser for secure authentication, and helmet for setting secure HTTP headers:</p>
<pre><code class="lang-bash">npm install express mongoose dotenv bcryptjs jsonwebtoken cookie-parser
</code></pre>
<h4 id="heading-serverappjs-entry-point">server/app.js (Entry Point)</h4>
<p>Next, we’ll set up the first or the main entry point for the backend. This is the main Express.js application file, which configures middleware, establishes a MongoDB connection, and sets up API routes for authentication and task management.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>);

<span class="hljs-keyword">const</span> mongoose = <span class="hljs-built_in">require</span>(<span class="hljs-string">'mongoose'</span>);

<span class="hljs-keyword">const</span> dotenv = <span class="hljs-built_in">require</span>(<span class="hljs-string">'dotenv'</span>);

<span class="hljs-keyword">const</span> cookieParser = <span class="hljs-built_in">require</span>(<span class="hljs-string">'cookie-parser'</span>);

<span class="hljs-keyword">const</span> helmet = <span class="hljs-built_in">require</span>(<span class="hljs-string">'helmet'</span>);

<span class="hljs-keyword">const</span> authRoutes = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./routes/authRoutes'</span>);

<span class="hljs-keyword">const</span> taskRoutes = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./routes/taskRoutes'</span>);

<span class="hljs-keyword">const</span> { notFound, errorHandler } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./middleware/errorMiddleware'</span>);

dotenv.config();


<span class="hljs-keyword">const</span> app = express();

app.use(helmet());

app.use(express.json());

app.use(cookieParser());


mongoose.connect(process.env.MONGO_URI)

  .then(<span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'MongoDB connected!'</span>))

  .catch(<span class="hljs-function"><span class="hljs-params">err</span> =&gt;</span> <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'MongoDB connection error:'</span>, err));


app.use(<span class="hljs-string">'/api/auth'</span>, authRoutes);

app.use(<span class="hljs-string">'/api/tasks'</span>, taskRoutes);


app.get(<span class="hljs-string">'/'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {

  res.send(<span class="hljs-string">'MERN Task Manager API is running!'</span>);

});


app.use(notFound);

app.use(errorHandler);


<span class="hljs-keyword">const</span> PORT = process.env.PORT || <span class="hljs-number">5000</span>;

app.listen(PORT, <span class="hljs-function">() =&gt;</span> {

  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Server running on port <span class="hljs-subst">${PORT}</span>`</span>);

});
</code></pre>
<h4 id="heading-serverenv">server/.env</h4>
<p>To avoid hardcoding secrets, we’ll add a <code>.env</code> file where we can securely store environment variables, such as our database URI and JWT secret. This file stores sensitive environment variables such as your MongoDB connection string, server port, and JWT secret, keeping them secure and separate from your codebase.</p>
<pre><code class="lang-bash">MONGO_URI=your_mongodb_connection_string_here

PORT=5000

JWT_SECRET=supersecretjwtkey
</code></pre>
<h4 id="heading-servermodelsuserjs">server/models/User.js</h4>
<p>Now, let’s define our User model using MongoDB. This schema includes fields for username, email, and password, with pre-save hooks for password hashing and a method for password comparison.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> mongoose = <span class="hljs-built_in">require</span>(<span class="hljs-string">'mongoose'</span>);

<span class="hljs-keyword">const</span> bcrypt = <span class="hljs-built_in">require</span>(<span class="hljs-string">'bcryptjs'</span>);


<span class="hljs-keyword">const</span> UserSchema = <span class="hljs-keyword">new</span> mongoose.Schema({

  <span class="hljs-attr">username</span>: {

    <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>,

    <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>,

    <span class="hljs-attr">unique</span>: <span class="hljs-literal">true</span>,

  },

  <span class="hljs-attr">email</span>: {

    <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>,

    <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>,

    <span class="hljs-attr">unique</span>: <span class="hljs-literal">true</span>,

  },

  <span class="hljs-attr">password</span>: {

    <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>,

    <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>,

  },

});

UserSchema.pre(<span class="hljs-string">'save'</span>, <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">next</span>) </span>{

  <span class="hljs-keyword">if</span> (!<span class="hljs-built_in">this</span>.isModified(<span class="hljs-string">'password'</span>)) {

    next();

  }

  <span class="hljs-keyword">const</span> salt = <span class="hljs-keyword">await</span> bcrypt.genSalt(<span class="hljs-number">10</span>);

  <span class="hljs-built_in">this</span>.password = <span class="hljs-keyword">await</span> bcrypt.hash(<span class="hljs-built_in">this</span>.password, salt);

});


UserSchema.methods.matchPassword = <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">enteredPassword</span>) </span>{

  <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> bcrypt.compare(enteredPassword, <span class="hljs-built_in">this</span>.password);

};


<span class="hljs-built_in">module</span>.exports = mongoose.model(<span class="hljs-string">'User'</span>, UserSchema);
</code></pre>
<h4 id="heading-servermodelstaskjs">server/models/Task.js</h4>
<p>Next, we’ll create the Task model. This schema defines the Task model, which links each task to a user and includes fields for title, description, completion status, and creation timestamp.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> mongoose = <span class="hljs-built_in">require</span>(<span class="hljs-string">'mongoose'</span>);


<span class="hljs-keyword">const</span> TaskSchema = <span class="hljs-keyword">new</span> mongoose.Schema({

  <span class="hljs-attr">user</span>: {

    <span class="hljs-attr">type</span>: mongoose.Schema.Types.ObjectId,

    <span class="hljs-attr">ref</span>: <span class="hljs-string">'User'</span>,

    <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>,

  },

  <span class="hljs-attr">title</span>: {

    <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>,

    <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>,

    <span class="hljs-attr">trim</span>: <span class="hljs-literal">true</span>,

  },

  <span class="hljs-attr">description</span>: {

    <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>,

    <span class="hljs-attr">trim</span>: <span class="hljs-literal">true</span>,

  },

  <span class="hljs-attr">completed</span>: {

    <span class="hljs-attr">type</span>: <span class="hljs-built_in">Boolean</span>,

    <span class="hljs-attr">default</span>: <span class="hljs-literal">false</span>,

  },

  <span class="hljs-attr">createdAt</span>: {

    <span class="hljs-attr">type</span>: <span class="hljs-built_in">Date</span>,

    <span class="hljs-attr">default</span>: <span class="hljs-built_in">Date</span>.now,

  },

});


<span class="hljs-built_in">module</span>.exports = mongoose.model(<span class="hljs-string">'Task'</span>, TaskSchema);
</code></pre>
<h4 id="heading-servercontrollersauthcontrollerjs">server/controllers/authController.js</h4>
<p>Let’s build out the authentication controller. This controller handles user authentication flows, including registration, login, logout, and fetching user profiles, using JWTs and secure HTTP-only cookies.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> User = <span class="hljs-built_in">require</span>(<span class="hljs-string">'../models/User'</span>);

<span class="hljs-keyword">const</span> jwt = <span class="hljs-built_in">require</span>(<span class="hljs-string">'jsonwebtoken'</span>);

<span class="hljs-keyword">const</span> generateToken = <span class="hljs-function">(<span class="hljs-params">id</span>) =&gt;</span> {

  <span class="hljs-keyword">return</span> jwt.sign({ id }, process.env.JWT_SECRET, {

    <span class="hljs-attr">expiresIn</span>: <span class="hljs-string">'1h'</span>,

  });

};

<span class="hljs-built_in">exports</span>.registerUser = <span class="hljs-keyword">async</span> (req, res) =&gt; {

  <span class="hljs-keyword">const</span> { username, email, password } = req.body;

  <span class="hljs-keyword">try</span> {

    <span class="hljs-keyword">const</span> userExists = <span class="hljs-keyword">await</span> User.findOne({ email });

    <span class="hljs-keyword">if</span> (userExists) <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">400</span>).json({ <span class="hljs-attr">message</span>: <span class="hljs-string">'User already exists'</span> });

    <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> User.create({ username, email, password });

    <span class="hljs-keyword">if</span> (user) {

      <span class="hljs-keyword">const</span> token = generateToken(user._id);

      res.cookie(<span class="hljs-string">'token'</span>, token, { <span class="hljs-attr">httpOnly</span>: <span class="hljs-literal">true</span>, <span class="hljs-attr">secure</span>: process.env.NODE_ENV === <span class="hljs-string">'production'</span>, <span class="hljs-attr">maxAge</span>: <span class="hljs-number">3600000</span> });

      res.status(<span class="hljs-number">201</span>).json({ <span class="hljs-attr">id</span>: user.id, <span class="hljs-attr">username</span>: user.username, <span class="hljs-attr">email</span>: user.email });

    } <span class="hljs-keyword">else</span> {

      res.status(<span class="hljs-number">400</span>).json({ <span class="hljs-attr">message</span>: <span class="hljs-string">'Invalid user data'</span> });

    }

  } <span class="hljs-keyword">catch</span> (error) {

    res.status(<span class="hljs-number">500</span>).json({ <span class="hljs-attr">message</span>: error.message });

  }

};


<span class="hljs-built_in">exports</span>.loginUser = <span class="hljs-keyword">async</span> (req, res) =&gt; {

  <span class="hljs-keyword">const</span> { email, password } = req.body;

  <span class="hljs-keyword">try</span> {

    <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> User.findOne({ email });

    <span class="hljs-keyword">if</span> (user &amp;&amp; (<span class="hljs-keyword">await</span> user.matchPassword(password))) {

      <span class="hljs-keyword">const</span> token = generateToken(user._id);

      res.cookie(<span class="hljs-string">'token'</span>, token, { <span class="hljs-attr">httpOnly</span>: <span class="hljs-literal">true</span>, <span class="hljs-attr">secure</span>: process.env.NODE_ENV === <span class="hljs-string">'production'</span>, <span class="hljs-attr">maxAge</span>: <span class="hljs-number">3600000</span> });

      res.json({ <span class="hljs-attr">id</span>: user.id, <span class="hljs-attr">username</span>: user.username, <span class="hljs-attr">email</span>: user.email });

    } <span class="hljs-keyword">else</span> {

      res.status(<span class="hljs-number">401</span>).json({ <span class="hljs-attr">message</span>: <span class="hljs-string">'Invalid email or password'</span> });

    }

  } <span class="hljs-keyword">catch</span> (error) {

    res.status(<span class="hljs-number">500</span>).json({ <span class="hljs-attr">message</span>: error.message });

  }

};


<span class="hljs-built_in">exports</span>.logoutUser = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {

  res.cookie(<span class="hljs-string">'token'</span>, <span class="hljs-string">''</span>, { <span class="hljs-attr">httpOnly</span>: <span class="hljs-literal">true</span>, <span class="hljs-attr">expires</span>: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(<span class="hljs-number">0</span>) });

  res.status(<span class="hljs-number">200</span>).json({ <span class="hljs-attr">message</span>: <span class="hljs-string">'Logged out successfully'</span> });

};


<span class="hljs-built_in">exports</span>.getUserProfile = <span class="hljs-keyword">async</span> (req, res) =&gt; {

  <span class="hljs-keyword">try</span> {

    <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> User.findById(req.user._id).select(<span class="hljs-string">'-password'</span>);

    <span class="hljs-keyword">if</span> (user) {

      res.json(user);

    } <span class="hljs-keyword">else</span> {

      res.status(<span class="hljs-number">404</span>).json({ <span class="hljs-attr">message</span>: <span class="hljs-string">'User not found'</span> });

    }

  } <span class="hljs-keyword">catch</span> (error) {

    res.status(<span class="hljs-number">500</span>).json({ <span class="hljs-attr">message</span>: error.message });

  }

};
</code></pre>
<h4 id="heading-servercontrollerstaskcontrollerjs">server/controllers/taskController.js</h4>
<p>Now it’s time to implement the task controller. This controller provides the logic for fetching, creating, updating, and deleting tasks, ensuring that users can only interact with their tasks.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> Task = <span class="hljs-built_in">require</span>(<span class="hljs-string">'../models/Task'</span>);


<span class="hljs-built_in">exports</span>.getTasks = <span class="hljs-keyword">async</span> (req, res) =&gt; {

  <span class="hljs-keyword">try</span> {

    <span class="hljs-keyword">const</span> tasks = <span class="hljs-keyword">await</span> Task.find({ <span class="hljs-attr">user</span>: req.user._id });

    res.status(<span class="hljs-number">200</span>).json(tasks);

  } <span class="hljs-keyword">catch</span> (error) {

    res.status(<span class="hljs-number">500</span>).json({ <span class="hljs-attr">message</span>: error.message });

  }

};


<span class="hljs-built_in">exports</span>.createTask = <span class="hljs-keyword">async</span> (req, res) =&gt; {

  <span class="hljs-keyword">const</span> { title, description } = req.body;

  <span class="hljs-keyword">if</span> (!title) <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">400</span>).json({ <span class="hljs-attr">message</span>: <span class="hljs-string">'Please add a title'</span> });

  <span class="hljs-keyword">try</span> {

    <span class="hljs-keyword">const</span> task = <span class="hljs-keyword">await</span> Task.create({ title, description, <span class="hljs-attr">user</span>: req.user._id });

    res.status(<span class="hljs-number">201</span>).json(task);

  } <span class="hljs-keyword">catch</span> (error) {

    res.status(<span class="hljs-number">500</span>).json({ <span class="hljs-attr">message</span>: error.message });

  }

};


<span class="hljs-built_in">exports</span>.updateTask = <span class="hljs-keyword">async</span> (req, res) =&gt; {

  <span class="hljs-keyword">try</span> {

    <span class="hljs-keyword">const</span> task = <span class="hljs-keyword">await</span> Task.findById(req.params.id);

    <span class="hljs-keyword">if</span> (!task) <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">404</span>).json({ <span class="hljs-attr">message</span>: <span class="hljs-string">'Task not found'</span> });

    <span class="hljs-keyword">if</span> (task.user.toString() !== req.user._id.toString()) <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">401</span>).json({ <span class="hljs-attr">message</span>: <span class="hljs-string">'Not authorized'</span> });


    <span class="hljs-keyword">const</span> updatedTask = <span class="hljs-keyword">await</span> Task.findByIdAndUpdate(req.params.id, req.body, { <span class="hljs-attr">new</span>: <span class="hljs-literal">true</span>, <span class="hljs-attr">runValidators</span>: <span class="hljs-literal">true</span> });

    res.status(<span class="hljs-number">200</span>).json(updatedTask);

  } <span class="hljs-keyword">catch</span> (error) {

    res.status(<span class="hljs-number">500</span>).json({ <span class="hljs-attr">message</span>: error.message });

  }

};


<span class="hljs-built_in">exports</span>.deleteTask = <span class="hljs-keyword">async</span> (req, res) =&gt; {

  <span class="hljs-keyword">try</span> {

    <span class="hljs-keyword">const</span> task = <span class="hljs-keyword">await</span> Task.findById(req.params.id);

    <span class="hljs-keyword">if</span> (!task) <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">404</span>).json({ <span class="hljs-attr">message</span>: <span class="hljs-string">'Task not found'</span> });

    <span class="hljs-keyword">if</span> (task.user.toString() !== req.user._id.toString()) <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">401</span>).json({ <span class="hljs-attr">message</span>: <span class="hljs-string">'Not authorized'</span> });


    <span class="hljs-keyword">await</span> Task.deleteOne({ <span class="hljs-attr">_id</span>: req.params.id });

    res.status(<span class="hljs-number">200</span>).json({ <span class="hljs-attr">message</span>: <span class="hljs-string">'Task removed'</span> });

  } <span class="hljs-keyword">catch</span> (error) {

    res.status(<span class="hljs-number">500</span>).json({ <span class="hljs-attr">message</span>: error.message });

  }

};
</code></pre>
<h4 id="heading-servermiddlewareauthmiddlewarejs">server/middleware/authMiddleware.js</h4>
<p>To protect private routes<strong>,</strong> we will create a middleware that verifies the JWT from the request's cookies, ensuring that only authenticated users can access specific endpoints.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> jwt = <span class="hljs-built_in">require</span>(<span class="hljs-string">'jsonwebtoken'</span>);

<span class="hljs-keyword">const</span> User = <span class="hljs-built_in">require</span>(<span class="hljs-string">'../models/User'</span>);

<span class="hljs-built_in">exports</span>.protect = <span class="hljs-keyword">async</span> (req, res, next) =&gt; {

  <span class="hljs-keyword">let</span> token;

  <span class="hljs-keyword">if</span> (req.cookies.token) {

    <span class="hljs-keyword">try</span> {

      token = req.cookies.token;

      <span class="hljs-keyword">const</span> decoded = jwt.verify(token, process.env.JWT_SECRET);

      req.user = <span class="hljs-keyword">await</span> User.findById(decoded.id).select(<span class="hljs-string">'-password'</span>);

      next();

    } <span class="hljs-keyword">catch</span> (error) {

      res.status(<span class="hljs-number">401</span>).json({ <span class="hljs-attr">message</span>: <span class="hljs-string">'Not authorized, token failed'</span> });

    }

  } <span class="hljs-keyword">else</span> {

    res.status(<span class="hljs-number">401</span>).json({ <span class="hljs-attr">message</span>: <span class="hljs-string">'Not authorized, no token'</span> });

  }

};
</code></pre>
<h4 id="heading-servermiddlewareerrormiddlewarejs">server/middleware/errorMiddleware.js</h4>
<p>To handle errors cleanly across our backend, we’ll add global error-handling middleware that can handle 404 Not Found errors and provide a centralized error-handling mechanism for consistent API error responses.</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">exports</span>.notFound = <span class="hljs-function">(<span class="hljs-params">req, res, next</span>) =&gt;</span> {

  <span class="hljs-keyword">const</span> error = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">`Not Found - <span class="hljs-subst">${req.originalUrl}</span>`</span>);

  res.status(<span class="hljs-number">404</span>);

  next(error);

};


<span class="hljs-built_in">exports</span>.errorHandler = <span class="hljs-function">(<span class="hljs-params">err, req, res, next</span>) =&gt;</span> {

  <span class="hljs-keyword">const</span> statusCode = res.statusCode === <span class="hljs-number">200</span> ? <span class="hljs-number">500</span> : res.statusCode;

  res.status(statusCode);

  res.json({

    <span class="hljs-attr">message</span>: err.message,

    <span class="hljs-attr">stack</span>: process.env.NODE_ENV === <span class="hljs-string">'production'</span> ? <span class="hljs-literal">null</span> : err.stack,

  });

};
</code></pre>
<h4 id="heading-serverroutesauthroutesjs">server/routes/authRoutes.js</h4>
<p>Next, let’s define our authentication routes. These endpoints enable user authentication and map HTTP methods to their corresponding controller functions.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>);

<span class="hljs-keyword">const</span> { registerUser, loginUser, logoutUser, getUserProfile } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'../controllers/authController'</span>);

<span class="hljs-keyword">const</span> { protect } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'../middleware/authMiddleware'</span>);


<span class="hljs-keyword">const</span> router = express.Router();


router.post(<span class="hljs-string">'/register'</span>, registerUser);

router.post(<span class="hljs-string">'/login'</span>, loginUser);

router.get(<span class="hljs-string">'/logout'</span>, logoutUser);

router.get(<span class="hljs-string">'/profile'</span>, protect, getUserProfile);


<span class="hljs-built_in">module</span>.exports = router;
</code></pre>
<h4 id="heading-serverroutestaskroutesjs">server/routes/taskRoutes.js</h4>
<p>Now we’ll add the routes for task operations. This file defines the API routes for task management, applying the protect middleware to secure all task-related operations.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>);

<span class="hljs-keyword">const</span> { getTasks, createTask, updateTask, deleteTask } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'../controllers/taskController'</span>);

<span class="hljs-keyword">const</span> { protect } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'../middleware/authMiddleware'</span>);

<span class="hljs-keyword">const</span> router = express.Router();

router.route(<span class="hljs-string">'/'</span>).get(protect, getTasks).post(protect, createTask);

router.route(<span class="hljs-string">'/:id'</span>).put(protect, updateTask).delete(protect, deleteTask);

<span class="hljs-built_in">module</span>.exports = router;
</code></pre>
<h3 id="heading-frontend-implementation-react">Frontend Implementation (React)</h3>
<h4 id="heading-dependencies-1">Dependencies</h4>
<p>Now, you’ll need to initialize a new React project and install your essential libraries: Axios for HTTP requests, React Router for navigation, and React Toastify for displaying notifications.</p>
<pre><code class="lang-bash">npm install axios react-router-dom react-toastify
</code></pre>
<h4 id="heading-clientsrcindexjs">client/src/index.js</h4>
<p>Let’s start the frontend by setting up the entry point. Here we are rendering the main App component and wrapping it with AuthProvider to provide authentication context globally.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">import</span> ReactDOM <span class="hljs-keyword">from</span> <span class="hljs-string">'react-dom/client'</span>;

<span class="hljs-keyword">import</span> <span class="hljs-string">'./index.css'</span>;

<span class="hljs-keyword">import</span> App <span class="hljs-keyword">from</span> <span class="hljs-string">'./App'</span>;

<span class="hljs-keyword">import</span> { AuthProvider } <span class="hljs-keyword">from</span> <span class="hljs-string">'./context/AuthContext'</span>;


<span class="hljs-keyword">const</span> root = ReactDOM.createRoot(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'root'</span>));

root.render(

  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">React.StrictMode</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">AuthProvider</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">App</span> /&gt;</span>

    <span class="hljs-tag">&lt;/<span class="hljs-name">AuthProvider</span>&gt;</span>

  <span class="hljs-tag">&lt;/<span class="hljs-name">React.StrictMode</span>&gt;</span></span>

);
</code></pre>
<h4 id="heading-clientsrcappjs">client/src/App.js</h4>
<p>Next, we’ll define our main App component. This sets up the client-side routing for the application, and defines public and private routes, and includes a navigation bar and toast notification system.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">import</span> { BrowserRouter <span class="hljs-keyword">as</span> Router, Routes, Route } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-router-dom'</span>;

<span class="hljs-keyword">import</span> { ToastContainer } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-toastify'</span>;

<span class="hljs-keyword">import</span> <span class="hljs-string">'react-toastify/dist/ReactToastify.css'</span>;


<span class="hljs-keyword">import</span> Navbar <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/Navbar'</span>;

<span class="hljs-keyword">import</span> Register <span class="hljs-keyword">from</span> <span class="hljs-string">'./pages/Register'</span>;

<span class="hljs-keyword">import</span> Login <span class="hljs-keyword">from</span> <span class="hljs-string">'./pages/Login'</span>;

<span class="hljs-keyword">import</span> Dashboard <span class="hljs-keyword">from</span> <span class="hljs-string">'./pages/Dashboard'</span>;

<span class="hljs-keyword">import</span> PrivateRoute <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/PrivateRoute'</span>;


<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{

  <span class="hljs-keyword">return</span> (

    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Router</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">Navbar</span> /&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">ToastContainer</span> /&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"container"</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">Routes</span>&gt;</span>

          <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/register"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Register</span> /&gt;</span>} /&gt;

          <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/login"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Login</span> /&gt;</span>} /&gt;

          <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/dashboard"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">PrivateRoute</span> /&gt;</span>}&gt;

            <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">index</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Dashboard</span> /&gt;</span>} /&gt;

          <span class="hljs-tag">&lt;/<span class="hljs-name">Route</span>&gt;</span>

          <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">h1</span>&gt;</span>Welcome to Task Manager!<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>} /&gt;

        <span class="hljs-tag">&lt;/<span class="hljs-name">Routes</span>&gt;</span>

      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

    <span class="hljs-tag">&lt;/<span class="hljs-name">Router</span>&gt;</span></span>

  );

}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<h4 id="heading-clientsrccontextauthcontextjs">client/src/context/AuthContext.js</h4>
<p>We’ll create an authentication context that manages the global authentication state. It provides functions for user login, registration, and logout, and automatically loads user data on component mount.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { createContext, useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">'axios'</span>;

<span class="hljs-keyword">const</span> AuthContext = createContext();

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> AuthProvider = <span class="hljs-function">(<span class="hljs-params">{ children }</span>) =&gt;</span> {

  <span class="hljs-keyword">const</span> [user, setUser] = useState(<span class="hljs-literal">null</span>);

  <span class="hljs-keyword">const</span> [loading, setLoading] = useState(<span class="hljs-literal">true</span>);


  useEffect(<span class="hljs-function">() =&gt;</span> {

    <span class="hljs-keyword">const</span> loadUser = <span class="hljs-keyword">async</span> () =&gt; {

      <span class="hljs-keyword">try</span> {

        <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> axios.get(<span class="hljs-string">'/api/auth/profile'</span>);

        setUser(res.data);

      } <span class="hljs-keyword">catch</span> (err) {

        setUser(<span class="hljs-literal">null</span>);

      } <span class="hljs-keyword">finally</span> {

        setLoading(<span class="hljs-literal">false</span>);

      }

    };

    loadUser();

  }, []);


  <span class="hljs-keyword">const</span> login = <span class="hljs-keyword">async</span> (email, password) =&gt; {

    <span class="hljs-keyword">try</span> {

      <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> axios.post(<span class="hljs-string">'/api/auth/login'</span>, { email, password });

      setUser(res.data);

      <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;

    } <span class="hljs-keyword">catch</span> (err) {

      <span class="hljs-built_in">console</span>.error(err.response.data.message);

      <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;

    }

  };


  <span class="hljs-keyword">const</span> register = <span class="hljs-keyword">async</span> (username, email, password) =&gt; {

    <span class="hljs-keyword">try</span> {

      <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> axios.post(<span class="hljs-string">'/api/auth/register'</span>, { username, email, password });

      setUser(res.data);

      <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;

    } <span class="hljs-keyword">catch</span> (err) {

      <span class="hljs-built_in">console</span>.error(err.response.data.message);

      <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;

    }

  };


  <span class="hljs-keyword">const</span> logout = <span class="hljs-keyword">async</span> () =&gt; {

    <span class="hljs-keyword">try</span> {

      <span class="hljs-keyword">await</span> axios.get(<span class="hljs-string">'/api/auth/logout'</span>);

      setUser(<span class="hljs-literal">null</span>);

    } <span class="hljs-keyword">catch</span> (err) {

      <span class="hljs-built_in">console</span>.error(err);

    }

  };


  <span class="hljs-keyword">return</span> (

    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">AuthContext.Provider</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">user</span>, <span class="hljs-attr">loading</span>, <span class="hljs-attr">login</span>, <span class="hljs-attr">register</span>, <span class="hljs-attr">logout</span> }}&gt;</span>

      {children}

    <span class="hljs-tag">&lt;/<span class="hljs-name">AuthContext.Provider</span>&gt;</span></span>

  );

};


<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> AuthContext;
</code></pre>
<h4 id="heading-clientsrccomponentsnavbarjs">client/src/components/Navbar.js</h4>
<p>Here’s a dynamic navigation bar component that dynamically displays links based on the user's authentication status, showing either login/register options or a welcome message and logout button.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { useContext } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">import</span> { Link } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-router-dom'</span>;

<span class="hljs-keyword">import</span> AuthContext <span class="hljs-keyword">from</span> <span class="hljs-string">'../context/AuthContext'</span>;


<span class="hljs-keyword">const</span> Navbar = <span class="hljs-function">() =&gt;</span> {

  <span class="hljs-keyword">const</span> { user, logout } = useContext(AuthContext);


  <span class="hljs-keyword">return</span> (

    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">nav</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Task Manager<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>

        {user ? (

          <span class="hljs-tag">&lt;&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>Welcome, {user.username}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{logout}</span>&gt;</span>Logout<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/dashboard"</span>&gt;</span>Dashboard<span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>

          <span class="hljs-tag">&lt;/&gt;</span>

        ) : (

          <span class="hljs-tag">&lt;&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/login"</span>&gt;</span>Login<span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/register"</span>&gt;</span>Register<span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>

          <span class="hljs-tag">&lt;/&gt;</span></span>

        )}

      &lt;/div&gt;

    &lt;/nav&gt;

  );

};


<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Navbar;
</code></pre>
<h4 id="heading-clientsrccomponentsprivateroutejs">client/src/components/PrivateRoute.js</h4>
<p>To protect certain pages, we can create a Private Route component. This will be a guard for private routes, ensuring that only authenticated users can access them and redirecting unauthenticated users to the login page.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { useContext } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">import</span> { Navigate, Outlet } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-router-dom'</span>;

<span class="hljs-keyword">import</span> AuthContext <span class="hljs-keyword">from</span> <span class="hljs-string">'../context/AuthContext'</span>;


<span class="hljs-keyword">const</span> PrivateRoute = <span class="hljs-function">() =&gt;</span> {

  <span class="hljs-keyword">const</span> { user, loading } = useContext(AuthContext);


  <span class="hljs-keyword">if</span> (loading) {

    <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Loading...<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>; <span class="hljs-comment">// Or a spinner</span>

  }


  <span class="hljs-keyword">return</span> user ? <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Outlet</span> /&gt;</span></span> : <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Navigate</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/login"</span> <span class="hljs-attr">replace</span> /&gt;</span></span>;

};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> PrivateRoute;
</code></pre>
<h4 id="heading-clientsrcpagesregisterjs">client/src/pages/Register.js</h4>
<p>Now, let’s create the Register component, which provides a user registration form, handles input state and form submission, and displays success or error messages using toast notifications.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { useState, useContext } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">import</span> { useNavigate } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-router-dom'</span>;

<span class="hljs-keyword">import</span> { toast } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-toastify'</span>;

<span class="hljs-keyword">import</span> AuthContext <span class="hljs-keyword">from</span> <span class="hljs-string">'../context/AuthContext'</span>;


<span class="hljs-keyword">const</span> Register = <span class="hljs-function">() =&gt;</span> {

  <span class="hljs-keyword">const</span> [username, setUsername] = useState(<span class="hljs-string">''</span>);

  <span class="hljs-keyword">const</span> [email, setEmail] = useState(<span class="hljs-string">''</span>);

  <span class="hljs-keyword">const</span> [password, setPassword] = useState(<span class="hljs-string">''</span>);

  <span class="hljs-keyword">const</span> { register } = useContext(AuthContext);

  <span class="hljs-keyword">const</span> navigate = useNavigate();


  <span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-keyword">async</span> (e) =&gt; {

    e.preventDefault();

    <span class="hljs-keyword">const</span> success = <span class="hljs-keyword">await</span> register(username, email, password);

    <span class="hljs-keyword">if</span> (success) {

      toast.success(<span class="hljs-string">'Registration successful!'</span>);

      navigate(<span class="hljs-string">'/dashboard'</span>);

    } <span class="hljs-keyword">else</span> {

      toast.error(<span class="hljs-string">'Registration failed. Please try again.'</span>);

    }

  };


  <span class="hljs-keyword">return</span> (

    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Register<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleSubmit}</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>

          <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span>Username:<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>

          <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{username}</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setUsername(e.target.value)} required /&gt;

        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>

          <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span>Email:<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>

          <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{email}</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setEmail(e.target.value)} required /&gt;

        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>

          <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span>Password:<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>

          <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"password"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{password}</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setPassword(e.target.value)} required /&gt;

        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Register<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

      <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>

    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>

  );

};


<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Register;
</code></pre>
<h4 id="heading-clientsrcpagesloginjs">client/src/pages/Login.js</h4>
<p>Now, for the login form, it works similarly to the register page but logs users into the system instead. This page manages input fields, handles form submissions, and provides feedback via toast notifications.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { useState, useContext } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">import</span> { useNavigate } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-router-dom'</span>;

<span class="hljs-keyword">import</span> { toast } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-toastify'</span>;

<span class="hljs-keyword">import</span> AuthContext <span class="hljs-keyword">from</span> <span class="hljs-string">'../context/AuthContext'</span>;


<span class="hljs-keyword">const</span> Login = <span class="hljs-function">() =&gt;</span> {

  <span class="hljs-keyword">const</span> [email, setEmail] = useState(<span class="hljs-string">''</span>);

  <span class="hljs-keyword">const</span> [password, setPassword] = useState(<span class="hljs-string">''</span>);

  <span class="hljs-keyword">const</span> { login } = useContext(AuthContext);

  <span class="hljs-keyword">const</span> navigate = useNavigate();


  <span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-keyword">async</span> (e) =&gt; {

    e.preventDefault();

    <span class="hljs-keyword">const</span> success = <span class="hljs-keyword">await</span> login(email, password);

    <span class="hljs-keyword">if</span> (success) {

      toast.success(<span class="hljs-string">'Login successful!'</span>);

      navigate(<span class="hljs-string">'/dashboard'</span>);

    } <span class="hljs-keyword">else</span> {

      toast.error(<span class="hljs-string">'Login failed. Invalid credentials.'</span>);

    }

  };


  <span class="hljs-keyword">return</span> (

    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Login<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleSubmit}</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>

          <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span>Email:<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>

          <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{email}</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setEmail(e.target.value)} required /&gt;

        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>

          <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span>Password:<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>

          <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"password"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{password}</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setPassword(e.target.value)} required /&gt;

        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Login<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

      <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>

    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>

  );

};


<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Login;
</code></pre>
<h4 id="heading-clientsrcpagesdashboardjs">client/src/pages/Dashboard.js</h4>
<p>Finally, we’ll build the Dashboard page. This dashboard component displays a user's tasks, allowing them to create new tasks, mark tasks as complete or incomplete, and delete tasks, with real-time updates.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { useState, useEffect, useContext } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">'axios'</span>;

<span class="hljs-keyword">import</span> { toast } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-toastify'</span>;

<span class="hljs-keyword">import</span> AuthContext <span class="hljs-keyword">from</span> <span class="hljs-string">'../context/AuthContext'</span>;


<span class="hljs-keyword">const</span> Dashboard = <span class="hljs-function">() =&gt;</span> {

  <span class="hljs-keyword">const</span> { user } = useContext(AuthContext);

  <span class="hljs-keyword">const</span> [tasks, setTasks] = useState([]);

  <span class="hljs-keyword">const</span> [newTaskTitle, setNewTaskTitle] = useState(<span class="hljs-string">''</span>);

  <span class="hljs-keyword">const</span> [newTaskDescription, setNewTaskDescription] = useState(<span class="hljs-string">''</span>);


  useEffect(<span class="hljs-function">() =&gt;</span> {

    <span class="hljs-keyword">if</span> (user) {

      fetchTasks();

    }

  }, [user]);


  <span class="hljs-keyword">const</span> fetchTasks = <span class="hljs-keyword">async</span> () =&gt; {

    <span class="hljs-keyword">try</span> {

      <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> axios.get(<span class="hljs-string">'/api/tasks'</span>);

      setTasks(res.data);

    } <span class="hljs-keyword">catch</span> (err) {

      toast.error(<span class="hljs-string">'Failed to fetch tasks.'</span>);

      <span class="hljs-built_in">console</span>.error(err);

    }

  };


  <span class="hljs-keyword">const</span> handleCreateTask = <span class="hljs-keyword">async</span> (e) =&gt; {

    e.preventDefault();

    <span class="hljs-keyword">try</span> {

      <span class="hljs-keyword">await</span> axios.post(<span class="hljs-string">'/api/tasks'</span>, { <span class="hljs-attr">title</span>: newTaskTitle, <span class="hljs-attr">description</span>: newTaskDescription });

      setNewTaskTitle(<span class="hljs-string">''</span>);

      setNewTaskDescription(<span class="hljs-string">''</span>);

      toast.success(<span class="hljs-string">'Task created successfully!'</span>);

      fetchTasks();

    } <span class="hljs-keyword">catch</span> (err) {

      toast.error(<span class="hljs-string">'Failed to create task.'</span>);

      <span class="hljs-built_in">console</span>.error(err);

    }

  };


  <span class="hljs-keyword">const</span> handleUpdateTask = <span class="hljs-keyword">async</span> (id, completed) =&gt; {

    <span class="hljs-keyword">try</span> {

      <span class="hljs-keyword">await</span> axios.put(<span class="hljs-string">`/api/tasks/<span class="hljs-subst">${id}</span>`</span>, { completed });

      toast.success(<span class="hljs-string">'Task updated successfully!'</span>);

      fetchTasks();

    } <span class="hljs-keyword">catch</span> (err) {

      toast.error(<span class="hljs-string">'Failed to update task.'</span>);

      <span class="hljs-built_in">console</span>.error(err);

    }

  };


  <span class="hljs-keyword">const</span> handleDeleteTask = <span class="hljs-keyword">async</span> (id) =&gt; {

    <span class="hljs-keyword">try</span> {

      <span class="hljs-keyword">await</span> axios.delete(<span class="hljs-string">`/api/tasks/<span class="hljs-subst">${id}</span>`</span>);

      toast.success(<span class="hljs-string">'Task deleted successfully!'</span>);

      fetchTasks();

    } <span class="hljs-keyword">catch</span> (err) {

      toast.error(<span class="hljs-string">'Failed to delete task.'</span>);

      <span class="hljs-built_in">console</span>.error(err);

    }

  };


  <span class="hljs-keyword">return</span> (

    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Welcome, {user ? user.username : 'Guest'}!<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>Your Tasks<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleCreateTask}</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">input</span>

          <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>

          <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"New Task Title"</span>

          <span class="hljs-attr">value</span>=<span class="hljs-string">{newTaskTitle}</span>

          <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setNewTaskTitle(e.target.value)}

          required

        /&gt;

        <span class="hljs-tag">&lt;<span class="hljs-name">input</span>

          <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>

          <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Description (optional)"</span>

          <span class="hljs-attr">value</span>=<span class="hljs-string">{newTaskDescription}</span>

          <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setNewTaskDescription(e.target.value)}

        /&gt;

        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Add Task<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

      <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>

        {tasks.map((task) =&gt; (

          <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{task._id}</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">textDecoration:</span> <span class="hljs-attr">task.completed</span> ? '<span class="hljs-attr">line-through</span>' <span class="hljs-attr">:</span> '<span class="hljs-attr">none</span>' }}&gt;</span>

              {task.title}: {task.description}

            <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> handleUpdateTask(task._id, !task.completed)}&gt;

              {task.completed ? 'Mark Incomplete' : 'Mark Complete'}

            <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> handleDeleteTask(task._id)}&gt;Delete<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

          <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>

        ))}

      <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>

    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>

  );

};


<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Dashboard;
</code></pre>
<h2 id="heading-deployment-from-localhost-to-live"><strong>Deployment: From Localhost to Live</strong></h2>
<p>Deploying a MERN stack application involves deploying the backend API and the frontend React application separately.</p>
<p>Let’s talk about why we do it separately. As you have seen from above, in a MERN stack app, the frontend and backend are separate by design. React handles the UI, while Express and Node handle server logic and API calls. Because they serve different roles, you'll need to deploy them separately.</p>
<p>The backend runs on a Node.js compatible server, which connects to a database such as MongoDB Atlas. The frontend, once it is built, becomes static files that can be hosted from anywhere, from NGINX to hosting platforms like Netlify or Vercel.</p>
<p>This separation provides you with flexibility and improved scalability. Let’s walk through how to deploy each part.</p>
<h3 id="heading-backend-deployment-nodejsexpressjs"><strong>Backend Deployment (Node.js/Express.js)</strong></h3>
<p>For backend deployment, platforms like Heroku, Render, or AWS EC2 are common choices. Here, I’ll outline a general approach for a cloud VM on AWS EC2</p>
<h4 id="heading-1-prepare-for-production">1. Prepare for Production</h4>
<p>To start, set the environment to <code>production</code> and install only the dependencies your app needs to run, optimizing your application's performance. Skipping devDependencies helps reduce its footprint.</p>
<pre><code class="lang-bash"><span class="hljs-built_in">export</span> NODE_ENV=production

npm install --production
</code></pre>
<h4 id="heading-2-process-manager-pm2">2. Process Manager (PM2)</h4>
<p>Next, we’ll set up a process manager to keep our backend server running reliably. PM2 is a popular tool that handles automatic restarts if your Node.js application crashes, manages multiple app instances, and also helps ensure high availability in production environments.</p>
<pre><code class="lang-bash">npm install -g pm2

pm2 start server/app.js --name mern-api

pm2 save

pm2 startup
</code></pre>
<h4 id="heading-3-nginx-as-a-reverse-proxy">3. NGINX as a Reverse Proxy</h4>
<p>Now that our backend is running with PM2, we need a way to handle incoming web traffic. That’s where NGINX comes in. We'll install NGINX to serve as a high-performance reverse proxy directing incoming web traffic to your Node.js backend and serving static frontend files.</p>
<pre><code class="lang-bash">sudo apt update

sudo apt install nginx
</code></pre>
<p>Once NGINX is installed, it’s time to configure it (/etc/nginx/sites-available/default or a new config file). We’ll set it up to forward API requests to the backend and serve the React app, acting as the single entry point. You can update the default configuration file or create a new one:</p>
<pre><code class="lang-nginx"><span class="hljs-comment"># /etc/nginx/sites-available/default</span>
<span class="hljs-section">server</span> {

    <span class="hljs-attribute">listen</span> <span class="hljs-number">80</span>;

    <span class="hljs-attribute">server_name</span> your_domain_or_ip;


    <span class="hljs-attribute">location</span> /api/ {

        <span class="hljs-attribute">proxy_pass</span> http://localhost:5000;

        <span class="hljs-attribute">proxy_http_version</span> <span class="hljs-number">1</span>.<span class="hljs-number">1</span>;

        <span class="hljs-attribute">proxy_set_header</span> Upgrade <span class="hljs-variable">$http_upgrade</span>;

        <span class="hljs-attribute">proxy_set_header</span> Connection <span class="hljs-string">'upgrade'</span>;

        <span class="hljs-attribute">proxy_set_header</span> Host <span class="hljs-variable">$host</span>;

        <span class="hljs-attribute">proxy_cache_bypass</span> <span class="hljs-variable">$http_upgrade</span>;

    }


    <span class="hljs-attribute">location</span> / {

        <span class="hljs-attribute">root</span> /var/www/my-mern-app/client/build; <span class="hljs-comment"># Path to your React build folder</span>

        <span class="hljs-attribute">try_files</span> <span class="hljs-variable">$uri</span> /index.html;

    }

}
</code></pre>
<p>With the NGINX configuration created, we’ll enable it and restart the service to apply the changes, making your application go live:</p>
<pre><code class="lang-bash">sudo ln -s /etc/nginx/sites-available/default /etc/nginx/sites-enabled/

sudo systemctl restart nginx
</code></pre>
<h4 id="heading-4-https-with-certbot-lets-encrypt">4. HTTPS with Certbot (Let's Encrypt)</h4>
<p>To secure your app with HTTPS, we can install Certbot and use it to automatically obtain and configure a free SSL/TLS certificate from Let’s Encrypt, enabling secure HTTPS connections for your domain.</p>
<pre><code class="lang-bash">sudo snap install --classic certbot

sudo certbot --nginx -d your_domain_or_ip
</code></pre>
<h3 id="heading-frontend-deployment-react"><strong>Frontend Deployment (React)</strong></h3>
<p>With the backend deployed, let’s move to the frontend. For the React frontend, we’ll build the application and serve the static files via NGINX (as shown above) or a dedicated static site hosted on platforms like Netlify, Vercel, or AWS S3 + CloudFront.</p>
<h4 id="heading-build-the-react-app">Build the React App</h4>
<p>This command compiles and optimizes your React application into a build folder containing static assets, ready for efficient deployment to any web server or static hosting service.</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> client

npm run build
</code></pre>
<h3 id="heading-database-deployment-mongodb-atlas"><strong>Database Deployment (MongoDB Atlas)</strong></h3>
<p>For production, we’ll use a managed MongoDB service like MongoDB Atlas. It handles replication, sharding, and backups, simplifying database management significantly.</p>
<h4 id="heading-create-a-cluster-on-mongodb-atlas">Create a Cluster on MongoDB Atlas</h4>
<ul>
<li><p>Sign up/Log in to MongoDB Atlas.</p>
</li>
<li><p>Create a new cluster (choose a cloud provider and region).</p>
</li>
<li><p>Set up a database user with appropriate permissions.</p>
</li>
<li><p>Configure network access (allow connections from your server's IP address).</p>
</li>
<li><p>Get your connection string and update MONGO_URI in your server/.env file.</p>
</li>
</ul>
<h4 id="heading-1-env-configuration-example">1. <code>.env</code> Configuration Example</h4>
<p>After creating the cluster and user in MongoDB Atlas, you’ll receive a connection string. You need to update your <code>.env</code> file with it</p>
<pre><code class="lang-ini"><span class="hljs-comment"># server/.env</span>
<span class="hljs-attr">MONGO_URI</span>=mongodb+srv://yourUser:yourPassword@cluster0.mongodb.net/yourDBName
<span class="hljs-attr">JWT_SECRET</span>=your_secret_jwt_key
<span class="hljs-attr">NODE_ENV</span>=production
</code></pre>
<h4 id="heading-2-connect-to-mongodb-in-appjs">2. Connect to MongoDB in <code>app.js</code></h4>
<p>Next, in the <code>server/app.js</code> file, make sure you're using the connection string from the environment variable:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> mongoose = <span class="hljs-built_in">require</span>(<span class="hljs-string">'mongoose'</span>);
<span class="hljs-keyword">const</span> dotenv = <span class="hljs-built_in">require</span>(<span class="hljs-string">'dotenv'</span>);
dotenv.config();

mongoose.connect(process.env.MONGO_URI)
  .then(<span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'MongoDB connected!'</span>))
  .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Connection error:'</span>, err));
</code></pre>
<h3 id="heading-other-deployment-options"><strong>Other Deployment Options</strong></h3>
<p>While this article drives you through manual deployment with EC2 and NGINX, other platforms can simplify the process:</p>
<ul>
<li><p><strong>Render</strong>, <strong>Railway</strong>, and <strong>Heroku</strong> offer easy full-stack deployment with GitHub integration.</p>
</li>
<li><p><strong>Vercel</strong> and <strong>Netlify</strong> are ideal for hosting the React frontend.</p>
</li>
<li><p>You may consider using <strong>Docker</strong> to maintain consistent environments across development and production.</p>
</li>
<li><p>For CI/CD, Linting, Testing, &amp; Deployment can be automated on every push using tools like <strong>GitHub Actions</strong></p>
</li>
</ul>
<p>There is no right or wrong choice here. Select the setup that best suits your project’s scale, team experience, and desired level of control.</p>
<h2 id="heading-security-best-practices-fortifying-your-application"><strong>Security Best Practices: Fortifying Your Application</strong></h2>
<p>Security is paramount. You can implement these best practices to protect your MERN application.</p>
<h3 id="heading-setup-input-validation-and-sanitization"><strong>Setup Input Validation and Sanitization</strong></h3>
<p>Always validate and sanitize input on the server side. You can use libraries like Joi or Zod to make this process easier.</p>
<h4 id="heading-example-with-joi">Example with Joi:</h4>
<p>To validate and sanitize incoming data on the server, we will utilize Joi, a powerful library for defining schemas and enforcing input rules.</p>
<pre><code class="lang-bash">npm install joi
</code></pre>
<p>Now that we’ve installed Joi, we will use it to define strict validation rules for user registration and login inputs. This ensures data quality and prevents common injection attacks.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// server/validators/authValidator.js</span>

<span class="hljs-keyword">const</span> Joi = <span class="hljs-built_in">require</span>(<span class="hljs-string">'joi'</span>);


<span class="hljs-keyword">const</span> registerSchema = Joi.object({

  <span class="hljs-attr">username</span>: Joi.string().min(<span class="hljs-number">3</span>).max(<span class="hljs-number">30</span>).required(),

  <span class="hljs-attr">email</span>: Joi.string().email().required(),

  <span class="hljs-attr">password</span>: Joi.string().min(<span class="hljs-number">6</span>).required(),

});


<span class="hljs-keyword">const</span> loginSchema = Joi.object({

  <span class="hljs-attr">email</span>: Joi.string().email().required(),

  <span class="hljs-attr">password</span>: Joi.string().required(),

});


<span class="hljs-built_in">module</span>.exports = { registerSchema, loginSchema };
</code></pre>
<p>Next, we’ll integrate these schemas directly into our authentication controller to automatically validate incoming request bodies against predefined schemas.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// server/controllers/authController.js (snippet)</span>

<span class="hljs-keyword">const</span> { registerSchema, loginSchema } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'../validators/authValidator'</span>);


<span class="hljs-built_in">exports</span>.registerUser = <span class="hljs-keyword">async</span> (req, res) =&gt; {

  <span class="hljs-keyword">const</span> { error } = registerSchema.validate(req.body);

  <span class="hljs-keyword">if</span> (error) <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">400</span>).json({ <span class="hljs-attr">message</span>: error.details[<span class="hljs-number">0</span>].message });

  <span class="hljs-comment">// ... rest of the registration logic</span>

};


<span class="hljs-built_in">exports</span>.loginUser = <span class="hljs-keyword">async</span> (req, res) =&gt; {

  <span class="hljs-keyword">const</span> { error } = loginSchema.validate(req.body);

  <span class="hljs-keyword">if</span> (error) <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">400</span>).json({ <span class="hljs-attr">message</span>: error.details[<span class="hljs-number">0</span>].message });

  <span class="hljs-comment">// ... rest of the login logic</span>

};
</code></pre>
<h3 id="heading-add-authentication-and-authorization"><strong>Add Authentication and Authorization</strong></h3>
<p>You can use JWTs for authentication and implement middleware for protected routes.</p>
<h4 id="heading-jwt-implementation-covered-in-authcontrollerjs-and-authmiddlewarejs-above">JWT Implementation (covered in authController.js and authMiddleware.js above)</h4>
<p>Key aspects:</p>
<ul>
<li><p>HttpOnly Cookies: Store JWTs in HttpOnly cookies to prevent client-side JavaScript access, mitigating XSS attacks.</p>
</li>
<li><p>Secure Flag: Use secure: true in production to ensure cookies are only sent over HTTPS.</p>
</li>
</ul>
<p>These practices ensure that authentication tokens are securely transmitted and stored, protecting against common web vulnerabilities like Cross-Site Scripting (XSS).</p>
<h3 id="heading-implement-rate-limiting"><strong>Implement Rate Limiting</strong></h3>
<p>To protect our API from abuse and malicious intent, we will implement basic rate limiting. This helps protect against brute-force login attempts and DDoS attacks.</p>
<h4 id="heading-installation">Installation</h4>
<p>We will install express-rate-limit package for it</p>
<pre><code class="lang-bash">npm install express-rate-limit
</code></pre>
<h4 id="heading-serverappjs-snippet">server/app.js (snippet)</h4>
<p>Once it is installed, let’s configure the rate limiter and apply it to all incoming requests. This ensures that no single IP can overwhelm your server with repeated calls. The following middleware limits each IP address to 200 requests within a 15-minute window.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> rateLimit = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express-rate-limit'</span>);

<span class="hljs-keyword">const</span> limiter = rateLimit({

  <span class="hljs-attr">windowMs</span>: <span class="hljs-number">15</span> * <span class="hljs-number">60</span> * <span class="hljs-number">1000</span>, <span class="hljs-comment">// 15 minutes</span>

  <span class="hljs-attr">max</span>: <span class="hljs-number">200</span>, <span class="hljs-comment">// Limit each IP to 200 requests per windowMs</span>

  <span class="hljs-attr">message</span>: <span class="hljs-string">'Too many requests from this IP, please try again after 15 minutes'</span>,

});

app.use(limiter); <span class="hljs-comment">// Apply to all requests</span>
</code></pre>
<h3 id="heading-setup-cors-configuration-cross-origin-resource-sharing"><strong>Setup CORS Configuration (Cross-Origin Resource Sharing)</strong></h3>
<p>Next, we move our focus to enable secure communication between your frontend and backend. By default, all browsers block cross-origin requests, so we need to configure CORS (Cross-Origin Resource Sharing) to permit the React app to communicate with the Express API.</p>
<h4 id="heading-installation-1">Installation</h4>
<pre><code class="lang-bash">npm install cors
</code></pre>
<h4 id="heading-serverappjs-snippet-1">server/app.js (snippet)</h4>
<p>Once installed<strong>,</strong> we can configure CORS for our Express application, specifying allowed origins and enabling credential sharing for secure cross-origin requests. Remember to replace the origin with your actual production URL when deploying.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> cors = <span class="hljs-built_in">require</span>(<span class="hljs-string">'cors'</span>);

app.use(cors({

  <span class="hljs-attr">origin</span>: <span class="hljs-string">'http://localhost:3000'</span>, <span class="hljs-comment">// Replace with your frontend URL in production</span>

  <span class="hljs-attr">credentials</span>: <span class="hljs-literal">true</span>,

}));
</code></pre>
<h3 id="heading-use-environment-variables"><strong>Use Environment Variables</strong></h3>
<p>To keep sensitive information secure and out of your codebase, we will use environment variables. This allows us to efficiently manage secrets, such as database connection strings and JWT keys, without hardcoding them or including them in the source code.</p>
<p>Create a <code>.env</code> file in your <code>server/</code> directory:</p>
<h4 id="heading-env-example">.env (example)</h4>
<p>This .env file stores sensitive configuration details like database connection strings and API keys</p>
<pre><code class="lang-ini"><span class="hljs-attr">MONGO_URI</span>=your_mongodb_connection_string

<span class="hljs-attr">JWT_SECRET</span>=your_super_secret_jwt_key

<span class="hljs-attr">NODE_ENV</span>=production
</code></pre>
<h2 id="heading-monitoring-and-logging-with-winston-and-morgan"><strong>Monitoring and Logging with Winston and Morgan</strong></h2>
<p>Once the application is live, it's critical to monitor the behavior and catch issues promptly. Monitoring and logging help you measure performance, find bugs, and keep a log of all server activity.</p>
<p>We’ll use Morgan for logging HTTP requests and Winston for more general-purpose application logging.</p>
<h3 id="heading-installation-2">Installation</h3>
<p>We will install Morgan for logging HTTP requests and Winston for comprehensive and customizable application logging.</p>
<pre><code class="lang-bash">npm install morgan winston
</code></pre>
<h3 id="heading-serverconfigloggerjs">server/config/logger.js</h3>
<p>Next, let’s configure Winston to handle our application logs. This will output logs to the console by default, with options to enable file-based logging for errors and general information.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> winston = <span class="hljs-built_in">require</span>(<span class="hljs-string">'winston'</span>);

<span class="hljs-keyword">const</span> logger = winston.createLogger({

  <span class="hljs-attr">level</span>: <span class="hljs-string">'info'</span>,

  <span class="hljs-attr">format</span>: winston.format.combine(

    winston.format.timestamp(),

    winston.format.json()

  ),

  <span class="hljs-attr">transports</span>: [

    <span class="hljs-keyword">new</span> winston.transports.Console(),

    <span class="hljs-comment">// new winston.transports.File({ filename: 'error.log', level: 'error' }),</span>

    <span class="hljs-comment">// new winston.transports.File({ filename: 'combined.log', level: 'info' }),</span>

  ],

});

<span class="hljs-built_in">module</span>.exports = logger;
</code></pre>
<h3 id="heading-serverappjs-snippet-2">server/app.js (snippet)</h3>
<p>With Winston and Morgan set up, now let’s integrate them into our <code>app.js</code> file. We’ll use Morgan for request logging during development and replace standard <code>console.log</code> calls with Winston logs for structured and configurable application logging.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> morgan = <span class="hljs-built_in">require</span>(<span class="hljs-string">'morgan'</span>);

<span class="hljs-keyword">const</span> logger = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./config/logger'</span>);

<span class="hljs-keyword">if</span> (process.env.NODE_ENV === <span class="hljs-string">'development'</span>) {

  app.use(morgan(<span class="hljs-string">'dev'</span>));

}

<span class="hljs-comment">// Replace console.log with logger.info for database connection</span>

mongoose.connect(process.env.MONGO_URI)

  .then(<span class="hljs-function">() =&gt;</span> logger.info(<span class="hljs-string">'MongoDB connected!'</span>))

  .catch(<span class="hljs-function"><span class="hljs-params">err</span> =&gt;</span> logger.error(<span class="hljs-string">'MongoDB connection error:'</span>, err));


<span class="hljs-comment">// Replace console.log in app.listen</span>

app.listen(PORT, <span class="hljs-function">() =&gt;</span> {

  logger.info(<span class="hljs-string">`Server running on port <span class="hljs-subst">${PORT}</span>`</span>);

});
</code></pre>
<h3 id="heading-frontend-error-monitoring-sentry"><strong>Frontend Error Monitoring (Sentry)</strong></h3>
<p>To monitor errors in the frontend, we’ll integrate Sentry. It’s a fantastic tool for tracking exceptions and performance issues in real time. It helps us capture and report client-side errors.</p>
<h4 id="heading-installation-3">Installation</h4>
<pre><code class="lang-bash">npm install @sentry/react @sentry/tracing
</code></pre>
<h4 id="heading-clientsrcindexjs-snippet">client/src/index.js (snippet)</h4>
<p>After installation, let’s initialize Sentry in the React application so that it can automatically capture errors and performance data. We’ll add this to our <code>index.js</code> file.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> Sentry <span class="hljs-keyword">from</span> <span class="hljs-string">'@sentry/react'</span>;

<span class="hljs-keyword">import</span> { BrowserTracing } <span class="hljs-keyword">from</span> <span class="hljs-string">'@sentry/tracing'</span>;


Sentry.init({

  <span class="hljs-attr">dsn</span>: <span class="hljs-string">"YOUR_SENTRY_DSN"</span>, <span class="hljs-comment">// Replace with your Sentry DSN</span>

  <span class="hljs-attr">integrations</span>: [<span class="hljs-keyword">new</span> BrowserTracing()],

  <span class="hljs-attr">tracesSampleRate</span>: <span class="hljs-number">1.0</span>,

  <span class="hljs-attr">environment</span>: process.env.NODE_ENV,

});
</code></pre>
<p>And that’s it! Congratulations on building and deploying a full-stack MERN app.</p>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>This article provided a code-first walkthrough of building, securing, and deploying a MERN stack application. By focusing on practical code examples and essential configurations, you now have a solid foundation for your MERN projects.</p>
<p>Remember, continuous learning and adaptation are key in the ever-evolving world of web development. Happy coding!</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
