Skip to content

API created for Dashboard Data#13

Merged
harshGupta090722 merged 1 commit into
mainfrom
Development
Apr 30, 2026
Merged

API created for Dashboard Data#13
harshGupta090722 merged 1 commit into
mainfrom
Development

Conversation

@harshGupta090722
Copy link
Copy Markdown
Owner

@harshGupta090722 harshGupta090722 commented Apr 30, 2026

Summary by CodeRabbit

  • New Features

    • Added a dashboard with role-based views: administrators can view employee counts, daily attendance summaries, and pending leave requests; regular users can monitor their own attendance, pending leaves, and access their latest payslip.
  • Documentation

    • Added performance optimization guidance demonstrating concurrent query execution patterns.
  • Chores

    • Updated dependencies.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 30, 2026

📝 Walkthrough

Walkthrough

A dashboard endpoint is implemented with role-based logic: admin users receive aggregated employee, attendance, and leave counts; non-admin users get personalized attendance and payslip data. Supporting infrastructure includes new route handler, API route registration, and documentation example. A build-level package.json is removed while server dependencies are updated.

Changes

Cohort / File(s) Summary
Documentation & Learning
Learnings.md
Added example demonstrating sequential vs. parallel database query performance using Promise.all for concurrent execution.
Package Management
package.json, server/package.json
Root package.json entirely removed; server/package.json adds bcryptjs dependency (^3.0.3).
Dashboard Feature
server/controllers/dashboardController.js, server/routes/dashboardRoutes.js, server/server.js
Implements new dashboard endpoint with role-based branching: admin role aggregates employee/attendance/leave counts, non-admin role returns personalized user dashboard. Route protected by protect middleware, mounted at /api/dashboard.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Server as /api/dashboard<br/>(protect middleware)
    participant SessionData as Session Data
    participant AdminPath as Admin Path<br/>(queries: Employee,<br/>Attendance, Leave,<br/>Departments)
    participant UserPath as Non-Admin Path<br/>(queries: Employee,<br/>Attendance, Leave,<br/>Payslip)

    Client->>Server: GET /api/dashboard
    Server->>SessionData: Check session.role
    
    alt Admin Role
        SessionData-->>Server: role = ADMIN
        Server->>AdminPath: Count employees,<br/>attendance (today),<br/>pending leaves,<br/>departments
        AdminPath-->>Server: {employeeCount,<br/>attendanceCount,<br/>leaveCount,<br/>departmentCount}
        Server-->>Client: 200 {role, stats}
    else Non-Admin Role
        SessionData-->>Server: role = USER
        Server->>UserPath: Look up employee<br/>by session.userId
        alt Employee Found
            UserPath-->>Server: Fetch attendance (month),<br/>pending leaves,<br/>latest payslip<br/>(concurrent queries)
            UserPath-->>Server: {attendance,<br/>pendingLeaves,<br/>payslip}
            Server-->>Client: 200 {role, employee,<br/>attendance, leaves,<br/>payslip}
        else Employee Not Found
            Server-->>Client: 404 {message}
        end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

📊 A dashboard blooms with role-based sight,
Admins see stats sparkling bright,
While users peek their monthly flow,
Parallel queries steal the show! ✨🐰

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely summarizes the primary change: creating a new dashboard API endpoint with supporting controller, routes, and server integration.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch Development

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 0/1 reviews remaining, refill in 60 minutes.

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (1)
server/package.json (1)

15-16: Remove bcrypt from package.json — it is unused.

The codebase imports and uses only bcryptjs (found in authController.js and employeeController.js). The bcrypt package on line 15 is not referenced anywhere and can be removed to eliminate the unnecessary native dependency and reduce the dependency footprint.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/package.json` around lines 15 - 16, Remove the unused "bcrypt"
dependency from package.json (the line with "bcrypt": "^6.0.0") since the
codebase uses only bcryptjs; after removing that entry, run your package manager
(npm install or yarn install) to update package-lock.json / yarn.lock and verify
there are no imports of "bcrypt" (search for "require('bcrypt')" or "import
bcrypt") in files like authController.js and employeeController.js to ensure
nothing breaks.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@server/controllers/dashboardController.js`:
- Around line 35-38: The Employee lookup in dashboardController.js uses
Employee.findOne({ userId: session.userId }) and therefore returns soft-deleted
records; update the query to also filter out deleted employees (e.g., include
isDeleted: false) or explicitly check employee.isDeleted after retrieval and
return 404 if true so soft-deleted users cannot fetch dashboard data; ensure you
still call .lean() and return the same 404 response when the filtered query
yields no result.
- Around line 1-4: Add an import for the Payslip model at the top of
dashboardController.js so the non-admin branch that calls Payslip.findOne(...)
(the Payslip symbol used around the non-admin dashboard logic) doesn't throw a
ReferenceError; mirror the existing model imports (e.g., Attendance, Employee,
LeaveApplication) and import Payslip before it's referenced in the file.
- Around line 40-47: currentMonthAttendance query uses an undefined today and
incorrectly sets the lower bound to the current day at 01:00; declare const
today = new Date() before the Attendance.countDocuments call and change the date
range to the start of the month and start of next month (e.g., new
Date(today.getFullYear(), today.getMonth(), 1, 0, 0, 0) as the $gte and new
Date(today.getFullYear(), today.getMonth() + 1, 1, 0, 0, 0) as the $lt) when
building the Attendance.countDocuments query that references employee._id.
- Around line 18-23: The todayAttendance query uses Attendance.countDocuments
with a date range where both bounds are the same (startOfDay), causing zero
results; update the upper bound to the start of the next day (e.g., compute
startOfDay with new Date().setHours(0,0,0,0) and set the $lt bound to new
Date(startOfDay).setDate(startOfDay.getDate() + 1) or use setHours(24,0,0,0)) so
the filter becomes date >= startOfDay && date < startOfNextDay; adjust the code
around Attendance.countDocuments and the todayAttendance variable accordingly.

