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?
Tags
Node js