Project Introduction
The Employee Management System is a comprehensive web application designed to streamline the management of employee information, attendance, payroll, and performance reviews. Built using Node.js, this platform allows HR personnel and administrators to manage employee records efficiently. The system supports multiple user roles, including admin, HR, and employee, ensuring a tailored experience for each user type. The underlying MySQL database schema is structured to manage users, employees, attendance, payroll, performance reviews, recruitment, training programs, leave requests, and notifications, providing a robust foundation for effective employee management.
Project Objectives
- To develop a user-friendly interface for HR personnel to manage employee records and information.
- To implement a secure user authentication system with role-based access control.
- To facilitate the management of employee attendance, including clock-in and clock-out times.
- To manage payroll processing, including salary calculations, bonuses, and deductions.
- To provide a system for conducting performance reviews and tracking employee progress.
- To enable recruitment management, including job postings and applicant tracking.
- To implement training program management for employee skill development.
- To handle leave requests and approvals efficiently.
- To ensure the application is scalable and maintainable for future enhancements.
Project Modules
- User Management Module:
This module handles user registration, authentication, and role management, allowing users to manage their accounts based on their designated roles.
- Employee Management Module:
This module allows HR personnel to add, update, and manage employee records, including personal details, job titles, and departments.
- Attendance Management Module:
This module tracks employee attendance, including clock-in and clock-out times, and manages leave types.
- Payroll Management Module:
This module processes payroll for employees, including calculations for basic salary, bonuses, deductions, and net salary.
- Performance Review Module:
This module manages performance reviews for employees, allowing for scoring and comments on employee performance.
- Recruitment Management Module:
This module allows HR to create and manage job postings, including job titles and descriptions.
- Training Management Module:
This module tracks training programs for employees, including training titles and completion dates.
- Leave Request Management Module:
This module handles employee leave requests, including types of leave, start and end dates, and approval statuses.
- Notification Module:
This module sends notifications to users regarding important updates, approvals, and reminders.
Steps Overview
Set Up the Project: Initialize a new Node.js project and install the required packages.
Configure Sequelize: Set up Sequelize to connect to your database and define models based on the provided schema.
Create Repositories: Implement repository patterns for data access.
Create Controllers: Implement controllers to handle business logic.
Set Up Routes: Define routes for the application.
Create Views: Use EJS to create views for the application with Bootstrap 5 for styling.
Implement CRUD Operations: Implement the CRUD operations for the Users, Roles, Employees, Attendance, Payroll, Performance, JobPostings, TrainingPrograms, LeaveRequests, Documents, Policies, and Announcements tables.
Step 1: Set Up the Project
mkdir hr-management-app
cd hr-management-app
npm init -y
npm install express sequelize mysql2 ejs body-parser
Step 2: Configure Sequelize
Create a config folder and a database.js file to configure Sequelize.
// config/database.js
const { Sequelize } = require('sequelize');
const sequelize = new Sequelize('database_name', 'username', 'password', {
host: 'localhost',
dialect: 'mysql',
});
module.exports = sequelize;
Step 3: Define Models
Create a models folder and define the models based on the provided schema.
1. User Model: models/User.js
const { DataTypes } = require('sequelize');
const sequelize = require('../config/database');
const User = sequelize.define('User ', {
UserId: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
Username: {
type: DataTypes.STRING(50),
allowNull: false,
unique: true,
},
PasswordHash: {
type: DataTypes.STRING(256),
allowNull: false,
},
Email: {
type: DataTypes.STRING(100),
allowNull: false,
unique: true,
},
RoleId: {
type: DataTypes.INTEGER,
},
}, {
timestamps: true,
createdAt: 'CreatedAt',
});
module.exports = User;
2. Role Model: models/Role.js
const { DataTypes } = require('sequelize');
const sequelize = require('../config/database');
const Role = sequelize.define('Role', {
RoleId: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
RoleName: {
type: DataTypes.STRING(50),
allowNull: false,
unique: true,
},
}, {
timestamps: false,
});
module.exports = Role;
3. Employee Model: models/Employee.js
const { DataTypes } = require('sequelize');
const sequelize = require('../config/database');
const Employee = sequelize.define('Employee', {
EmployeeId: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
FirstName: {
type: DataTypes.STRING(50),
allowNull: false,
},
LastName: {
type: DataTypes.STRING(50),
allowNull: false,
},
Email: {
type: DataTypes.STRING(100),
allowNull: false,
unique: true,
},
Phone: {
type: DataTypes.STRING(15),
},
HireDate: {
type: DataTypes.DATE,
allowNull: false,
},
JobTitle: {
type: DataTypes.STRING(100),
},
Department: {
type: DataTypes.STRING(100),
},
Salary: {
type: DataTypes.DECIMAL(18, 2),
},
CreatedAt: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW,
},
UserId: {
type: DataTypes.INTEGER,
},
}, {
timestamps: true,
});
module.exports = Employee;
4. Attendance Model: models/Attendance.js
const { DataTypes } = require('sequelize');
const sequelize = require('../config/database');
const Attendance = sequelize.define('Attendance', {
AttendanceId: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
EmployeeId: {
type: DataTypes.INTEGER,
},
Date: {
type: DataTypes.DATE,
allowNull: false,
},
Status: {
type: DataTypes.STRING(20),
allowNull: false,
},
}, {
timestamps: true,
createdAt: 'CreatedAt',
});
module.exports = Attendance;
5. Payroll Model: models/Payroll.js
const { DataTypes } = require('sequelize');
const sequelize = require('../config/database');
const Payroll = sequelize.define('Payroll', {
PayrollId: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
EmployeeId: {
type: DataTypes.INTEGER,
},
PayPeriodStart: {
type: DataTypes.DATE,
allowNull: false,
},
PayPeriodEnd: {
type: DataTypes.DATE,
allowNull: false,
},
GrossSalary: {
type: DataTypes.DECIMAL(18, 2),
allowNull: false,
},
Deductions: {
type: DataTypes.DECIMAL(18, 2),
allowNull: false,
},
NetSalary: {
type: DataTypes.DECIMAL(18, 2),
allowNull: false,
},
}, {
timestamps: true,
createdAt: 'CreatedAt',
});
module.exports = Payroll;
6. Performance Model: models/Performance.js
const { DataTypes } = require('sequelize');
const sequelize = require('../config/database');
const Performance = sequelize.define('Performance', {
PerformanceId: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
EmployeeId: {
type: DataTypes.INTEGER,
},
ReviewDate: {
type: DataTypes.DATE,
allowNull: false,
},
Rating: {
type: DataTypes.INTEGER,
validate: {
min: 1,
max: 5,
},
},
Comments: {
type: DataTypes.TEXT,
},
}, {
timestamps: true,
createdAt: 'CreatedAt',
});
module.exports = Performance;
7. JobPosting Model: models/JobPosting.js
const { DataTypes } = require('sequelize');
const sequelize = require('../config/database');
const JobPosting = sequelize.define('JobPosting', {
JobPostingId: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
JobTitle: {
type: DataTypes.STRING(100),
allowNull: false,
},
Description: {
type: DataTypes.TEXT,
allowNull: false,
},
Requirements: {
type: DataTypes.TEXT,
},
CreatedAt: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW,
},
IsActive: {
type: DataTypes.BOOLEAN,
defaultValue: true,
},
}, {
timestamps: false,
});
module.exports = JobPosting;
8. TrainingProgram Model: models/TrainingProgram.js
const { DataTypes } = require('sequelize');
const sequelize = require('../config/database');
const TrainingProgram = sequelize.define('TrainingProgram', {
TrainingProgramId: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
Title: {
type: DataTypes.STRING(100),
allowNull: false,
},
Description: {
type: DataTypes.TEXT,
},
StartDate: {
type: DataTypes.DATE,
allowNull: false,
},
EndDate: {
type: DataTypes.DATE,
allowNull: false,
},
CreatedAt: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW,
},
}, {
timestamps: false,
});
module.exports = TrainingProgram;
9. LeaveRequest Model: models/LeaveRequest.js
const { DataTypes } = require('sequelize');
const sequelize = require('../config/database');
const LeaveRequest = sequelize.define('LeaveRequest', {
LeaveRequestId: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
EmployeeId: {
type: DataTypes.INTEGER,
},
StartDate: {
type: DataTypes.DATE,
allowNull: false,
},
EndDate: {
type: DataTypes.DATE,
allowNull: false,
},
Reason: {
type: DataTypes.TEXT,
allowNull: false,
},
Status: {
type: DataTypes.STRING(20),
allowNull: false,
},
}, {
timestamps: true,
createdAt: 'CreatedAt',
});
module.exports = LeaveRequest;
10. Document Model: models/Document.js
const { DataTypes } = require('sequelize');
const sequelize = require('../config/database');
const Document = sequelize.define('Document', {
DocumentId: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
EmployeeId: {
type: DataTypes.INTEGER,
},
DocumentType: {
type: DataTypes.STRING(100),
allowNull: false,
},
FilePath: {
type: DataTypes.STRING(256),
allowNull: false,
},
CreatedAt: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW,
},
}, {
timestamps: false,
});
module.exports = Document;
11. Policy Model: models/Policy.js
const { DataTypes } = require('sequelize');
const sequelize = require('../config/database');
const Policy = sequelize.define('Policy', {
PolicyId: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
Title: {
type: DataTypes.STRING(100),
allowNull: false,
},
Description: {
type: DataTypes.TEXT,
},
CreatedAt: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW,
},
}, {
timestamps: false,
});
module.exports = Policy;
12. Announcement Model: models/Announcement.js
const { DataTypes } = require('sequelize');
const sequelize = require('../config/database');
const Announcement = sequelize.define('Announcement', {
AnnouncementId: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
Title: {
type: DataTypes.STRING(100),
allowNull: false,
},
Message: {
type: DataTypes.TEXT,
allowNull: false,
},
CreatedAt: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW,
},
}, {
timestamps: false,
});
module.exports = Announcement;
Step 4: Create Repositories
Create a repositories folder and implement the repository pattern for data access. Each repository will handle the CRUD operations for its respective model.
1. User Repository: repositories/UserRepository.js
const User = require('../models/User');
class UserRepository {
async createUser (data) {
return await User.create(data);
}
async getAllUsers() {
return await User.findAll();
}
async getUser ById(id) {
return await User.findByPk(id);
}
async updateUser (id, data) {
const user = await this.getUser ById(id);
if (user) {
return await user.update(data);
}
return null;
}
async deleteUser (id) {
const user = await this.getUser ById(id);
if (user) {
await user.destroy();
return true;
}
return false;
}
}
module.exports = new UserRepository();
2. Role Repository: repositories/RoleRepository.js
const Role = require('../models/Role');
class RoleRepository {
async createRole(data) {
return await Role.create(data);
}
async getAllRoles() {
return await Role.findAll();
}
async getRoleById(id) {
return await Role.findByPk(id);
}
async updateRole(id, data) {
const role = await this.getRoleById(id);
if (role) {
return await role.update(data);
}
return null;
}
async deleteRole(id) {
const role = await this.getRoleById(id);
if (role) {
await role.destroy();
return true;
}
return false;
}
}
module.exports = new RoleRepository();
3. Employee Repository: repositories/EmployeeRepository.js
const Employee = require('../models/Employee');
class EmployeeRepository {
async createEmployee(data) {
return await Employee.create(data);
}
async getAllEmployees() {
return await Employee.findAll();
}
async getEmployeeById(id) {
return await Employee.findByPk(id);
}
async updateEmployee(id, data) {
const employee = await this.getEmployeeById(id);
if (employee) {
return await employee.update(data);
}
return null;
}
async deleteEmployee(id) {
const employee = await this.getEmployeeById(id);
if (employee) {
await employee.destroy();
return true;
}
return false;
}
}
module.exports = new EmployeeRepository();
4. Attendance Repository: repositories/AttendanceRepository.js
const Attendance = require('../models/Attendance');
class AttendanceRepository {
async createAttendance(data) {
return await Attendance.create(data);
}
async getAllAttendanceRecords() {
return await Attendance.findAll();
}
async getAttendanceById(id) {
return await Attendance.findByPk(id);
}
async updateAttendance(id, data) {
const attendance = await this.getAttendanceById(id);
if (attendance) {
return await attendance.update(data);
}
return null;
}
async deleteAttendance(id) {
const attendance = await this.getAttendanceById(id);
if (attendance) {
await attendance.destroy();
return true;
}
return false;
}
}
module.exports = new AttendanceRepository();
5. Payroll Repository: repositories/PayrollRepository.js
const Payroll = require('../models/Payroll');
class PayrollRepository {
async createPayroll(data) {
return await Payroll.create(data);
}
async getAllPayrolls() {
return await Payroll.findAll();
}
async getPayrollById(id) {
return await Payroll.findByPk(id);
}
async updatePayroll(id, data) {
const payroll = await this.getPayrollById(id);
if (payroll) {
return await payroll.update(data);
}
return null;
}
async deletePayroll(id) {
const payroll = await this.getPayrollById(id);
if (payroll) {
await payroll.destroy();
return true;
}
return false;
}
}
module.exports = new PayrollRepository();
6. Performance Repository: repositories/PerformanceRepository.js
const Performance = require('../models/Performance');
class PerformanceRepository {
async createPerformance(data) {
return await Performance.create(data);
}
async getAllPerformances() {
return await Performance.findAll();
}
async getPerformanceById(id) {
return await Performance.findByPk(id);
}
async updatePerformance(id, data) {
const performance = await this.getPerformanceById(id);
if (performance) {
return await performance.update(data);
}
return null;
}
async deletePerformance(id) {
const performance = await this.getPerformanceById(id);
if (performance) {
await performance.destroy();
return true;
}
return false;
}
}
module.exports = new PerformanceRepository();
7. JobPosting Repository: repositories/JobPostingRepository.js
const JobPosting = require('../models/JobPosting');
class JobPostingRepository {
async createJobPosting(data) {
return await JobPosting.create(data);
}
async getAllJobPostings() {
return await JobPosting.findAll();
}
async getJobPostingById(id) {
return await JobPosting.findByPk(id);
}
async updateJobPosting(id, data) {
const jobPosting = await this.getJobPostingById(id);
if (jobPosting) {
return await jobPosting.update(data);
}
return null;
}
async deleteJobPosting(id) {
const jobPosting = await this.getJobPostingById(id);
if (jobPosting) {
await jobPosting.destroy();
return true;
}
return false;
}
}
module.exports = new JobPostingRepository();
8. TrainingProgram Repository: repositories/TrainingProgramRepository.js
const TrainingProgram = require('../models/TrainingProgram');
class TrainingProgramRepository {
async createTrainingProgram(data) {
return await TrainingProgram.create(data);
}
async getAllTrainingPrograms() {
return await TrainingProgram.findAll();
}
async getTrainingProgramById(id) {
return await TrainingProgram.findByPk(id);
}
async updateTrainingProgram(id, data) {
const trainingProgram = await this.getTrainingProgramById(id);
if (trainingProgram) {
return await trainingProgram.update(data);
}
return null;
}
async deleteTrainingProgram(id) {
const trainingProgram = await this.getTrainingProgramById(id);
if (trainingProgram) {
await trainingProgram.destroy();
return true;
}
return false;
}
}
module.exports = new TrainingProgramRepository();
9. LeaveRequest Repository: repositories/LeaveRequestRepository.js
const LeaveRequest = require('../models/LeaveRequest');
class LeaveRequestRepository {
async createLeaveRequest(data) {
return await LeaveRequest.create(data);
}
async getAllLeaveRequests() {
return await LeaveRequest.findAll();
}
async getLeaveRequestById(id) {
return await LeaveRequest.findByPk(id);
}
async updateLeaveRequest(id, data) {
const leaveRequest = await this.getLeaveRequestById(id);
if (leaveRequest) {
return await leaveRequest.update(data);
}
return null;
}
async deleteLeaveRequest(id) {
const leaveRequest = await this.getLeaveRequestById(id);
if (leaveRequest) {
await leaveRequest.destroy();
return true;
}
return false;
}
}
module.exports = new LeaveRequestRepository();
10. Document Repository: repositories/DocumentRepository.js
const Document = require('../models/Document');
class DocumentRepository {
async createDocument(data) {
return await Document.create(data);
}
async getAllDocuments() {
return await Document.findAll();
}
async getDocumentById(id) {
return await Document.findByPk(id);
}
async updateDocument(id, data) {
const document = await this.getDocumentById(id);
if (document) {
return await document.update(data);
}
return null;
}
async deleteDocument(id) {
const document = await this.getDocumentById(id);
if (document) {
await document.destroy();
return true;
}
return false;
}
}
module.exports = new DocumentRepository();
11. Policy Repository: repositories/PolicyRepository.js
const Policy = require('../models/Policy');
class PolicyRepository {
async createPolicy(data) {
return await Policy.create(data);
}
async getAllPolicies() {
return await Policy.findAll();
}
async getPolicyById(id) {
return await Policy.findByPk(id);
}
async updatePolicy(id, data) {
const policy = await this.getPolicyById(id);
if (policy) {
return await policy.update(data);
}
return null;
}
async deletePolicy(id) {
const policy = await this.getPolicyById(id);
if (policy) {
await policy.destroy();
return true;
}
return false;
}
}
module.exports = new PolicyRepository();
12. Announcement Repository: repositories/AnnouncementRepository.js
const Announcement = require ('../models/Announcement');
class AnnouncementRepository {
async createAnnouncement(data) {
return await Announcement.create(data);
}
async getAllAnnouncements() {
return await Announcement.findAll();
}
async getAnnouncementById(id) {
return await Announcement.findByPk(id);
}
async updateAnnouncement(id, data) {
const announcement = await this.getAnnouncementById(id);
if (announcement) {
return await announcement.update(data);
}
return null;
}
async deleteAnnouncement(id) {
const announcement = await this.getAnnouncementById(id);
if (announcement) {
await announcement.destroy();
return true;
}
return false;
}
}
module.exports = new AnnouncementRepository();
Step 5: Create Controllers
Create a controllers folder and implement controllers for each model to handle the business logic.
1. User Controller: controllers/UserController.js
const UserRepository = require('../repositories/UserRepository');
class UserController {
async createUser (req, res) {
try {
const user = await UserRepository.createUser (req.body);
res.redirect('/users');
} catch (error) {
console.error(error);
res.status(500).send("Internal Server Error");
}
}
async getAllUsers(req, res) {
const users = await UserRepository.getAllUsers();
res.render('users/index', { users });
}
async getUser ById(req, res) {
const user = await UserRepository.getUser ById(req.params.id);
res.render('users/edit', { user });
}
async updateUser (req, res) {
await UserRepository.updateUser (req.params.id, req.body);
res.redirect('/users');
}
async deleteUser (req, res) {
await UserRepository.deleteUser (req.params.id);
res.redirect('/users');
}
}
module.exports = new UserController();
2. Role Controller: controllers/RoleController.js
const RoleRepository = require('../repositories/RoleRepository');
class RoleController {
async createRole(req, res) {
try {
await RoleRepository.createRole(req.body);
res.redirect('/roles');
} catch (error) {
console.error(error);
res.status(500).send("Internal Server Error");
}
}
async getAllRoles(req, res) {
const roles = await RoleRepository.getAllRoles();
res.render('roles/index', { roles });
}
async getRoleById(req, res) {
const role = await RoleRepository.getRoleById(req.params.id);
res.render('roles/edit', { role });
}
async updateRole(req, res) {
await RoleRepository.updateRole(req.params.id, req.body);
res.redirect('/roles');
}
async deleteRole(req, res) {
await RoleRepository.deleteRole(req.params.id);
res.redirect('/roles');
}
}
module.exports = new RoleController();
3. Employee Controller: controllers/EmployeeController.js
const EmployeeRepository = require('../repositories/EmployeeRepository');
class EmployeeController {
async createEmployee(req, res) {
try {
await EmployeeRepository.createEmployee(req.body);
res.redirect('/employees');
} catch (error) {
console.error(error);
res.status(500).send("Internal Server Error");
}
}
async getAllEmployees(req, res) {
const employees = await EmployeeRepository.getAllEmployees();
res.render('employees/index', { employees });
}
async getEmployeeById(req, res) {
const employee = await EmployeeRepository.getEmployeeById(req.params.id);
res.render('employees/edit', { employee });
}
async updateEmployee(req, res) {
await EmployeeRepository.updateEmployee(req.params.id, req.body);
res.redirect('/employees');
}
async deleteEmployee(req, res) {
await EmployeeRepository.deleteEmployee(req.params.id);
res.redirect('/employees');
}
}
module.exports = new EmployeeController();
4. Attendance Controller: controllers/AttendanceController.js
const AttendanceRepository = require('../repositories/AttendanceRepository');
class AttendanceController {
async createAttendance(req, res) {
try {
await AttendanceRepository.createAttendance(req.body);
res.redirect('/attendance');
} catch (error) {
console.error(error);
res.status(500).send("Internal Server Error");
}
}
async getAllAttendance(req, res) {
const attendanceRecords = await AttendanceRepository.getAllAttendanceRecords();
res.render('attendance/index', { attendanceRecords });
}
async getAttendanceById(req, res) {
const attendance = await AttendanceRepository.getAttendanceById(req.params.id);
res.render('attendance/edit', { attendance });
}
async updateAttendance(req, res) {
await AttendanceRepository.updateAttendance(req.params.id, req.body);
res.redirect('/attendance');
}
async deleteAttendance(req, res) {
await AttendanceRepository.deleteAttendance(req.params.id);
res.redirect('/attendance');
}
}
module.exports = new AttendanceController();
5. Payroll Controller: controllers/PayrollController.js
const PayrollRepository = require('../repositories/PayrollRepository');
class PayrollController {
async createPayroll(req, res) {
try {
await PayrollRepository.createPayroll(req.body);
res.redirect('/payroll');
} catch (error) {
console.error(error);
res.status(500).send("Internal Server Error");
}
}
async getAllPayrolls(req, res) {
const payrolls = await PayrollRepository.getAllPayrolls();
res.render('payroll/index', { payrolls });
}
async getPayrollById(req, res) {
const payroll = await PayrollRepository.getPayrollById(req.params.id);
res.render('payroll/edit', { payroll });
}
async updatePayroll(req, res) {
await PayrollRepository.updatePayroll(req.params.id, req.body);
res.redirect('/payroll');
}
async deletePayroll(req, res) {
await PayrollRepository.deletePayroll(req.params.id);
res.redirect('/payroll');
}
}
module.exports = new PayrollController();
6. Performance Controller: controllers/PerformanceController.js
const PerformanceRepository = require('../repositories/PerformanceRepository');
class PerformanceController {
async createPerformance(req, res) {
try {
await PerformanceRepository.createPerformance(req.body);
res.redirect('/performance');
} catch (error) {
console.error(error);
res.status(500).send("Internal Server Error");
}
}
async getAllPerformances(req, res) {
const performances = await PerformanceRepository.getAllPerformances();
res.render('performance/index', { performances });
}
async getPerformanceById(req, res) {
const performance = await PerformanceRepository.getPerformanceById(req.params.id);
res.render('performance/edit', { performance });
}
async updatePerformance(req, res) {
await PerformanceRepository.updatePerformance(req.params.id, req.body);
res.redirect('/performance');
}
async deletePerformance(req, res) {
await PerformanceRepository.deletePerformance(req.params.id);
res.redirect('/performance');
}
}
module.exports = new PerformanceController();
7. JobPosting Controller: controllers/JobPostingController.js
const JobPostingRepository = require('../repositories/JobPostingRepository');
class JobPostingController {
async createJobPosting(req, res) {
try {
await JobPostingRepository.createJobPosting(req.body);
res.redirect('/job-postings');
} catch (error) {
console.error(error);
res.status(500).send("Internal Server Error");
}
}
async getAllJobPostings(req, res) {
const jobPostings = await JobPostingRepository.getAllJobPostings();
res.render('job-postings/index', { jobPostings });
}
async getJobPostingById(req, res) {
const jobPosting = await JobPostingRepository.getJobPostingById(req.params.id);
res.render('job-postings/edit', { jobPosting });
}
async updateJobPosting(req, res) {
await JobPostingRepository.updateJobPosting(req.params.id, req.body);
res.redirect('/job-postings');
}
async deleteJobPosting(req, res) {
await JobPostingRepository.deleteJobPosting(req.params.id);
res.redirect('/job-postings');
}
}
module.exports = new JobPostingController();
8. TrainingProgram Controller: controllers/TrainingProgramController.js
const TrainingProgramRepository = require('../repositories/TrainingProgramRepository');
class TrainingProgramController {
async createTrainingProgram(req, res) {
try {
await TrainingProgramRepository.createTrainingProgram(req.body);
res.redirect('/training-programs');
} catch (error) {
console.error(error);
res.status(500).send("Internal Server Error");
}
}
async getAllTrainingPrograms(req, res) {
const trainingPrograms = await TrainingProgramRepository.getAllTrainingPrograms();
res.render('training-programs/index', { trainingPrograms });
}
async getTrainingProgramById(req, res) {
const trainingProgram = await TrainingProgramRepository.getTrainingProgramById(req.params.id);
res.render('training-programs/edit', { trainingProgram });
}
async updateTrainingProgram(req, res) {
await TrainingProgramRepository.updateTrainingProgram(req.params.id, req.body);
res.redirect('/training-programs');
}
async deleteTrainingProgram(req, res) {
await TrainingProgramRepository.deleteTrainingProgram(req.params.id );
res.redirect('/training-programs');
}
}
module.exports = new TrainingProgramController();
9. LeaveRequest Controller: controllers/LeaveRequestController.js
const LeaveRequestRepository = require('../repositories/LeaveRequestRepository');
class LeaveRequestController {
async createLeaveRequest(req, res) {
try {
await LeaveRequestRepository.createLeaveRequest(req.body);
res.redirect('/leave-requests');
} catch (error) {
console.error(error);
res.status(500).send("Internal Server Error");
}
}
async getAllLeaveRequests(req, res) {
const leaveRequests = await LeaveRequestRepository.getAllLeaveRequests();
res.render('leave-requests/index', { leaveRequests });
}
async getLeaveRequestById(req, res) {
const leaveRequest = await LeaveRequestRepository.getLeaveRequestById(req.params.id);
res.render('leave-requests/edit', { leaveRequest });
}
async updateLeaveRequest(req, res) {
await LeaveRequestRepository.updateLeaveRequest(req.params.id, req.body);
res.redirect('/leave-requests');
}
async deleteLeaveRequest(req, res) {
await LeaveRequestRepository.deleteLeaveRequest(req.params.id);
res.redirect('/leave-requests');
}
}
module.exports = new LeaveRequestController();
10. Document Controller: controllers/DocumentController.js
const DocumentRepository = require('../repositories/DocumentRepository');
class DocumentController {
async createDocument(req, res) {
try {
await DocumentRepository.createDocument(req.body);
res.redirect('/documents');
} catch (error) {
console.error(error);
res.status(500).send("Internal Server Error");
}
}
async getAllDocuments(req, res) {
const documents = await DocumentRepository.getAllDocuments();
res.render('documents/index', { documents });
}
async getDocumentById(req, res) {
const document = await DocumentRepository.getDocumentById(req.params.id);
res.render('documents/edit', { document });
}
async updateDocument(req, res) {
await DocumentRepository.updateDocument(req.params.id, req.body);
res.redirect('/documents');
}
async deleteDocument(req, res) {
await DocumentRepository.deleteDocument(req.params.id);
res.redirect('/documents');
}
}
module.exports = new DocumentController();
11. Policy Controller: controllers/PolicyController.js
const PolicyRepository = require('../repositories/PolicyRepository');
class PolicyController {
async createPolicy(req, res) {
try {
await PolicyRepository.createPolicy(req.body);
res.redirect('/policies');
} catch (error) {
console.error(error);
res.status(500).send("Internal Server Error");
}
}
async getAllPolicies(req, res) {
const policies = await PolicyRepository.getAllPolicies();
res.render('policies/index', { policies });
}
async getPolicyById(req, res) {
const policy = await PolicyRepository.getPolicyById(req.params.id);
res.render('policies/edit', { policy });
}
async updatePolicy(req, res) {
await PolicyRepository.updatePolicy(req.params.id, req.body);
res.redirect('/policies');
}
async deletePolicy(req, res) {
await PolicyRepository.deletePolicy(req.params.id);
res.redirect('/policies');
}
}
module.exports = new PolicyController();
12. Announcement Controller: controllers/AnnouncementController.js
const AnnouncementRepository = require('../repositories/AnnouncementRepository');
class AnnouncementController {
async createAnnouncement(req, res) {
try {
await AnnouncementRepository.createAnnouncement(req.body);
res.redirect('/announcements');
} catch (error) {
console.error(error);
res.status(500).send("Internal Server Error");
}
}
async getAllAnnouncements(req, res) {
const announcements = await AnnouncementRepository.getAllAnnouncements();
res.render('announcements/index', { announcements });
}
async getAnnouncementById(req, res) {
const announcement = await AnnouncementRepository.getAnnouncementById(req.params.id);
res.render('announcements/edit', { announcement });
}
async updateAnnouncement(req, res) {
await AnnouncementRepository.updateAnnouncement(req.params.id, req.body);
res.redirect('/announcements');
}
async deleteAnnouncement(req, res) {
await AnnouncementRepository.deleteAnnouncement(req.params.id);
res.redirect('/announcements');
}
}
module.exports = new AnnouncementController();
Step 6: Set Up Routes
Create a routes folder and define routes for each model.
1. User Routes: routes/userRoutes.js
const express = require('express');
const router = express.Router();
const UserController = require ('../controllers/UserController');
router.get('/', UserController.getAllUsers);
router.get('/create', (req, res) => res.render('users/create'));
router.post('/', UserController.createUser );
router.get('/:id/edit', UserController.getUser ById);
router.post('/:id', UserController.updateUser );
router.post('/:id/delete', UserController.deleteUser );
module.exports = router;
2. Role Routes: routes/roleRoutes.js
const express = require('express');
const router = express.Router();
const RoleController = require('../controllers/RoleController');
router.get('/', RoleController.getAllRoles);
router.get('/create', (req, res) => res.render('roles/create'));
router.post('/', RoleController.createRole);
router.get('/:id/edit', RoleController.getRoleById);
router.post('/:id', RoleController.updateRole);
router.post('/:id/delete', RoleController.deleteRole);
module.exports = router;
3. Employee Routes: routes/employeeRoutes.js
const express = require('express');
const router = express.Router();
const EmployeeController = require('../controllers/EmployeeController');
router.get('/', EmployeeController.getAllEmployees);
router.get('/create', (req, res) => res.render('employees/create'));
router.post('/', EmployeeController.createEmployee);
router.get('/:id/edit', EmployeeController.getEmployeeById);
router.post('/:id', EmployeeController.updateEmployee);
router.post('/:id/delete', EmployeeController.deleteEmployee);
module.exports = router;
4. Attendance Routes: routes/attendanceRoutes.js
const express = require('express');
const router = express.Router();
const AttendanceController = require('../controllers/AttendanceController');
router.get('/', AttendanceController.getAllAttendance);
router.get('/create', (req, res) => res.render('attendance/create'));
router.post('/', AttendanceController.createAttendance);
router.get('/:id/edit', AttendanceController.getAttendanceById);
router.post('/:id', AttendanceController.updateAttendance);
router.post('/:id/delete', AttendanceController.deleteAttendance);
module.exports = router;
5. Payroll Routes: routes/payrollRoutes.js
const express = require('express');
const router = express.Router();
const PayrollController = require('../controllers/PayrollController');
router.get('/', PayrollController.getAllPayrolls);
router.get('/create', (req, res) => res.render('payroll/create'));
router.post('/', PayrollController.createPayroll);
router.get('/:id/edit', PayrollController.getPayrollById);
router.post('/:id', PayrollController.updatePayroll);
router.post('/:id/delete', PayrollController.deletePayroll);
module.exports = router;
6. Performance Routes: routes/performanceRoutes.js
const express = require('express');
const router = express.Router();
const PerformanceController = require('../controllers/PerformanceController');
router.get('/', PerformanceController.getAllPerformances);
router.get('/create', (req, res) => res.render('performance/create'));
router.post('/', PerformanceController.createPerformance);
router.get('/:id/edit', PerformanceController.getPerformanceById);
router.post('/:id', PerformanceController.updatePerformance);
router.post('/:id/delete', PerformanceController.deletePerformance);
module.exports = router;
7. JobPosting Routes: routes/jobPostingRoutes.js
const express = require('express');
const router = express.Router();
const JobPostingController = require('../controllers/JobPostingController');
router.get('/', JobPostingController.getAllJobPostings);
router.get('/create', (req, res) => res.render('job-postings/create'));
router.post('/', JobPostingController.createJobPosting);
router.get('/:id/edit', JobPostingController.getJobPostingById);
router.post('/:id', JobPostingController.updateJobPosting);
router.post('/:id/delete', JobPostingController.deleteJobPosting);
module.exports = router;
8. TrainingProgram Routes: routes/trainingProgramRoutes.js
const express = require('express');
const router = express.Router();
const TrainingProgramController = require('../controllers/TrainingProgramController');
router.get('/', TrainingProgramController.getAllTrainingPrograms);
router.get('/create', (req, res) => res.render('training-programs/create'));
router.post('/', TrainingProgramController.createTrainingProgram);
router.get('/:id/edit', TrainingProgramController.getTrainingProgramById);
router.post('/:id', TrainingProgramController.updateTrainingProgram);
router.post('/:id/delete', TrainingProgramController.deleteTrainingProgram);
module.exports = router;
9. LeaveRequest Routes: routes/leaveRequestRoutes.js
const express = require('express');
const router = express.Router();
const LeaveRequestController = require('../controllers/LeaveRequestController');
router.get('/', LeaveRequestController.getAllLeaveRequests);
router.get('/create', (req, res) => res.render('leave-requests/create'));
router.post('/', LeaveRequestController.createLeaveRequest);
router.get('/:id/edit', LeaveRequestController.getLeaveRequest ById);
router.post('/:id', LeaveRequestController.updateLeaveRequest);
router.post('/:id/delete', LeaveRequestController.deleteLeaveRequest);
module.exports = router;
10. Document Routes: routes/documentRoutes.js
const express = require('express');
const router = express.Router();
const DocumentController = require('../controllers/DocumentController');
router.get('/', DocumentController.getAllDocuments);
router.get('/create', (req, res) => res.render('documents/create'));
router.post('/', DocumentController.createDocument);
router.get('/:id/edit', DocumentController.getDocumentById);
router.post('/:id', DocumentController.updateDocument);
router.post('/:id/delete', DocumentController.deleteDocument);
module.exports = router;
11. Policy Routes: routes/policyRoutes.js
const express = require('express');
const router = express.Router();
const PolicyController = require('../controllers/PolicyController');
router.get('/', PolicyController.getAllPolicies);
router.get('/create', (req, res) => res.render('policies/create'));
router.post('/', PolicyController.createPolicy);
router.get('/:id/edit', PolicyController.getPolicyById);
router.post('/:id', PolicyController.updatePolicy);
router.post('/:id/delete', PolicyController.deletePolicy);
module.exports = router;
12. Announcement Routes: routes/announcementRoutes.js
const express = require('express');
const router = express.Router();
const AnnouncementController = require('../controllers/AnnouncementController');
router.get('/', AnnouncementController.getAllAnnouncements);
router.get('/create', (req, res) => res.render('announcements/create'));
router.post('/', AnnouncementController.createAnnouncement);
router.get('/:id/edit', AnnouncementController.getAnnouncementById);
router.post('/:id', AnnouncementController.updateAnnouncement);
router.post('/:id/delete', AnnouncementController.deleteAnnouncement);
module.exports = router;
Step 7: Create Views
Create a views folder and set up EJS templates for each model using Bootstrap 5 for styling.
1. User Views: views/users/index.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
<title>Users</title>
</head>
<body>
<div class="container">
<h1>Users</h1>
<a href="/users/create" class="btn btn-primary">Create User</a>
<table class="table">
<thead>
<tr>
<th>UserId</th>
<th>Username</th>
<th>Email</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<% users.forEach(user => { %>
<tr>
<td><%= user.UserId %></td>
<td><%= user.Username %></td>
<td><%= user.Email %></td>
<td>
<a href="/users/<%= user.UserId %>/edit" class="btn btn-warning">Edit</a>
<form action="/users/<%= user.UserId %>/delete" method="POST" style="display:inline;">
<button type="submit" class="btn btn-danger">Delete</button>
</form>
</td>
</tr>
<% }) %>
</tbody>
</table>
</div>
</body>
</html>
2. User Create View: views/users/create.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
<title>Create User</title>
</head>
<body>
<div class="container">
<h1>Create User</h1>
<form action="/users" method="POST">
<div class="mb-3">
<label for="Username" class="form-label">Username</label>
<input type="text" class="form-control" id="Username" name="Username" required>
</div>
<div class="mb-3">
<label for="Email" class="form-label">Email</label>
<input type="email" class="form-control" id="Email" name="Email" required>
</div>
<div class="mb-3">
<label for="PasswordHash" class="form-label">Password</label>
<input type="password" class ="form-control" id="PasswordHash" name="PasswordHash" required>
</div>
<button type="submit" class="btn btn-primary">Create User</button>
</form>
</div>
</body>
</html>
3. User Edit View: views/users/edit.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
<title>Edit User</title>
</head>
<body>
<div class="container">
<h1>Edit User</h1>
<form action="/users/<%= user.UserId %>" method="POST">
<div class="mb-3">
<label for="Username" class="form-label">Username</label>
<input type="text" class="form-control" id="Username" name="Username" value="<%= user.Username %>" required>
</div>
<div class="mb-3">
<label for="Email" class="form-label">Email</label>
<input type="email" class="form-control" id="Email" name="Email" value="<%= user.Email %>" required>
</div>
<button type="submit" class="btn btn-primary">Update User</button>
</form>
</div>
</body>
</html>
4. Role Views: views/roles/index.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
<title>Roles</title>
</head>
<body>
<div class="container">
<h1>Roles</h1>
<a href="/roles/create" class="btn btn-primary">Create Role</a>
<table class="table">
<thead>
<tr>
<th>RoleId</th>
<th>RoleName</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<% roles.forEach(role => { %>
<tr>
<td><%= role.RoleId %></td>
<td><%= role.RoleName %></td>
<td>
<a href="/roles/<%= role.RoleId %>/edit" class="btn btn-warning">Edit</a>
<form action="/roles/<%= role.RoleId %>/delete" method="POST" style="display:inline;">
<button type="submit" class="btn btn-danger">Delete</button>
</form>
</td>
</tr>
<% }) %>
</tbody>
</table>
</div>
</body>
</html>
5. Role Create View: views/roles/create.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
<title>Create Role</title>
</head>
<body>
<div class="container">
<h1>Create Role</h1>
<form action="/roles" method="POST">
<div class="mb-3">
<label for="RoleName" class="form-label">Role Name</label>
<input type="text" class="form-control" id="RoleName" name="RoleName" required>
</div>
<button type="submit" class="btn btn-primary">Create Role</button>
</form>
</div>
</body>
</html>
6. Role Edit View: views/roles/edit.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
<title>Edit Role</title>
</head>
<body>
<div class="container">
<h1>Edit Role</h1>
<form action="/roles/<%= role.RoleId %>" method="POST ">
<div class="mb-3">
<label for="RoleName" class="form-label">Role Name</label>
<input type="text" class="form-control" id="RoleName" name="RoleName" value="<%= role.RoleName %>" required>
</div>
<button type="submit" class="btn btn-primary">Update Role</button>
</form>
</div>
</body>
</html>
7. Employee Views: views/employees/index.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
<title>Employees</title>
</head>
<body>
<div class="container">
<h1>Employees</h1>
<a href="/employees/create" class="btn btn-primary">Create Employee</a>
<table class="table">
<thead>
<tr>
<th>EmployeeId</th>
<th>FirstName</th>
<th>LastName</th>
<th>Email</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<% employees.forEach(employee => { %>
<tr>
<td><%= employee.EmployeeId %></td>
<td><%= employee.FirstName %></td>
<td><%= employee.LastName %></td>
<td><%= employee.Email %></td>
<td>
<a href="/employees/<%= employee.EmployeeId %>/edit" class="btn btn-warning">Edit</a>
<form action="/employees/<%= employee.EmployeeId %>/delete" method="POST" style="display:inline;">
<button type="submit" class="btn btn-danger">Delete</button>
</form>
</td>
</tr>
<% }) %>
</tbody>
</table>
</div>
</body>
</html>
8. Employee Create View: views/employees/create.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
<title>Create Employee</title>
</head>
<body>
<div class="container">
<h1>Create Employee</h1>
<form action="/employees" method="POST">
<div class="mb-3">
<label for="FirstName" class="form-label">First Name</label>
<input type="text" class="form-control" id="FirstName" name="FirstName" required>
</div>
<div class="mb-3">
<label for="LastName" class="form-label">Last Name</label>
<input type="text" class="form-control" id="LastName" name="LastName" required>
</div>
<div class="mb-3">
<label for="Email" class="form-label">Email</label>
<input type="email" class="form-control" id="Email" name="Email" required>
</div>
<div class="mb-3">
<label for="Phone" class="form-label">Phone</label>
<input type="text" class="form-control" id="Phone" name="Phone">
</div>
<div class="mb-3">
<label for="HireDate" class="form-label">Hire Date</label>
<input type="date" class="form-control" id="HireDate" name="HireDate" required>
</div>
<div class="mb-3">
<label for="JobTitle" class="form-label">Job Title</label>
<input type="text" class="form-control" id="JobTitle" name="JobTitle">
</div>
<div class="mb-3">
<label for="Department" class="form-label">Department</label>
<input type="text" class="form-control" id="Department" name="Department">
</div>
<div class="mb-3">
<label for="Salary" class="form-label">Salary</label>
<input type="number" class="form-control" id="Salary" name="Salary" step="0.01">
</div>
<button type="submit" class="btn btn-primary">Create Employee</button>
</form>
</div>
</body>
</html>
9. Employee Edit View: views/employees/edit.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
<title>Edit Employee</title>
</head>
<body>
<div class="container">
<h1>Edit Employee</h1>
<form action="/employees/<%= employee.EmployeeId %>" method="POST">
<div class="mb-3">
<label for="FirstName" class="form-label">First Name</label>
<input type="text" class="form-control" id="FirstName" name="FirstName" value="<%= employee.FirstName %>" required>
</div>
<div class="mb-3">
<label for="LastName" class="form-label">Last Name</label>
<input type="text" class="form-control" id="LastName" name="LastName" value="<%= employee.LastName %>" required>
</div>
<div class="mb-3">
<label for="Email" class="form-label">Email</label>
<input type="email" class="form-control" id="Email" name="Email" value="<%= employee.Email %>" required>
</div>
<div class="mb-3">
<label for="Phone" class="form-label">Phone</label>
<input type="text" class="form-control" id="Phone" name="Phone" value="<%= employee.Phone %>">
</div>
<div class="mb-3">
<label for="HireDate" class="form-label">Hire Date</label>
<input type="date" class="form-control" id="HireDate" name="HireDate" value="<%= employee.HireDate.toISOString().split('T')[0] %>" required>
</div>
<div class="mb-3">
<label for="JobTitle" class="form-label">Job Title</label>
<input type="text" class="form-control" id="JobTitle" name="JobTitle" value="<%= employee.JobTitle %>">
</div>
<div class="mb-3">
<label for="Department" class="form-label">Department</label>
<input type="text" class="form-control" id="Department" name="Department" value="<%= employee.Department %>">
</div>
<div class="mb-3">
<label for="Salary" class="form-label">Salary</label>
<input type="number" class="form-control" id="Salary" name="Salary" value="<%= employee.Salary %>" step="0.01">
</div>
<button type="submit" class="btn btn-primary">Update Employee</button>
</form>
</div>
</body>
</html>
10. Attendance Views: views/attendance/index.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
<title>Attendance</title>
</head>
<body>
<div class="container">
<h1>Attendance Records</h1>
<a href="/attendance/create" class="btn btn-primary">Create Attendance Record</a>
<table class="table">
<thead>
<tr>
<th>AttendanceId</th>
<th>EmployeeId</th>
<th>Date</th>
<th>Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<% attendanceRecords.forEach(record => { %>
<tr>
<td><%= record.AttendanceId %></td>
<td><%= record.EmployeeId %></td>
<td><%= record.Date.toISOString().split('T')[0] %></td>
<td><%= record.Status %></td>
<td>
<a href="/attendance/<%= record.AttendanceId %>/edit" class="btn btn-warning">Edit</a>
<form action="/attendance/<%= record.AttendanceId %>/delete" method=" POST" style="display:inline;">
<button type="submit" class="btn btn-danger">Delete</button>
</form>
</td>
</tr>
<% }) %>
</tbody>
</table>
</div>
</body>
</html>
11. Attendance Create View: views/attendance/create.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
<title>Create Attendance Record</title>
</head>
<body>
<div class="container">
<h1>Create Attendance Record</h1>
<form action="/attendance" method="POST">
<div class="mb-3">
<label for="EmployeeId" class="form-label">Employee ID</label>
<input type="number" class="form-control" id="EmployeeId" name="EmployeeId" required>
</div>
<div class="mb-3">
<label for="Date" class="form-label">Date</label>
<input type="date" class="form-control" id="Date" name="Date" required>
</div>
<div class="mb-3">
<label for="Status" class="form-label">Status</label>
<select class="form-select" id="Status" name="Status" required>
<option value="Present">Present</option>
<option value="Absent">Absent</option>
<option value="Leave">Leave</option>
</select>
</div>
<button type="submit" class="btn btn-primary">Create Attendance Record</button>
</form>
</div>
</body>
</html>
12. Attendance Edit View: views/attendance/edit.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
<title>Edit Attendance Record</title>
</head>
<body>
<div class="container">
<h1>Edit Attendance Record</h1>
<form action="/attendance/<%= record.AttendanceId %>" method="POST">
<div class="mb-3">
<label for="EmployeeId" class="form-label">Employee ID</label>
<input type="number" class="form-control" id="EmployeeId" name="EmployeeId" value="<%= record.EmployeeId %>" required>
</div>
<div class="mb-3">
<label for="Date" class="form-label">Date</label>
<input type="date" class="form-control" id="Date" name="Date" value="<%= record.Date.toISOString().split('T')[0] %>" required>
</div>
<div class="mb-3">
<label for="Status" class="form-label">Status</label>
<select class="form-select" id="Status" name="Status" required>
<option value="Present" <%= record.Status === 'Present' ? 'selected' : '' %>>Present</option>
<option value="Absent" <%= record.Status === 'Absent' ? 'selected' : '' %>>Absent</option>
<option value="Leave" <%= record.Status === 'Leave' ? 'selected' : '' %>>Leave</option>
</select>
</div>
<button type="submit" class="btn btn-primary">Update Attendance Record</button>
</form>
</div>
</body>
</html>
Step 8: Integrate All Routes in the Main Application
In your main application file (e.g., app.js), integrate all the routes.
// app.js
const express = require('express');
const bodyParser = require('body-parser');
const sequelize = require('./config/database');
const userRoutes = require('./routes/userRoutes');
const roleRoutes = require('./routes/roleRoutes');
const employeeRoutes = require('./routes/employeeRoutes');
const attendanceRoutes = require('./routes/attendanceRoutes');
const payrollRoutes = require('./routes/payrollRoutes');
const performanceRoutes = require('./routes/performanceRoutes');
const jobPostingRoutes = require('./routes/jobPostingRoutes');
const trainingProgramRoutes = require('./routes/trainingProgramRoutes');
const leaveRequestRoutes = require('./routes/leaveRequestRoutes');
const documentRoutes = require('./routes /documentRoutes');
const policyRoutes = require('./routes/policyRoutes');
const announcementRoutes = require('./routes/announcementRoutes');
const app = express();
app.set('view engine', 'ejs');
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static('public'));
app.use('/users', userRoutes);
app.use('/roles', roleRoutes);
app.use('/employees', employeeRoutes);
app.use('/attendance', attendanceRoutes);
app.use('/payroll', payrollRoutes);
app.use('/performance', performanceRoutes);
app.use('/job-postings', jobPostingRoutes);
app.use('/training-programs', trainingProgramRoutes);
app.use('/leave-requests', leaveRequestRoutes);
app.use('/documents', documentRoutes);
app.use('/policies', policyRoutes);
app.use('/announcements', announcementRoutes);
const PORT = process.env.PORT || 3000;
sequelize.sync().then(() => {
app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`);
});
});
With this setup, you now have a complete CRUD application for managing users, roles, employees, attendance, payroll, performance, job postings, training programs, leave requests, documents, policies, and announcements using Node.js, Sequelize, Express, EJS, and Bootstrap 5. You can further enhance the application by adding features such as authentication, authorization, and more advanced UI components as needed.
Creating a Dashboard Page
To create a dashboard page that displays consolidated data related to your HR management project, we will follow these steps:
Steps Overview
Create a Dashboard Controller: This controller will fetch data from various models and aggregate it.
Set Up Dashboard Routes: Define a route for accessing the dashboard.
Create a Dashboard View: Use EJS to create a view that will render the dashboard and display the consolidated data.
Step 1: Create the Dashboard Controller
Create a file named DashboardController.js in the controllers directory. This controller will fetch and consolidate data from various models.
// controllers/DashboardController.js
const User = require('../models/User');
const Employee = require('../models/Employee');
const Attendance = require('../models/Attendance');
const Payroll = require('../models/Payroll');
const Performance = require('../models/Performance');
const JobPosting = require('../models/JobPosting');
const TrainingProgram = require('../models/TrainingProgram');
const LeaveRequest = require('../models/LeaveRequest');
const Document = require('../models/Document');
const Policy = require('../models/Policy');
const Announcement = require('../models/Announcement');
class DashboardController {
async getDashboardData(req, res) {
try {
const userCount = await User.count();
const employeeCount = await Employee.count();
const attendanceCount = await Attendance.count();
const payrollCount = await Payroll.count();
const performanceCount = await Performance.count();
const jobPostingCount = await JobPosting.count();
const trainingProgramCount = await TrainingProgram.count();
const leaveRequestCount = await LeaveRequest.count();
const documentCount = await Document.count();
const policyCount = await Policy.count();
const announcementCount = await Announcement.count();
const dashboardData = {
userCount,
employeeCount,
attendanceCount,
payrollCount,
performanceCount,
jobPostingCount,
trainingProgramCount,
leaveRequestCount,
documentCount,
policyCount,
announcementCount,
};
res.render('dashboard', { dashboardData });
} catch (error) {
console.error("Error fetching dashboard data:", error);
res.status(500).send("Internal Server Error");
}
}
}
module.exports = new DashboardController();
Step 2: Set Up Dashboard Routes
Create a file named dashboardRoutes.js in the routes directory. This file will define the route for accessing the dashboard.
// routes/dashboardRoutes.js
const express = require('express');
const router = express.Router();
const DashboardController = require('../controllers/DashboardController');
router.get('/', DashboardController.getDashboardData);
module.exports = router;
Step 3: Create the Dashboard View
Create a file named dashboard.ejs in the views directory. This file will render the dashboard and display the consolidated data.
<!-- views/dashboard.ejs -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
<title>Dashboard</title>
</head>
<body>
<div class="container">
<h1>Dashboard</h1>
<div class="row">
<div class="col-md-3">
<div class="card text-white bg-primary mb-3">
<div class="card-header">Total Users</div>
<div class="card-body">
<h5 class="card-title"><%= dashboardData.userCount %></h5>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card text-white bg-success mb-3">
<div class="card-header">Total Employees</div>
<div class="card-body">
<h5 class="card-title"><%= dashboardData.employeeCount %></h5>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card text-white bg-warning mb-3">
<div class="card-header">Total Attendance Records</div>
<div class="card-body">
<h5 class="card-title"><%= dashboardData.attendanceCount %></h5>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card text-white bg-danger mb-3">
<div class="card-header">Total Payroll Records</div>
<div class="card-body">
<h5 class="card-title"><%= dashboardData.payrollCount %></h5>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card text-white bg-info mb-3">
<div class="card-header">Total Performance Reviews</div>
<div class="card-body">
<h5 class="card-title"><%= dashboardData.performanceCount %></h5>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card text-white bg-secondary mb-3">
<div class="card-header">Total Job Postings</div>
<div class="card-body">
<h5 class="card-title"><%= dashboardData.jobPostingCount %></h5>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card text-white bg-dark mb-3">
<div class="card-header">Total Training Programs</div>
<div class="card-body">
<h5 class="card-title"><%= dashboardData.trainingProgramCount %></h5>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card text-white bg-light text-dark mb-3">
<div class="card-header">Total Leave Requests</div>
<div class="card-body">
<h5 class="card-title"><%= dashboardData.leaveRequestCount %></h5>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card text-white bg-success mb-3">
<div class="card-header">Total Documents</div>
<div class="card-body">
<h5 class="card-title"><%= dashboardData.documentCount %></h5>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card text-white bg-danger mb-3">
<div class="card-header">Total Policies</div>
<div class="card-body">
<h5 class="card -title"><%= dashboardData.policyCount %></h5>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card text-white bg-warning mb-3">
<div class="card-header">Total Announcements</div>
<div class="card-body">
<h5 class="card-title"><%= dashboardData.announcementCount %></h5>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
Step 4: Integrate Dashboard Routes in the Main Application
In your main application file (e.g., app.js), integrate the dashboard routes.
// app.js
const express = require('express');
const bodyParser = require('body-parser');
const sequelize = require('./config/database');
const userRoutes = require('./routes/userRoutes');
const roleRoutes = require('./routes/roleRoutes');
const employeeRoutes = require('./routes/employeeRoutes');
const attendanceRoutes = require('./routes/attendanceRoutes');
const payrollRoutes = require('./routes/payrollRoutes');
const performanceRoutes = require('./routes/performanceRoutes');
const jobPostingRoutes = require('./routes/jobPostingRoutes');
const trainingProgramRoutes = require('./routes/trainingProgramRoutes');
const leaveRequestRoutes = require('./routes/leaveRequestRoutes');
const documentRoutes = require('./routes/documentRoutes');
const policyRoutes = require('./routes/policyRoutes');
const announcementRoutes = require('./routes/announcementRoutes');
const dashboardRoutes = require('./routes/dashboardRoutes'); // Import dashboard routes
const app = express();
app.set('view engine', 'ejs');
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static('public'));
app.use('/users', userRoutes);
app.use('/roles', roleRoutes);
app.use('/employees', employeeRoutes);
app.use('/attendance', attendanceRoutes);
app.use('/payroll', payrollRoutes);
app.use('/performance', performanceRoutes);
app.use('/job-postings', jobPostingRoutes);
app.use('/training-programs', trainingProgramRoutes);
app.use('/leave-requests', leaveRequestRoutes);
app.use('/documents', documentRoutes);
app.use('/policies', policyRoutes);
app.use('/announcements', announcementRoutes);
app.use('/dashboard', dashboardRoutes); // Use dashboard routes
const PORT = process.env.PORT || 3000;
sequelize.sync().then(() => {
app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`);
});
});
With these steps, you have created a dashboard page that consolidates and displays data related to users, employees, attendance, payroll, performance, job postings, training programs, leave requests, documents, policies, and announcements. You can further enhance the dashboard by adding charts or graphs for better visualization of the data.