basicaly i am writing code setup here only for me. Because i am facing lots of dificulty in development and geting a good job
This setup i usfe in code

import UserModel from "../model/User.js";
import bcrypt from 'bcrypt';
import dotenv from 'dotenv';
import sendEmailVerificationByOTP from "../utils/sendEmailVerificationByOTP.js";
import EmailVerificationModel from "../model/EmailVerificaion.js";
import transporter from "../config/emailConfig.js";
import jwt from "jsonwebtoken"
dotenv.config();

// signup user
const signup = async (req, res) => {
  try {
    const { name, email, password } = req.body;
    // all field is require
    if (!name || !email || !password ){
      return res.status(400).json({ status: "failed", message: "All fields are required" })
    }
    // user already exist
    const existingUser = await UserModel.findOne({ email });
    if (existingUser) {
      return res.status(400).json({ status: "Fail", message: "User already exist" })
    }
    // salt 
    const salt = await bcrypt.genSalt(Number(process.env.SALT));

    // hasspassword 
    const hasspassword = await bcrypt.hash(password, salt)

    const newUser = await new UserModel({
      name,
      email,
      password: hasspassword
    }).save();

    //CALL  send otp to user
    sendEmailVerificationByOTP(req, newUser)

    res.status(200).json({
      status: "sucess",
      message: "your accoount is sucessfuly created",
      user: { id: newUser._id, email: newUser.email }
    })


  } catch (error) {
    console.error(error)
    return res.status(400).json({ status: "failed", message: "Unable to Register, please try again later" })
  }

}

// Verify email
const verifyEmail = async (req, res) => {
  try {
    const { email, otp } = req.body;
    // Check if all required fields are provided
    if (!email || !otp) {
      return res.status(400).json({ status: "failed", message: "All fields are required" });
    }
    // Check if the email exists
    const userEmail = await UserModel.findOne({ email });
    if (!userEmail) {
      return res.status(400).json({ status: "failed", message: "Email does not exist" });
    }
    // Check if the email is already verified
    if (userEmail.is_verified) {
      return res.status(400).json({ status: "failed", message: "This email is already verified" });
    }
    // Check if there is a matching email verification OTP
    const emailVerification = await EmailVerificationModel.findOne({ userId: userEmail._id, otp });
    if (!emailVerification) {
      // Resend OTP if not verified
      await sendEmailVerificationByOTP(req, userEmail);
      return res.status(400).json({ status: "failed", message: "Invalid OTP. A new OTP has been sent to your email." });
    }
    // Check if OTP is expired
    const currentTime = new Date();
    const expirationTime = new Date(emailVerification.createdAt.getTime() + 15 * 60 * 1000); // 15 minutes
    if (currentTime > expirationTime) {
      // OTP expired, send new OTP
      await sendEmailVerificationByOTP(req, userEmail);
      return res.status(400).json({ status: "failed", message: "OTP expired. A new OTP has been sent to your email." });
    }
    // Mark the user's email as verified
    userEmail.is_verified = true;
    await userEmail.save();
    // Remove all OTP entries for the user
    await EmailVerificationModel.deleteMany({ userId: userEmail._id });

    return res.status(200).json({ status: "success", message: "Email verified successfully" });

  } catch (error) {
    console.error(error);
    return res.status(500).json({ status: "failed", message: "An error occurred while verifying the email." });
  }
};


// User Login
const Login = async (req, res) => {
  try {
    const { email, password } = req.body
    // All field is require
    if (!email || !password) {
      return res.status(400).json({ status: "fail to login", message: "All field is required" })
    }
    // Email is exist or not
    const user = await UserModel.findOne({ email })
    if (!user) {
      return res.status(400).json({ status: "Fail to login", message: "Email or password is not exist" })
    }
    // is user is verified or not
    if (!user.is_verified) {
      return res.status(400).json({ status: "fail to login", message: "Account is not active" })
    }

    // Check the user password is match or not
    const isMatch = await bcrypt.compare(password, user.password)
    //if password is not match
    if (!isMatch) {
      return res.status(400).json({ status: "Fail to login", message: "password is not same" })
    }
    // Generate single long-lived token (30 days)
    console.log("JWT Secret Key:", process.env.JWT_SECRET_KEY);
    const tokenExp = Math.floor(Date.now() / 1000) + (30 * 24 * 60 * 60);
    const token = jwt.sign(
      { 
        id: user._id, 
        roles: user.role[0],
        exp: tokenExp 
      },
      process.env.JWT_SECRET_KEY
    );

    // Send response 
    res.status(200).json({
      user: { id: user._id, email: user.email, name: user.name, roles: user.role[0] },
      status: "success",
      message: "Login successful",
      token,
      token_exp: tokenExp,
      is_auth: true
    });

  } catch (error) {
    console.log(error)
    res.status(400).json({ status: "Fail to login", message: "" })
  }
}