In `@server/routes/dashboardRoutes.js`:
- Around line 2-3: The import for the protect middleware is pointing to the
wrong module; update the import statement that brings in protect (the one paired
with getDashboard) so it imports protect from the auth module in the middleware
directory (i.e., import protect from the auth.js middleware export) to match
other routes and fix module resolution errors.

---

Nitpick comments:
In `@server/package.json`:
- Around line 15-16: Remove the unused "bcrypt" dependency from package.json
(the line with "bcrypt": "^6.0.0") since the codebase uses only bcryptjs; after
removing that entry, run your package manager (npm install or yarn install) to
update package-lock.json / yarn.lock and verify there are no imports of "bcrypt"
(search for "require('bcrypt')" or "import bcrypt") in files like
authController.js and employeeController.js to ensure nothing breaks.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a4666a24-5f85-40ad-a549-451a34ed9459

📥 Commits

Reviewing files that changed from the base of the PR and between 9fe6034 and c1b9706.

⛔ Files ignored due to path filters (2)
  • package-lock.json is excluded by !**/package-lock.json
  • server/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (6)
  • Learnings.md
  • package.json
  • server/controllers/dashboardController.js
  • server/package.json
  • server/routes/dashboardRoutes.js
  • server/server.js
💤 Files with no reviewable changes (1)
  • package.json

Comment on lines +1 to +4
import { DEPARTMENTS } from "../constants/departments.js";
import Attendance from "../models/Attendance.js"
import Employee from "../models/Employee.js"
import LeaveApplication from "../models/LeaveApplication.js";
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Import Payslip before using it on Line 53.

The non-admin branch calls Payslip.findOne(...), but this model is never imported in this file. That path will crash with a ReferenceError.

Suggested fix
 import { DEPARTMENTS } from "../constants/departments.js";
 import Attendance from "../models/Attendance.js"
 import Employee from "../models/Employee.js"
 import LeaveApplication from "../models/LeaveApplication.js";
+import Payslip from "../models/Payslip.js";
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { DEPARTMENTS } from "../constants/departments.js";
import Attendance from "../models/Attendance.js"
import Employee from "../models/Employee.js"
import LeaveApplication from "../models/LeaveApplication.js";
import { DEPARTMENTS } from "../constants/departments.js";
import Attendance from "../models/Attendance.js"
import Employee from "../models/Employee.js"
import LeaveApplication from "../models/LeaveApplication.js";
import Payslip from "../models/Payslip.js";
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/controllers/dashboardController.js` around lines 1 - 4, Add an import
for the Payslip model at the top of dashboardController.js so the non-admin
branch that calls Payslip.findOne(...) (the Payslip symbol used around the
non-admin dashboard logic) doesn't throw a ReferenceError; mirror the existing
model imports (e.g., Attendance, Employee, LeaveApplication) and import Payslip
before it's referenced in the file.

Comment on lines +18 to +23
Attendance.countDocuments({
date: {
$gte: new Date(new Date().setHours(0, 0, 0, 0)),
$lt: new Date(new Date().setHours(0, 0, 0, 0)),
}
}),
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

todayAttendance will always be 0 with this range.

Line 20 and Line 21 both resolve to the same timestamp, so the query becomes date >= startOfDay && date < startOfDay, which no document can satisfy.

Suggested fix
+            const startOfToday = new Date();
+            startOfToday.setHours(0, 0, 0, 0);
+            const startOfTomorrow = new Date(startOfToday);
+            startOfTomorrow.setDate(startOfTomorrow.getDate() + 1);
+
             const [totalEmployees, todayAttendance, pendingLeaves] = await
                 Promise.all([
                     Employee.countDocuments({ isDeleted: { $ne: true } }),
                     Attendance.countDocuments({
                         date: {
-                            $gte: new Date(new Date().setHours(0, 0, 0, 0)),
-                            $lt: new Date(new Date().setHours(0, 0, 0, 0)),
+                            $gte: startOfToday,
+                            $lt: startOfTomorrow,
                         }
                     }),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/controllers/dashboardController.js` around lines 18 - 23, The
