Skip to content

fix: enforce security, validation, runtime stability, and dashboard correctness#8

Open
ArhanAnsari wants to merge 24 commits intoJavaScript-Mastery-Pro:mainfrom
ArhanAnsari:fix/bughunt-arhan
Open

fix: enforce security, validation, runtime stability, and dashboard correctness#8
ArhanAnsari wants to merge 24 commits intoJavaScript-Mastery-Pro:mainfrom
ArhanAnsari:fix/bughunt-arhan

Conversation

@ArhanAnsari
Copy link
Copy Markdown

@ArhanAnsari ArhanAnsari commented Apr 18, 2026

Overview

This PR resolves multiple high-impact issues identified during the BugHunt Blitz challenge. The changes focus on strengthening API security, enforcing strict validation, improving runtime stability, and ensuring consistent dashboard data behavior.


Key Fixes

🔒 Security & Authorization

  • Enforced strict ownership checks (teacherId) across all [id] mutation routes:
    • Students, Grades, Assignments, Announcements
  • Prevented cross-tenant access (IDOR vulnerabilities)
  • Strengthened authorization logic in PUT and DELETE endpoints across multiple APIs

⚙️ Runtime Stability & Error Handling

  • Improved error handling across all APIs (students, grades, assignments, announcements, profile)
  • Removed unsafe error responses and standardized failure handling
  • Prevented runtime crashes caused by invalid inputs and unhandled states

✅ Validation & Input Safety

  • Added ObjectId validation for studentId in:
    • Grades API
    • Attendance API
  • Ensured invalid IDs return proper 400 responses instead of causing server errors
  • Improved schema-level validation and request handling

🧠 Logic & Data Correctness

  • Fixed dashboard data loading issues with proper error handling (res.ok checks)
  • Corrected total calculations for students and assignments to avoid pagination-based inaccuracies
  • Standardized grade-point mapping across the application for consistent calculations

🗄️ Database & Setup Fixes

  • Refactored MongoDB connection logic for better reliability
  • Improved seed script diagnostics to ensure successful database initialization

🎨 Minor Improvements

  • Updated UI styling for authentication pages
  • Improved readability of GRADE_POINT configuration

Notes

  • Followed one bug = one commit strategy for clean and traceable history
  • All fixes are minimal and targeted to avoid unnecessary refactoring
  • Focused strictly on real issues (security, validation, runtime, and logic)

Verification

  • npm run lint passed
  • npm run build passed
  • ✅ Application runs successfully without runtime errors
  • ✅ Database connection and seeding verified

Summary

This PR significantly improves:

  • Security isolation
  • API reliability
  • Input validation
  • Database stability
  • Dashboard correctness

The codebase is now stable and ready for submission.

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Enhanced security by restricting data modifications to authenticated users' own records
    • Improved error handling with clearer, consistent error messages
    • Added strict validation for student identifiers
  • Improvements

    • Strengthened database connection security with TLS and increased timeout settings
    • Better error recovery for dashboard data loading
  • Style

    • Updated sign-in and sign-up page backgrounds

Copilot AI review requested due to automatic review settings April 18, 2026 08:35
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 18, 2026

Warning

Rate limit exceeded

@ArhanAnsari has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 21 minutes and 19 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 21 minutes and 19 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a8f2d35a-2ef4-4628-8679-64b31e9addf1

📥 Commits

Reviewing files that changed from the base of the PR and between 8d95d84 and 1e55bb3.

📒 Files selected for processing (10)
  • app/api/announcements/[id]/route.ts
  • app/api/assignments/[id]/route.ts
  • app/api/attendance/route.ts
  • app/api/grades/[id]/route.ts
  • app/api/grades/route.ts
  • app/api/profile/route.ts
  • app/api/students/[id]/route.ts
  • app/dashboard/OverviewClient.tsx
  • models/Teacher.ts
  • scripts/seed.mjs
📝 Walkthrough

Walkthrough