// profile
const userProfile = async (req, res) => {
  res.send({ "user": req.user })
}

// Change Password
const changePassword = async (req, res) => {
  try {
    const { password, confirm_password } = req.body
    if (!password || !confirm_password) {
      res.status(400).json({ statu: "Fail", message: "all filed is require" })
    }
    if (password !== confirm_password) {
      res.statu(400).json({ status: "Fail", message: "Password is not match" })
    }
    const salt = await bcrypt.genSalt(Number(process.env.SALT))

    const hashPassword = await bcrypt.hash(password, salt)
    await UserModel.findByIdAndUpdate(req.user._id, { $set: { password: hashPassword } })
    // Send success response
    res.status(200).json({ status: "success", message: "Password changed successfully" });
  } catch (error) {
    console.error(error);
    res.status(500).json({ status: "failed", message: "Unable to change password, please try again later" });
  }
}

// Send Password Reset Link via Email
const sendUserPasswordResetEmail = async (req, res) => {
  try {
    // Extract email from req.body
    const { email } = req.body;

    // Check if email is provided
    if (!email) {
      return res.status(400).json({ status: "failed", message: "Email field is required" });
    }

    // Find user by email
    const user = await UserModel.findOne({ email: email });
    if (!user) {
      return res.status(404).json({ status: "failed", message: "Email doesn't exist" });
    }

    // Create a secret and token for password reset
    const secret = user._id + process.env.JWT_ACCESS_TOKEN_SECRET_KEY;
    const token = jwt.sign({ userId: user._id }, secret, { expiresIn: '15m' });

    // Construct the reset password link
    const resetLink = `${process.env.FRONTEND_HOST}/account/reset-password-confirm/${user._id}/${token}`;
    console.log(resetLink)
    // Send password reset email
    await transporter.sendMail({
      from: process.env.EMAIL_FROM,
      to: user.email,
      subject: "Reset your password",
      html: `<p>Hello ${user.name},</p><p>Please <a href="${resetLink}">click here</a> to reset your password.</p>`,
    });

    // Respond with success
    res.status(200).json({ status: "success", message: "Password reset email sent. Please check your email." });
  } catch (error) {
    console.error(error);
    res.status(500).json({ status: "failed", message: "Unable to send password reset email. Please try again later." });
  }
};

// reset password
const resetPassword = async (req, res) => {
  try {
    const { password, confirm_password } = req.body;
    const { id, token } = req.params;
    // Find user by ID
    const user = await UserModel.findById(id);
    if (!user) {
      return res.status(404).json({ status: "failed", message: "User not found" });
    }
    // Validate token
    const new_secret = user._id + process.env.JWT_ACCESS_TOKEN_SECRET_KEY;
    jwt.verify(token, new_secret);

    // Check if password and password_confirmation are provided
    if (!password || !confirm_password) {
      return res.status(400).json({ status: "failed", message: "New Password and Confirm New Password are required" });
    }

    // Check if password and password_confirmation match
    if (password !== confirm_password) {
      return res.status(400).json({ status: "failed", message: "New Password and Confirm New Password don't match" });
    }

    // Generate salt and hash new password
    const salt = await bcrypt.genSalt(10);
    const newHashPassword = await bcrypt.hash(password, salt);

    // Update user's password
    await UserModel.findByIdAndUpdate(user._id, { $set: { password: newHashPassword } });

    // Send success response
    res.status(200).json({ status: "success", message: "Password reset successfully" });

  } catch (error) {
    console.log(error);
    if (error.name === "TokenExpiredError") {
      return res.status(400).json({ status: "failed", message: "Token expired. Please request a new password reset link." });
    }
    return res.status(500).json({ status: "failed", message: "Unable to reset password. Please try again later." });
  }
}

// Logout
const Logout = async (req, res) => {
  try {
    res.clearCookie('accessToken');
    res.clearCookie('refreshToken');
    res.clearCookie('is_auth');
    res.status(200).json({ status: "success", message: "Logout successfully done" });
  } catch (error) {
    console.error(error);
    res.status(500).json({ status: "failed", message: "Unable to logout, please try again later" });
  }
};

export { signup,  verifyEmail, Login,  userProfile, Logout, changePassword, resetPassword, sendUserPasswordResetEmail };

Author Of article : Harendra Read full article