todayAttendance query uses Attendance.countDocuments with a date range where
both bounds are the same (startOfDay), causing zero results; update the upper
bound to the start of the next day (e.g., compute startOfDay with new
Date().setHours(0,0,0,0) and set the $lt bound to new
Date(startOfDay).setDate(startOfDay.getDate() + 1) or use setHours(24,0,0,0)) so
the filter becomes date >= startOfDay && date < startOfNextDay; adjust the code
around Attendance.countDocuments and the todayAttendance variable accordingly.

Comment on lines +35 to +38
const employee = await Employee.findOne({ userId: session.userId }).lean();

if (!employee)
return res.status(404).json({ error: "Employee not found" });
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Soft-deleted employees can still fetch dashboard data.

This lookup only checks userId. Because the JWT stays valid after login, a soft-deleted employee can still resolve here until the token expires unless isDeleted is filtered too.

Suggested fix
-            const employee = await Employee.findOne({ userId: session.userId }).lean();
+            const employee = await Employee.findOne({
+                userId: session.userId,
+                isDeleted: { $ne: true },
+            }).lean();
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const employee = await Employee.findOne({ userId: session.userId }).lean();
if (!employee)
return res.status(404).json({ error: "Employee not found" });
const employee = await Employee.findOne({
userId: session.userId,
isDeleted: { $ne: true },
}).lean();
if (!employee)
return res.status(404).json({ error: "Employee not found" });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/controllers/dashboardController.js` around lines 35 - 38, The Employee
lookup in dashboardController.js uses Employee.findOne({ userId: session.userId
}) and therefore returns soft-deleted records; update the query to also filter
out deleted employees (e.g., include isDeleted: false) or explicitly check
employee.isDeleted after retrieval and return 404 if true so soft-deleted users
cannot fetch dashboard data; ensure you still call .lean() and return the same
404 response when the filtered query yields no result.

Comment on lines +40 to +47
const [currentMonthAttendance, pendingLeaves, latestPayslip] = await Promise.all([
Attendance.countDocuments({
employeeId: employee._id,
date: {
$gte: new Date(today.getFullYear(), today.getMonth(), today.getDate(), 1),
$lt: new Date(today.getFullYear(), today.getMonth() + 1, 1),
}
}),
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

currentMonthAttendance can never work as written.

Line 44 and Line 45 reference today, which is never defined, so the employee dashboard will throw before this query runs. Even after defining it, the lower bound starts on the current day at 01:00, not at the first day of the month.

Suggested fix
+            const today = new Date();
+            const startOfMonth = new Date(today.getFullYear(), today.getMonth(), 1);
+            const startOfNextMonth = new Date(today.getFullYear(), today.getMonth() + 1, 1);
+
             const [currentMonthAttendance, pendingLeaves, latestPayslip] = await Promise.all([
                 Attendance.countDocuments({
                     employeeId: employee._id,
                     date: {
-                        $gte: new Date(today.getFullYear(), today.getMonth(), today.getDate(), 1),
-                        $lt: new Date(today.getFullYear(), today.getMonth() + 1, 1),
+                        $gte: startOfMonth,
+                        $lt: startOfNextMonth,
                     }
                 }),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/controllers/dashboardController.js` around lines 40 - 47,
currentMonthAttendance query uses an undefined today and incorrectly sets the
lower bound to the current day at 01:00; declare const today = new Date() before
the Attendance.countDocuments call and change the date range to the start of the
month and start of next month (e.g., new Date(today.getFullYear(),
today.getMonth(), 1, 0, 0, 0) as the $gte and new Date(today.getFullYear(),
today.getMonth() + 1, 1, 0, 0, 0) as the $lt) when building the
Attendance.countDocuments query that references employee._id.

Comment on lines +2 to +3
import { protect } from "../middlewares/protect.js";
import { getDashboard } from "../controllers/dashboardController.js";
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -e

echo "Candidate middleware files:"
fd -t f 'protect\.js|auth\.js' server

echo
echo "Where protect is exported:"
rg -n -C2 --glob 'server/**/*.js' 'export\s+(const|function)\s+protect|export\s*\{\s*protect\s*\}' server

echo
echo "Where the dashboard route imports protect from:"
rg -n -C2 --glob 'server/routes/**/*.js' 'import\s*\{\s*protect\s*\}\s*from' server/routes

Repository: harshGupta090722/EMS

Length of output: 1771


Fix incorrect import path for the protect middleware.

The protect middleware is exported from server/middleware/auth.js, but this file imports from a non-existent path. Update line 2:

import { protect } from "../middleware/auth.js";

All other route files use this correct path. The current import will fail during module resolution.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/routes/dashboardRoutes.js` around lines 2 - 3, The import for the
protect middleware is pointing to the wrong module; update the import statement
that brings in protect (the one paired with getDashboard) so it imports protect
from the auth module in the middleware directory (i.e., import protect from the
auth.js middleware export) to match other routes and fix module resolution
errors.

@harshGupta090722 harshGupta090722 merged commit b6ef4c8 into main Apr 30, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant