Employee Task Management System.

 Perfect ✅ Let’s build a starter project structure for your Employee Task Management System.

This is the kind of boilerplate you’d set up in the first 30 minutes of a 3-hour exam, so you can then focus on implementing business logic.


📂 Project Structure

employee-task-manager/
│── node_modules/
│── src/
│   ├── config/
│   │   └── db.js          # Database connection
│   ├── controllers/
│   │   ├── authController.js
│   │   └── taskController.js
│   ├── middleware/
│   │   ├── authMiddleware.js
│   │   └── errorMiddleware.js
│   ├── models/
│   │   ├── User.js
│   │   └── Task.js
│   ├── routes/
│   │   ├── authRoutes.js
│   │   └── taskRoutes.js
│   ├── utils/
│   │   └── logger.js
│   ├── app.js             # Express app config
│   └── server.js          # Entry point
│── .env
│── package.json

📦 Install Dependencies

npm init -y
npm install express bcryptjs jsonwebtoken dotenv pg sequelize
npm install joi helmet cors morgan winston
npm install nodemon --save-dev

⚙️ src/config/db.js (Database Setup with Sequelize + PostgreSQL)

const { Sequelize } = require("sequelize");

const sequelize = new Sequelize(
  process.env.DB_NAME,
  process.env.DB_USER,
  process.env.DB_PASS,
  {
    host: process.env.DB_HOST || "localhost",
    dialect: "postgres", // change to "mysql" if needed
    logging: false,
  }
);

module.exports = sequelize;

👤 src/models/User.js

const { DataTypes } = require("sequelize");
const sequelize = require("../config/db");

const User = sequelize.define("User", {
  id: { type: DataTypes.INTEGER, autoIncrement: true, primaryKey: true },
  name: { type: DataTypes.STRING, allowNull: false },
  email: { type: DataTypes.STRING, allowNull: false, unique: true },
  password: { type: DataTypes.STRING, allowNull: false },
  role: { type: DataTypes.ENUM("Admin", "Manager", "Employee"), defaultValue: "Employee" },
});

module.exports = User;

src/models/Task.js

const { DataTypes } = require("sequelize");
const sequelize = require("../config/db");
const User = require("./User");

const Task = sequelize.define("Task", {
  id: { type: DataTypes.INTEGER, autoIncrement: true, primaryKey: true },
  title: { type: DataTypes.STRING, allowNull: false },
  description: { type: DataTypes.TEXT },
  status: { type: DataTypes.ENUM("Pending", "Completed"), defaultValue: "Pending" },
});

Task.belongsTo(User, { foreignKey: "assignedTo" });

module.exports = Task;

🔑 src/controllers/authController.js

const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");
const User = require("../models/User");

exports.register = async (req, res, next) => {
  try {
    const { name, email, password, role } = req.body;
    const hashedPassword = await bcrypt.hash(password, 10);
    const user = await User.create({ name, email, password: hashedPassword, role });
    res.status(201).json({ message: "User registered", user });
  } catch (err) {
    next(err);
  }
};

exports.login = async (req, res, next) => {
  try {
    const { email, password } = req.body;
    const user = await User.findOne({ where: { email } });
    if (!user) return res.status(401).json({ message: "Invalid credentials" });

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

    const token = jwt.sign({ id: user.id, role: user.role }, process.env.JWT_SECRET, {
      expiresIn: "1h",
    });

    res.json({ token });
  } catch (err) {
    next(err);
  }
};

📋 src/controllers/taskController.js

const Task = require("../models/Task");
const User = require("../models/User");

exports.createTask = async (req, res, next) => {
  try {
    const { title, description, assignedTo } = req.body;
    const task = await Task.create({ title, description, assignedTo });
    res.status(201).json(task);
  } catch (err) {
    next(err);
  }
};

exports.getTasks = async (req, res, next) => {
  try {
    const tasks = await Task.findAll({ include: User });
    res.json(tasks);
  } catch (err) {
    next(err);
  }
};

exports.updateTaskStatus = async (req, res, next) => {
  try {
    const { id } = req.params;
    const { status } = req.body;
    const task = await Task.findByPk(id);
    if (!task) return res.status(404).json({ message: "Task not found" });
    task.status = status;
    await task.save();
    res.json(task);
  } catch (err) {
    next(err);
  }
};

🔐 src/middleware/authMiddleware.js

const jwt = require("jsonwebtoken");

exports.authMiddleware = (req, res, next) => {
  const token = req.headers["authorization"];
  if (!token) return res.status(401).json({ message: "No token provided" });

  try {
    const decoded = jwt.verify(token.split(" ")[1], process.env.JWT_SECRET);
    req.user = decoded;
    next();
  } catch (err) {
    return res.status(401).json({ message: "Invalid token" });
  }
};

exports.roleMiddleware = (roles) => {
  return (req, res, next) => {
    if (!roles.includes(req.user.role)) {
      return res.status(403).json({ message: "Access denied" });
    }
    next();
  };
};

🚦 src/middleware/errorMiddleware.js

exports.errorHandler = (err, req, res, next) => {
  console.error(err.stack);
  res.status(500).json({ message: err.message });
};

🌍 src/routes/authRoutes.js

const express = require("express");
const { register, login } = require("../controllers/authController");
const router = express.Router();

router.post("/register", register);
router.post("/login", login);

module.exports = router;

📌 src/routes/taskRoutes.js

const express = require("express");
const { createTask, getTasks, updateTaskStatus } = require("../controllers/taskController");
const { authMiddleware, roleMiddleware } = require("../middleware/authMiddleware");
const router = express.Router();

router.post("/", authMiddleware, roleMiddleware(["Admin", "Manager"]), createTask);
router.get("/", authMiddleware, getTasks);
router.patch("/:id", authMiddleware, roleMiddleware(["Employee", "Manager"]), updateTaskStatus);

module.exports = router;

🚀 src/app.js

const express = require("express");
const dotenv = require("dotenv");
const helmet = require("helmet");
const morgan = require("morgan");

const authRoutes = require("./routes/authRoutes");
const taskRoutes = require("./routes/taskRoutes");
const { errorHandler } = require("./middleware/errorMiddleware");

dotenv.config();
const app = express();

app.use(express.json());
app.use(helmet());
app.use(morgan("dev"));

app.use("/api/auth", authRoutes);
app.use("/api/tasks", taskRoutes);

app.use(errorHandler);

module.exports = app;

🖥️ src/server.js

const app = require("./app");
const sequelize = require("./config/db");
const User = require("./models/User");
const Task = require("./models/Task");

const PORT = process.env.PORT || 5000;

sequelize.sync({ alter: true }).then(() => {
  console.log("Database synced");
  app.listen(PORT, () => console.log(`Server running on port ${PORT}`));
});

🔑 .env

PORT=5000
DB_NAME=yourdbname
DB_USER=yourdbuser
DB_PASS=yourdbpass
DB_HOST=localhost
JWT_SECRET=supersecretkey

✅ Now you have a ready-to-practice boilerplate.
In a real exam, this lets you focus on logic, authentication, task workflows, and role-based access instead of wasting time on setup.


Do you also want me to create a step-by-step practice exam flow (like a 3-hour roadmap: “first do DB, then JWT, then tasks”) so you can time yourself and simulate the real exam?

Previous Post Next Post