This PR adds authentication-based authorization scoping to API endpoints (restricting updates/deletions to authenticated teachers), introduces MongoDB ObjectId validation for studentId fields, standardizes error responses with generic messages, updates CGPA grade mappings (D: 4→5), enhances dashboard data validation, and improves MongoDB connection configuration with TLS and timeout settings.

Changes

Cohort / File(s) Summary
Authentication Pages
app/(auth)/sign-in/[[...sign-in]]/page.tsx, app/(auth)/sign-up/[[...sign-up]]/page.tsx
Updated Tailwind gradient utility class from bg-gradient-to-br to bg-linear-to-br for background styling.
API Authorization Scoping
app/api/announcements/[id]/route.ts, app/api/assignments/[id]/route.ts, app/api/grades/[id]/route.ts, app/api/students/[id]/route.ts
Added teacherId: userId constraint to PUT/DELETE queries, restricting data modifications to the authenticated teacher. Updated error messages to use consistent double-quoted strings.
API Data Validation
app/api/attendance/route.ts, app/api/grades/route.ts, app/api/students/route.ts
Integrated mongoose.Types.ObjectId.isValid() validation for studentId fields; returns 400 on invalid ObjectIds. Updated StudentSchema parsing to enforce validation before data persistence.
API Error Handling & Configuration
app/api/assignments/route.ts, app/api/grades/route.ts, app/api/profile/route.ts
Standardized error responses to return generic { error: "Internal server error" } messages instead of stack traces. Changed GET auth in profile to use only auth() instead of query parameters. Ensured async operations are awaited.
Dashboard Data Loading
app/dashboard/OverviewClient.tsx
Added res.ok check after fetches; throws on failed API responses. Updated CGPA mapping for grade D from 4 to 5. Changed totalStudents and totalAssignments computation to prefer .total fields with fallbacks.
Dashboard Formatting
app/dashboard/grades/GradesClient.tsx, app/dashboard/students/StudentsClient.tsx
Reformatted GRADE_POINT mapping objects from single-line to multi-line layout while preserving grade-to-point values.
Database Configuration
lib/mongodb.ts
Added tls: true and serverSelectionTimeoutMS: 10000 to mongoose.connect options; normalized string quoting and semicolons.
Seed Script Enhancement
scripts/seed.mjs
Added try/catch around connection with diagnostic logging for TLS/SSL/auth failures. Introduced post-insert verification step counting seeded documents by teacherId. Added explicit process.exit() calls and enhanced error reporting.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Poem

🐰 Authorization flows with teacher's care,
ObjectIds validated with MongoDB flair,
Gradients shift from old to new,
Seeds verified, connections too! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.69% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title directly and concisely summarizes the main objective: enforcing security (ownership checks), validation (ObjectId formats), runtime stability (error handling), and dashboard correctness across multiple endpoints.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

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: 10

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
app/api/profile/route.ts (1)

94-114: ⚠️ Potential issue | 🟡 Minor

academicHistory entry lengths are unbounded.

The array length is capped at 20, but each entry's year, title, and description strings are not length-validated. A malicious/buggy client can push very large strings (e.g., megabytes of text per entry × 20 entries) into the Teacher document, bloating storage and response payloads. Consider enforcing per-field max lengths (e.g., 10/200/2000) here and/or in the Mongoose schema.

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

In `@app/api/profile/route.ts` around lines 94 - 114, The academicHistory
validation currently checks array length and types but not string lengths;
update the validation around academicHistory in route.ts to enforce per-field
max lengths (for example: year max 10 chars, title max 200 chars, description
max 2000 chars) and ensure description is optional but when present is a string
within that limit; adjust the Array.every check on academicHistory to include
these length checks and return the same 400 NextResponse.json error if any entry
exceeds limits, and also mirror these constraints in the Teacher/Mongoose schema
(add maxlength validators for year, title, description) so DB-level validation
prevents oversized entries.
app/api/attendance/route.ts (1)

132-147: ⚠️ Potential issue | 🟠 Major

Verify studentId ownership before upserting attendance.

The POST path validates only ObjectId shape. A teacher can upsert attendance for any valid studentId, including another tenant’s student, while supplying arbitrary studentName and class. Check Student.exists({ _id: studentId, teacherId: userId }) before writing.

🛡️ Suggested direction
+import { Student } from '@/models/Student'
     if (isBulk) {
+      const studentIds = [
+        ...new Set((parsed.data as z.infer<typeof BulkSchema>).map((record) => record.studentId)),
+      ];
+      const ownedCount = await Student.countDocuments({
+        _id: { $in: studentIds },
+        teacherId: userId,
+      });
+      if (ownedCount !== studentIds.length) {
+        return NextResponse.json({ error: "Invalid studentId" }, { status: 400 });
+      }
+
       const ops = (parsed.data as z.infer<typeof BulkSchema>).map((record) => ({

Apply the same ownership check for the single-record branch before findOneAndUpdate.

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

In `@app/api/attendance/route.ts` around lines 132 - 147, The single-record POST
branch currently upserts attendance without verifying the teacher actually owns
the student; before calling Attendance.findOneAndUpdate use Student.exists({
_id: studentId, teacherId: userId }) (where studentId is parsed from
AttendanceSchema and userId is the authenticated teacher id) and return an
authorization error (e.g., 403) if the check fails; ensure you reference
Attendance.findOneAndUpdate and AttendanceSchema for locating the upsert and
Student.exists for the ownership check so only the owning teacher can upsert
that student’s attendance.
🧹 Nitpick comments (2)
app/api/profile/route.ts (1)

116-131: PUT silently 404s for users who haven't hit GET /api/profile yet.

findOneAndUpdate without upsert returns null when no Teacher document exists for clerkId: userId, producing a 404 even though the user is authenticated. Since GET auto-bootstraps the record, this creates an ordering dependency: any flow that issues PUT before GET (e.g., direct profile edit on first login, or after a DB wipe) will fail. Consider enabling upsert: true with setDefaultsOnInsert: true so PUT is self-sufficient and consistent with GET.

♻️ Proposed refactor
     const teacher = await Teacher.findOneAndUpdate(
       { clerkId: userId },
-      { $set: updatePayload },
-      { new: true },
+      { $set: updatePayload, $setOnInsert: { clerkId: userId } },
+      { new: true, upsert: true, setDefaultsOnInsert: true },
     );
-
-    if (!teacher) {
-      return NextResponse.json({ error: "Teacher not found" }, { status: 404 });
-    }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/api/profile/route.ts` around lines 116 - 131, The PUT handler can return
404 because Teacher.findOneAndUpdate({ clerkId: userId }, { $set: updatePayload
}, { new: true }) returns null if no document exists; update the call on Teacher
(findOneAndUpdate) to include upsert: true and setDefaultsOnInsert: true in the
options so a new Teacher is created when missing (preserving defaults), keeping
the same match on clerkId and using updatePayload for fields.
scripts/seed.mjs (1)

419-425: Let finally disconnect instead of exiting inside the try block.

Calling process.exit(0) here can bypass graceful cleanup and pending log flushes. Let main() resolve naturally; the existing catch already handles failures.

♻️ Proposed fix
-    process.exit(0)
+    return
   } catch (err) {
     console.error('\n❌  Seed operations failed:')
     console.error(`    ${err.message ?? err}`)
     throw err
   } finally {
     await mongoose.disconnect()
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/seed.mjs` around lines 419 - 425, Remove the in-try forced
process.exit(0) so the function can resolve naturally and let the existing
catch/finally perform cleanup; specifically, delete the call to process.exit(0)
inside the try block and rely on the catch to rethrow errors and the finally
block that calls mongoose.disconnect() to run for graceful cleanup and log
flushing (refer to the try/catch/finally and the process.exit(0) invocation in
scripts/seed.mjs).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/api/announcements/`[id]/route.ts:
- Around line 35-51: The code assumes body is an object and uses `key in body`,
which throws for null/primitives; after awaiting `req.json()` check that `body`
is a non-null object (and optionally not an array) before sanitizing, and if
it's not, return a 400 via `NextResponse.json({ error: "Invalid JSON request
body" }, { status: 400 })`; then proceed to build `sanitizedBody` by iterating
`ALLOWED_FIELDS` and copying values from `body`. Ensure these checks occur
immediately after `body = await req.json()` and before any use of `in` or
property access.

In `@app/api/assignments/`[id]/route.ts:
- Around line 55-59: The current use of Assignment.findOneAndUpdate(...,
sanitizedBody, { new: true }) does not run Mongoose validators; update the call
to include runValidators: true (and set context: 'query' if any validators rely
on query context) so that fields like status, kanbanStatus, deadline, and
maxMarks are validated on update; keep the selector {_id: id, teacherId: userId}
and new: true when modifying the options for the findOneAndUpdate call.

In `@app/api/attendance/route.ts`:
- Around line 8-11: The studentId refine in AttendanceSchema currently uses
mongoose.Types.ObjectId.isValid which accepts non-canonical 12-byte values;
update the validation to use mongoose.isObjectIdOrHexString (or the provided
canonical helper) to ensure only 24-char hex ObjectId strings pass; change the
refine predicate referenced on AttendanceSchema.studentId (and the similar
validation at the other occurrence around the code referenced at lines 82-85) to
call mongoose.isObjectIdOrHexString(id) (or call the isCanonicalObjectId helper)
and keep the existing error message.

In `@app/api/grades/`[id]/route.ts:
- Around line 44-48: The Grade.findOneAndUpdate call is missing runValidators so
Mongoose schema validators won't run on updates; modify the options object
passed to Grade.findOneAndUpdate (the call that currently uses { new: true }) to
include runValidators: true (e.g., { new: true, runValidators: true }) so
schema-level constraints (like marks bounds) are enforced while still keeping
the existing route-level validation around sanitizedBody.

In `@app/api/grades/route.ts`:
- Around line 24-33: The calcGrade function uses a strict greater-than for the
A+ threshold (if (pct > 90)) causing pct === 90 to fall into "A"; change that
comparison to >= so the A+ tier is consistent with all other inclusive
thresholds (i.e., use if (pct >= 90) in calcGrade), keeping the rest of the
thresholds (>=80, >=70, etc.) unchanged and still deriving pct from (marks /
max) * 100.
- Around line 92-112: The computed grade uses a fallback max (max =
parsed.data.maxMarks ?? 100) that can differ from the document's persisted
maxMarks on an update; modify the update path so calcGrade uses the effective
stored maxMarks: fetch the existing Grade (use Grade.findOne with the same
filter of teacherId/studentId/subject/term) to determine its maxMarks if
parsed.data.maxMarks is undefined, then compute grade = calcGrade(data.marks,
effectiveMax) and include that same effectiveMax in the $set payload (or require
maxMarks on updates); ensure this logic is used instead of calling calcGrade
with the hardcoded 100 fallback in the Grade.findOneAndUpdate flow.

In `@app/api/profile/route.ts`:
- Around line 16-24: The auto-bootstrap code uses unsafe optional chaining and a
non-atomic create that can race; change the email access to
clerkUser?.emailAddresses?.[0]?.emailAddress to avoid a TypeError when
emailAddresses is undefined, and replace the find-then-create logic that calls
Teacher.create (with unique clerkId) with an atomic upsert using
Teacher.findOneAndUpdate({ clerkId: userId }, { $setOnInsert: { clerkId: userId,
name: clerkUser?.fullName ?? "", email:
clerkUser?.emailAddresses?.[0]?.emailAddress ?? "", department: "", subjects: []
} }, { upsert: true, new: true, setDefaultsOnInsert: true, lean: true }) so
concurrent requests won’t produce E11000 duplicate-key errors and you get the
created/returned teacher object safely.

In `@app/api/students/`[id]/route.ts:
- Around line 7-17: ALLOWED_UPDATE_FIELDS includes a non-existent "grade"
property which causes silent ignores; remove "grade" from the
ALLOWED_UPDATE_FIELDS array in app/api/students/[id]/route.ts so student updates
only allow actual Student model fields (look for the ALLOWED_UPDATE_FIELDS
constant and delete the "grade" entry), and ensure any client documentation or
validation references the /api/grades endpoint for grade changes instead.
- Around line 35-55: The update currently writes sanitized fields directly and
bypasses schema validation; fix by enabling Mongoose update validators when
calling Student.findOneAndUpdate — add the options { new: true, runValidators:
true, context: 'query' } so Student schema validators (email format, required
constraints, etc.) are enforced on update, and ensure sanitizedBody only
contains allowed keys (ALLOWED_UPDATE_FIELDS) before calling findOneAndUpdate.

In `@app/dashboard/OverviewClient.tsx`:
- Around line 328-335: The current pendingAssignments calculation reads from the
paginated assignments array (assignments) so it undercounts; update the logic
that calls setStats so pendingAssignments uses the API's total for active
assignments instead of filtering the current page — e.g., perform a separate
fetch for active assignments (or use the response object that holds totals,
e.g., assignmentsDataActive.total or assignmentsData.totalActive) and pass that
total into setStats.pendingAssignments; ensure you still fall back to 0 if the
fetched total is undefined.

---

Outside diff comments:
In `@app/api/attendance/route.ts`:
- Around line 132-147: The single-record POST branch currently upserts
attendance without verifying the teacher actually owns the student; before
calling Attendance.findOneAndUpdate use Student.exists({ _id: studentId,
teacherId: userId }) (where studentId is parsed from AttendanceSchema and userId
is the authenticated teacher id) and return an authorization error (e.g., 403)
if the check fails; ensure you reference Attendance.findOneAndUpdate and
AttendanceSchema for locating the upsert and Student.exists for the ownership
check so only the owning teacher can upsert that student’s attendance.

In `@app/api/profile/route.ts`:
- Around line 94-114: The academicHistory validation currently checks array
length and types but not string lengths; update the validation around
academicHistory in route.ts to enforce per-field max lengths (for example: year
max 10 chars, title max 200 chars, description max 2000 chars) and ensure
description is optional but when present is a string within that limit; adjust
the Array.every check on academicHistory to include these length checks and
return the same 400 NextResponse.json error if any entry exceeds limits, and
also mirror these constraints in the Teacher/Mongoose schema (add maxlength
validators for year, title, description) so DB-level validation prevents
oversized entries.

---

Nitpick comments:
In `@app/api/profile/route.ts`:
- Around line 116-131: The PUT handler can return 404 because
Teacher.findOneAndUpdate({ clerkId: userId }, { $set: updatePayload }, { new:
true }) returns null if no document exists; update the call on Teacher
(findOneAndUpdate) to include upsert: true and setDefaultsOnInsert: true in the
options so a new Teacher is created when missing (preserving defaults), keeping
the same match on clerkId and using updatePayload for fields.

In `@scripts/seed.mjs`:
- Around line 419-425: Remove the in-try forced process.exit(0) so the function
can resolve naturally and let the existing catch/finally perform cleanup;
specifically, delete the call to process.exit(0) inside the try block and rely
on the catch to rethrow errors and the finally block that calls
mongoose.disconnect() to run for graceful cleanup and log flushing (refer to the
try/catch/finally and the process.exit(0) invocation in scripts/seed.mjs).
🪄 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: 7218cc83-bc93-4df2-b2a8-ad1d69f9b78c

📥 Commits

Reviewing files that changed from the base of the PR and between c71cbbf and 8d95d84.

📒 Files selected for processing (16)
  • app/(auth)/sign-in/[[...sign-in]]/page.tsx
  • app/(auth)/sign-up/[[...sign-up]]/page.tsx
  • app/api/announcements/[id]/route.ts
  • app/api/assignments/[id]/route.ts
  • app/api/assignments/route.ts
  • app/api/attendance/route.ts
  • app/api/grades/[id]/route.ts
  • app/api/grades/route.ts
  • app/api/profile/route.ts
  • app/api/students/[id]/route.ts
  • app/api/students/route.ts
  • app/dashboard/OverviewClient.tsx
  • app/dashboard/grades/GradesClient.tsx
  • app/dashboard/students/StudentsClient.tsx
  • lib/mongodb.ts
  • scripts/seed.mjs

Comment thread app/api/announcements/[id]/route.ts
Comment thread app/api/assignments/[id]/route.ts
Comment thread app/api/attendance/route.ts
Comment thread app/api/grades/[id]/route.ts
Comment thread app/api/grades/route.ts
Comment thread app/api/grades/route.ts
Comment thread app/api/profile/route.ts Outdated
Comment thread app/api/students/[id]/route.ts
Comment thread app/api/students/[id]/route.ts
Comment thread app/dashboard/OverviewClient.tsx Outdated
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR hardens the app’s API layer and dashboard behavior by tightening authorization/tenant isolation, improving validation and error handling, and aligning data calculations across the UI and backend.

Changes:

  • Enforced stricter auth/ownership filtering on multiple mutation routes and reduced unsafe error responses.
  • Added ObjectId validation for studentId in grades/attendance APIs and improved request parsing/validation.
  • Improved dashboard fetch robustness (res.ok checks) and corrected summary totals/grade-point mapping consistency.

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
scripts/seed.mjs Adds MongoDB connection diagnostics and post-seed verification counts.
lib/mongodb.ts Updates shared Mongoose connection options (TLS/timeout) with cached connection logic preserved.
app/dashboard/students/StudentsClient.tsx Re-formats grade-point mapping used for CGPA calculation.
app/dashboard/grades/GradesClient.tsx Re-formats grade-point mapping used for CGPA calculations.
app/dashboard/OverviewClient.tsx Adds response OK checks, fixes grade-point mapping for D, and corrects totals using API total fields.
app/api/students/route.ts Strengthens request validation and error handling for student listing/creation.
app/api/students/[id]/route.ts Adds ObjectId validation and enforces teacher ownership in update/delete queries.
app/api/profile/route.ts Removes cross-user profile access and improves PUT body validation/error handling.
app/api/grades/route.ts Adds studentId ObjectId validation, safer parsing, and avoids leaking stack traces.
app/api/grades/[id]/route.ts Enforces teacher ownership in update/delete queries and improves parsing.
app/api/attendance/route.ts Adds ObjectId validation for studentId in schema and query filters.
app/api/assignments/route.ts Avoids returning stack traces in 500 responses.
app/api/assignments/[id]/route.ts Enforces teacher ownership in update/delete queries and improves parsing/validation.
app/api/announcements/[id]/route.ts Enforces teacher ownership in update/delete queries and improves parsing/validation.
app/(auth)/sign-up/[[...sign-up]]/page.tsx Updates Tailwind gradient utility usage for auth UI.
app/(auth)/sign-in/[[...sign-in]]/page.tsx Updates Tailwind gradient utility usage for auth UI.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread scripts/seed.mjs
Comment on lines +246 to +250
console.error('\n❌ MongoDB Connection Failed!')
console.error(` Error: ${err.message}`)

if (err.message.includes('tls') || err.message.includes('SSL') || err.message.includes('tlsv1 alert')) {
console.error('\n🔍 DIAGNOSTIC (TLS/SSL Issue):')
Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

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

The catch block assumes err is an Error (err.message, err.name). If a non-Error is thrown, this logging/diagnostic path will itself throw and mask the root cause. Guard with err instanceof Error (or coerce via String(err)) before accessing .message / .name.

Copilot uses AI. Check for mistakes.
Comment thread scripts/seed.mjs
Comment on lines +229 to +241
const hostMatch = MONGODB_URI.match(/@([^\/?]+)/)
const host = hostMatch ? hostMatch[1] : 'local or unknown host'

console.log(`🔗 Connecting to MongoDB...`)
if (process.env.DEBUG_DB === 'true') {
console.log(`[DEBUG] Target Host: ${host}`)
console.log(`[DEBUG] Connecting with TLS and 10s timeout...`)
}

try {
await mongoose.connect(MONGODB_URI, {
bufferCommands: false,
tls: true,
Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

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

tls: true is forced for all MongoDB URIs. This can break connections to local/self-hosted MongoDB instances that aren’t configured for TLS. Consider enabling TLS conditionally (e.g., only for mongodb+srv:// or via an env flag) so the seed script works in more environments.

Suggested change
const hostMatch = MONGODB_URI.match(/@([^\/?]+)/)
const host = hostMatch ? hostMatch[1] : 'local or unknown host'
console.log(`🔗 Connecting to MongoDB...`)
if (process.env.DEBUG_DB === 'true') {
console.log(`[DEBUG] Target Host: ${host}`)
console.log(`[DEBUG] Connecting with TLS and 10s timeout...`)
}
try {
await mongoose.connect(MONGODB_URI, {
bufferCommands: false,
tls: true,
const tlsEnv = process.env.MONGODB_TLS?.trim().toLowerCase()
const shouldUseTls = tlsEnv === 'true' || tlsEnv === '1'
? true
: tlsEnv === 'false' || tlsEnv === '0'
? false
: isAtlas
const hostMatch = MONGODB_URI.match(/@([^\/?]+)/)
const host = hostMatch ? hostMatch[1] : 'local or unknown host'
console.log(`🔗 Connecting to MongoDB...`)
if (process.env.DEBUG_DB === 'true') {
console.log(`[DEBUG] Target Host: ${host}`)
console.log(`[DEBUG] Connecting with TLS ${shouldUseTls ? 'enabled' : 'disabled'} and 10s timeout...`)
}
try {
await mongoose.connect(MONGODB_URI, {
bufferCommands: false,
tls: shouldUseTls,

Copilot uses AI. Check for mistakes.
Comment thread scripts/seed.mjs Outdated
Comment on lines +418 to +419

process.exit(0)
Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

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

process.exit(0) inside the success path prevents the finally block from running, so mongoose.disconnect() will not execute. Prefer returning normally and letting the script finish (or move the exit into the main().then(...) after disconnect).

Suggested change
process.exit(0)
return

Copilot uses AI. Check for mistakes.
Comment thread lib/mongodb.ts
Comment on lines +29 to 33
.connect(MONGODB_URI, {
bufferCommands: false,
tls: true,
serverSelectionTimeoutMS: 10000,
})
Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

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

tls: true is always enabled for connectDB(). That works for Atlas (mongodb+srv://) but can break non-TLS/self-hosted MongoDB URIs. Consider making TLS conditional based on the URI scheme/host or an env flag to avoid unexpected connection failures in other environments.

Copilot uses AI. Check for mistakes.
// Validate ObjectId
if (!mongoose.Types.ObjectId.isValid(id)) {
return NextResponse.json({ error: 'Not found' }, { status: 404 })
return NextResponse.json({ error: "Not found" }, { status: 404 });
Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

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

PUT returns 404 for a malformed ObjectId (Not found), while DELETE in the same file returns 400 (Invalid id). This inconsistency makes client error handling harder. Consider returning 400 for invalid IDs in PUT as well (and keep 404 for well-formed-but-missing documents).

Suggested change
return NextResponse.json({ error: "Not found" }, { status: 404 });
return NextResponse.json({ error: "Invalid id" }, { status: 400 });

Copilot uses AI. Check for mistakes.
Comment thread app/api/students/[id]/route.ts Outdated
const ALLOWED_UPDATE_FIELDS = [
"name",
"email",
"grade",
Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

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

ALLOWED_UPDATE_FIELDS includes "grade", but the Student schema doesn’t define a grade field. Updates to this key will be ignored (or rejected, depending on strict mode), which is confusing for API consumers. Consider removing it from the whitelist or adding it to the schema if intended.

Suggested change
"grade",

Copilot uses AI. Check for mistakes.
Comment thread scripts/seed.mjs
} else if (err.message.includes('bad auth')) {
console.error('\n🔍 DIAGNOSTIC (Auth Issue): Check if your password contains unencoded special characters.')
}
process.exit(1)
Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

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

Calling process.exit(1) here will bypass any later cleanup code (including the finally block that disconnects Mongoose) and can truncate buffered logs. Prefer throwing/returning and letting the top-level main().catch(...) handle exiting after cleanup.

Suggested change
process.exit(1)
throw err

Copilot uses AI. Check for mistakes.
Comment thread app/api/grades/route.ts
Comment on lines +92 to +95
const data = parsed.data;
const max = data.maxMarks ?? 100;
const term = data.term ?? "Term 1";

Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

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

max defaults to 100 when maxMarks is omitted, but the update payload doesn’t ensure maxMarks is actually stored as 100. This can lead to grade docs with missing maxMarks, which breaks consumers that assume it’s numeric. Consider explicitly setting maxMarks: max when it’s not provided.

Copilot uses AI. Check for mistakes.
Comment thread app/api/grades/route.ts Outdated
grade: calcGrade(data.marks, max),
},
},
{ upsert: true, new: true },
Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

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

Because this uses findOneAndUpdate with { upsert: true }, Mongoose schema defaults (like maxMarks: 100 in the model) are not applied unless setDefaultsOnInsert: true is set. Consider adding setDefaultsOnInsert: true (and optionally runValidators: true) to the options to keep inserted docs consistent.

Suggested change
{ upsert: true, new: true },
{
upsert: true,
new: true,
setDefaultsOnInsert: true,
runValidators: true,
},

Copilot uses AI. Check for mistakes.
Copilot AI and others added 9 commits April 18, 2026 08:53
Agent-Logs-Url: https://github.com/ArhanAnsari/discord-challenge/sessions/fad4ba3f-07a4-4318-99ef-0b604087422f

Co-authored-by: ArhanAnsari <109061685+ArhanAnsari@users.noreply.github.com>
Agent-Logs-Url: https://github.com/ArhanAnsari/discord-challenge/sessions/fad4ba3f-07a4-4318-99ef-0b604087422f

Co-authored-by: ArhanAnsari <109061685+ArhanAnsari@users.noreply.github.com>
…n-runtime-stability

Harden API mutation safety and align dashboard/grade correctness with review feedback
@ArhanAnsari
Copy link
Copy Markdown
Author

ArhanAnsari commented Apr 19, 2026

Name: Arhan Ansari
Email: arhanansari2009@gmail.com
PR: #8
Total Bugs Fixed: 40–50 (self-reported)


Summary

  • Enforced strict authentication and teacher ownership checks across all mutation routes, eliminating cross-tenant access risks
  • Strengthened validation layer with proper ObjectId checks, Zod schema enforcement, and rejection of malformed/invalid payloads
  • Fixed multiple async/runtime issues including missing awaits, unsafe JSON parsing, and crash-prone API flows
  • Improved error handling by removing stack trace leaks and standardizing safe server responses
  • Resolved data integrity issues in grades and attendance logic, including maxMarks validation and consistent grade calculations
  • Corrected dashboard data inconsistencies (totals, API response handling, and pagination-related inaccuracies)
  • Prevented false-success operations by enforcing strict update rules and sanitizing incoming data
  • Refined API reliability and stability across students, grades, assignments, announcements, attendance, and profile modules
  • Applied setup/runtime fixes including MongoDB connection reliability and improved seed diagnostics

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.

3 participants