Skip to content

feat: MongoDB auth, session history, and full-width UI#231

Open
CodeByAlok24 wants to merge 5 commits into
GitMetricsLab:mainfrom
CodeByAlok24:alok
Open

feat: MongoDB auth, session history, and full-width UI#231
CodeByAlok24 wants to merge 5 commits into
GitMetricsLab:mainfrom
CodeByAlok24:alok

Conversation

@CodeByAlok24
Copy link
Copy Markdown

@CodeByAlok24 CodeByAlok24 commented May 13, 2026

Related Issue

N/A - New feature addition


Description

  • Reorganized project structure: Created separate frontend/ and backend/ folders
  • Connected MongoDB Atlas for user authentication (signup/login)
  • Added user session and tracker search history persistence to database
  • Fixed full-width display on all pages (removed max-width constraints)
  • Updated CORS configuration for proper frontend-backend communication
  • Added secured session cookies and credentials handling

How Has This Been Tested?

  • Tested signup and login with MongoDB Atlas connection
  • Verified tracker history saves to database after each search
  • Tested full-width responsive display across all pages
  • Verified session persistence across page refreshes

Screenshots (if applicable)

  • Login/Signup pages with MongoDB integration
  • Tracker dashboard with full-width display
  • Session history loaded from database after login

Type of Change

  • New feature
  • Bug fix
  • Code style update
  • Breaking change
  • Documentation update

Summary by CodeRabbit

  • New Features

    • Added search history tracking—users can now view and manage their recent GitHub username lookups.
    • Launched interactive tracker dashboard with filtering, sorting, and pagination for GitHub issues and pull requests.
    • Introduced contributors directory with search and contribution-based sorting.
    • Added product highlights and footer navigation sections.
  • Documentation

    • Expanded README with comprehensive setup guide and MongoDB/authentication configuration details.
  • Security

    • Improved CORS configuration and cookie settings for enhanced security.

@netlify
Copy link
Copy Markdown

netlify Bot commented May 13, 2026

Deploy Preview for github-spy failed.

Name Link
🔨 Latest commit 4336efc
🔍 Latest deploy log https://app.netlify.com/projects/github-spy/deploys/6a04f6708acd6d0008537911

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 13, 2026

📝 Walkthrough

Walkthrough

This PR restructures the project to a frontend-first layout, moving src/ to frontend/src/, adds a GitHub activity tracker page with persistent search history, introduces a contributors discovery page with landing UI components, and enhances backend security and session handling. TypeScript typing is improved, theme context is refactored, and documentation is expanded.

Changes

Frontend Project Structure Reorganization

Layer / File(s) Summary
Theme context extraction and refactoring
frontend/src/context/theme.ts, frontend/src/context/ThemeContext.tsx, frontend/src/pages/Contact/Contact.tsx, frontend/src/pages/Login/Login.tsx, frontend/src/components/Navbar.tsx
ThemeContextType and ThemeContext creation are extracted into a new theme.ts module. Imports are updated across Contact, Login, and Navbar components to reference the new module path, simplifying context provisioning and reducing circular dependencies.
Application layout adjustment
frontend/src/App.tsx, frontend/src/pages/Home/Home.tsx
App wrapper and main content className are updated to use w-full layout utilities, removing centering rules to accommodate full-width content and restructured page hierarchy.
Frontend directory structure and Docker build
docker-compose.yml, frontend/package.json, frontend/src/... (new), src/... (removed)`
Frontend source directory is moved from root src/ to frontend/src/, and the old src/ copies (Features, Footer, Hero, HowItWorks, Contributors, Tracker) are removed. Docker Compose frontend and frontend-prod services are updated to use ./frontend as build context and mount point.

GitHub Activity Tracker with Search History

Layer / File(s) Summary
User model and tracker history schema
backend/models/User.js
User schema gains trackerHistory (array, default []) and lastTrackedAt (date, default Date.now), establishing the data structure for persisting user search history.
Backend tracker history endpoints
backend/routes/auth.js
Two new authenticated endpoints are added: GET /tracker-history retrieves the current user's search history from the database, and POST /tracker-history accepts a new username/searchedAt entry, deduplicates by case-insensitive username, prepends to history, truncates to 10 most recent items, updates lastTrackedAt, and returns the updated list.
Tracker page with filtering and pagination
frontend/src/pages/Tracker/Tracker.tsx
New interactive dashboard that authenticates with GitHub, fetches and filters issues/PRs by tab/state/title/repo/date range, manages pagination via MUI TablePagination, loads lookup history from backend (with localStorage fallback), and saves new searches to both backend and local storage. Includes helper functions for icon mapping, date formatting, and history deduplication.

Contributors Discovery and Landing Page

Layer / File(s) Summary
Contributors page with filtering and sorting
frontend/src/pages/Contributors/Contributors.tsx
New page that fetches GitHub repository contributors via axios, maintains state for search/sort filters, computes filtered results and top contributor, and renders a responsive grid with contributor cards showing avatars, contribution counts, top-3 trophies (when sorting by contributions), and action buttons linking to contributor profile and external GitHub profile.
Landing page hero and feature components
frontend/src/components/Hero.tsx, frontend/src/components/Features.tsx, frontend/src/components/HowItWorks.tsx
Three new marketing components that compose the landing page: Hero displays title, navigation links to /track and /contributors, and a mock dashboard preview; Features renders product highlights in a card grid; HowItWorks displays a three-step workflow section. All include icon usage from lucide-react and support light/dark theming.
Footer component
frontend/src/components/Footer.tsx
New footer component with GitHub link, navigation links to /contact and /about, and dynamic copyright year display.

Backend Security and Configuration

Layer / File(s) Summary
Session and CORS security hardening
backend/server.js
CORS configuration is updated from wildcard to whitelist-based origin matching FRONTEND_URL (default http://localhost:5173) with credentials enabled. Session middleware gains explicit cookie settings: httpOnly: true, secure: false (with production/HTTPS note), and sameSite: 'lax' for improved session security.
Environment configuration updates
.env.example, backend/.env.sample
Removed VITE_BACKEND_URL entry from frontend .env.example and cleared sample environment variables from backend/.env.sample, delegating environment setup documentation to the expanded README.
Improved TypeScript typing for GitHub API interactions
frontend/src/hooks/useGitHubData.ts, frontend/src/hooks/useGitHubAuth.ts, frontend/src/pages/ContributorProfile/ContributorProfile.tsx
useGitHubData exports a new GitHubItem interface and introduces internal typed interfaces for API responses, client, and error shapes; error handling is updated to cast unknown errors and check status === 403 for rate-limit detection. useGitHubAuth octokit memoization now depends only on token. ContributorProfile introduces a GitHubProfile type.

Documentation and Test Infrastructure

Layer / File(s) Summary
Setup and testing documentation expansion
README.md, frontend/package.json
README is expanded with a detailed "Setup Guide" (frontend then backend run steps), a new "MongoDB & Authentication Setup" section with example environment variables and authentication notes, and comprehensive Jasmine testing documentation including spec file locations, configuration, troubleshooting, and coverage checklist. A test script is added to frontend/package.json to run Jasmine.
Test infrastructure updates
spec/auth.routes.spec.cjs, spec/user.model.spec.cjs
Tests are refactored to obtain mongoose from User.base instead of direct imports, passport is loaded via createRequire targeting the backend's package.json, MongoDB connections drop legacy options, and database cleanup becomes conditional on an active connection before disconnecting.

Sequence Diagram(s)

sequenceDiagram
    participant User as User Browser
    participant Frontend as Frontend App
    participant Backend as Backend API
    participant GitHub as GitHub API
    participant DB as MongoDB

    User->>Frontend: Login & Enter GitHub Token
    Frontend->>Backend: POST /auth/login (credentials)
    Backend->>DB: Verify User
    DB-->>Backend: User Found
    Backend-->>Frontend: Session Cookie Set
    Frontend->>Frontend: Redirect to /track

    User->>Frontend: Enter Username to Search
    Frontend->>Frontend: Load History from Backend
    Backend->>DB: GET User Tracker History
    DB-->>Backend: Return Last 10 Searches
    Backend-->>Frontend: Return History

    Frontend->>GitHub: Search Issues/PRs (token)
    GitHub-->>Frontend: Return Results (paginated)
    Frontend->>Frontend: Filter by State/Repo/Date

    User->>Frontend: Select Repository & Filters
    Frontend->>Frontend: Recompute Filtered Results
    Frontend->>User: Display Filtered Items + Pagination

    Frontend->>Backend: POST New Search (username, timestamp)
    Backend->>DB: Update User.trackerHistory
    DB-->>Backend: Deduplicate & Truncate to 10
    Backend-->>Frontend: Return Updated History
    Frontend->>Frontend: Update localStorage & UI
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

gssoc25, level1, frontend, backend, feature, refactor

Poem

🐰 A tracker hopped into the fold,
With search histories to hold,
Contributors march in a grid,
While themes are split (a clever mid)!
Frontend blooms in / so bright,
Security locked and sessions tight. ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.29% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main changes: MongoDB authentication, session/tracker history, and full-width UI improvements.
Description check ✅ Passed The description covers all required template sections with substantive details about project reorganization, MongoDB integration, testing methodology, and change type classification.
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 unit tests (beta)
  • Create PR with unit tests

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

🎉 Thank you @CodeByAlok24 for your contribution. Please make sure your PR follows https://github.com/GitMetricsLab/github_tracker/blob/main/CONTRIBUTING.md#-pull-request-guidelines

Copy link
Copy Markdown
Contributor

@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: 9

🧹 Nitpick comments (1)
backend/models/User.js (1)

19-22: ⚡ Quick win

Consider defining a more specific schema for trackerHistory.

The trackerHistory field uses a generic Array type, which provides no validation or documentation of the expected structure. Consider defining a subdocument schema or at minimum specifying the array item type.

💡 Example of a more specific schema
+const TrackerHistoryItemSchema = new mongoose.Schema({
+  username: { type: String, required: true },
+  searchedAt: { type: Date, default: Date.now }
+}, { _id: false });
+
 const UserSchema = new mongoose.Schema({
     username: {
       type: String,
       required: true,
       unique: true,
     },
     email: {
       type: String,
       required: true,
       unique: true,
     },
     password: {
       type: String,
       required: true,
     },
     trackerHistory: {
-      type: Array,
+      type: [TrackerHistoryItemSchema],
       default: [],
     },

Adjust the subdocument fields based on what's actually stored in the tracker history.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/models/User.js` around lines 19 - 22, The trackerHistory field in
User.js is declared as a generic Array which provides no validation; replace it
with a specific subdocument schema (e.g., create a TrackerHistorySchema or
inline schema) and use an array of that schema for trackerHistory (for example
an array of objects with fields like event:String, details:Mixed or Object,
timestamp:Date, userAgent:String as appropriate); update the User schema to use
trackerHistory: { type: [TrackerHistorySchema], default: [] } (or equivalent
inline definition) so Mongoose validates items and documents the expected
structure.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@backend/routes/auth.js`:
- Around line 60-74: Validate and sanitize req.body.username and
req.body.searchedAt before using them: ensure username exists and is a non-empty
string, and ensure searchedAt is a valid date (or omit/replace with Date.now()
if invalid). In the route where you fetch User (User.findById and then mutate
user.trackerHistory), add checks that username is typeof string and trim() !==
"" and that new Date(searchedAt) is valid (isNaN(Date.parse(...)) check) and
return a 400 with a clear message if validation fails; only then perform the
existing trackerHistory filtering (user.trackerHistory.filter(...)) and unshift
with a normalized { username: username.trim(), searchedAt: new Date(validDate) }
entry.

In `@backend/server.js`:
- Around line 26-30: Update the session cookie and proxy settings to be
environment-aware: call app.set('trust proxy', 1) during server setup, and in
the session middleware's cookie config (the cookie object currently containing
httpOnly/secure/sameSite) set secure = (process.env.NODE_ENV === 'production')
and set sameSite = 'none' when in production and FRONTEND_URL is cross-origin
(otherwise keep 'lax'); ensure secure is true in production so cookies require
HTTPS and adjust sameSite to 'none' when sending credentials across origins. Use
the existing session middleware cookie object and the app.set('trust proxy', 1)
symbol names to locate where to apply these changes.

In `@frontend/package.json`:
- Line 49: Remove the backend runtime packages mistakenly declared in frontend's
devDependencies: delete the entries for "express", "mongoose",
"express-session", "passport", "passport-local", "bcryptjs", and "supertest"
from frontend/package.json so only frontend-related packages remain; locate the
devDependencies block in frontend/package.json and remove those package keys
(ensure you don't touch backend/package.json where these belong) and then run
npm/yarn install to update lockfile.
- Line 10: The frontend package.json currently defines the "test" script
("test": "jasmine") and lists jasmine and `@types/jasmine` in devDependencies
though those tests are backend specs; remove the "test" script and
jasmine-related devDependencies from frontend/package.json and add them into
backend/package.json instead: add the "test": "jasmine" script to
backend/package.json and move jasmine and `@types/jasmine` into backend's
devDependencies so backend runs the Jasmine specs (refer to the "test" script
and the jasmine/@types/jasmine entries when updating the two package.json
files).

In `@frontend/src/hooks/useGitHubData.ts`:
- Around line 77-83: The hook useGitHubData currently sets rateLimited to true
on a 403 and the existing guard then blocks all future fetches with no recovery;
modify the 403 handling to parse a Retry-After header or X-RateLimit-Reset (or
fall back to a sensible default like 60s), call setRateLimited(true) but
schedule a timer to call setRateLimited(false) after that delay, and ensure the
timer is stored in a ref and cleared on unmount or when a new rate-limit event
occurs; this uses the existing symbols rateLimited, setRateLimited, and the 403
catch branch so the guard that prevents fetches will automatically resume after
the timeout.

In `@frontend/src/pages/Signup/Signup.tsx`:
- Around line 36-38: The redirect currently depends on response.data.message
string match; change the check to use an explicit status or boolean from the API
(e.g., response.status === 201 or response.data.success === true) before calling
navigate("/login") in the signup submit handler (the block that currently
inspects response.data.message and calls navigate). Update the API contract
usage to prefer response.status or response.data.success and handle non-success
cases accordingly.

In `@frontend/src/pages/Tracker/Tracker.tsx`:
- Around line 192-193: The end-date check in matchesEnd uses new Date(endDate)
which is midnight and thus excludes items later that day; update the logic to
compare createdAt against the end-of-day timestamp (e.g., compute an endOfDay
from endDate by setting hours to 23:59:59.999 or by creating nextDay = new
Date(endDate) + 1 day and using createdAt < nextDay) so matchesEnd becomes true
for any createdAt on the selected endDate; keep matchesStart as-is using
startDate and createdAt.
- Around line 160-164: The effect currently re-runs on every username (and tab)
change causing API calls on each keystroke; change it to only run for deliberate
fetches by introducing a stable "submittedUsername" state (e.g.,
submittedUsername) that is set in the form submit handler instead of using raw
username, then update the effect to depend on submittedUsername and page (and
not username/tab) and call fetchData(submittedUsername, page + 1,
ROWS_PER_PAGE); alternatively implement a debounce that sets submittedUsername
after a short pause—update handlers that trigger fetches to set
submittedUsername so fetches only occur on submit/debounced value, not on every
keystroke.

In `@README.md`:
- Around line 92-96: The README currently contains a hardcoded MongoDB
connection string (MONGO_URI) with embedded credentials; replace that value with
a placeholder (e.g.,
MONGO_URI=mongodb+srv://<DB_USER>:<DB_PASS>@<HOST>/<DB_NAME>?retryWrites=true&w=majority)
and update the example block so no real secrets appear, and add a short note to
rotate/revoke the exposed credentials immediately; locate the example using the
MONGO_URI token and update it accordingly.

---

Nitpick comments:
In `@backend/models/User.js`:
- Around line 19-22: The trackerHistory field in User.js is declared as a
generic Array which provides no validation; replace it with a specific
subdocument schema (e.g., create a TrackerHistorySchema or inline schema) and
use an array of that schema for trackerHistory (for example an array of objects
with fields like event:String, details:Mixed or Object, timestamp:Date,
userAgent:String as appropriate); update the User schema to use trackerHistory:
{ type: [TrackerHistorySchema], default: [] } (or equivalent inline definition)
so Mongoose validates items and documents the expected structure.
🪄 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: d5596297-a7d9-4847-8620-672de32ed83d

📥 Commits

Reviewing files that changed from the base of the PR and between 56e17a3 and 4336efc.

⛔ Files ignored due to path filters (4)
  • frontend/public/crl-icon.png is excluded by !**/*.png
  • frontend/public/crl.png is excluded by !**/*.png
  • frontend/public/vite.svg is excluded by !**/*.svg
  • frontend/src/assets/react.svg is excluded by !**/*.svg
📒 Files selected for processing (52)
  • .env.example
  • README.md
  • backend/.env.sample
  • backend/models/User.js
  • backend/routes/auth.js
  • backend/server.js
  • docker-compose.yml
  • frontend/Dockerfile.dev
  • frontend/Dockerfile.prod
  • frontend/eslint.config.js
  • frontend/index.html
  • frontend/package.json
  • frontend/postcss.config.cjs
  • frontend/public/_redirects
  • frontend/src/App.css
  • frontend/src/App.tsx
  • frontend/src/Routes/Router.tsx
  • frontend/src/components/Features.tsx
  • frontend/src/components/Footer.tsx
  • frontend/src/components/Hero.tsx
  • frontend/src/components/HowItWorks.tsx
  • frontend/src/components/Navbar.tsx
  • frontend/src/components/ScrollProgressBar.tsx
  • frontend/src/context/ThemeContext.tsx
  • frontend/src/context/theme.ts
  • frontend/src/hooks/useGitHubAuth.ts
  • frontend/src/hooks/useGitHubData.ts
  • frontend/src/index.css
  • frontend/src/main.tsx
  • frontend/src/pages/About/About.tsx
  • frontend/src/pages/Contact/Contact.tsx
  • frontend/src/pages/ContributorProfile/ContributorProfile.tsx
  • frontend/src/pages/Contributors/Contributors.tsx
  • frontend/src/pages/Home/Home.tsx
  • frontend/src/pages/Login/Login.tsx
  • frontend/src/pages/Signup/Signup.tsx
  • frontend/src/pages/Tracker/Tracker.tsx
  • frontend/src/utils/constants.ts
  • frontend/src/vite-env.d.ts
  • frontend/tailwind.config.js
  • frontend/tsconfig.app.json
  • frontend/tsconfig.json
  • frontend/tsconfig.node.json
  • frontend/vite.config.ts
  • spec/auth.routes.spec.cjs
  • spec/user.model.spec.cjs
  • src/components/Features.tsx
  • src/components/Footer.tsx
  • src/components/Hero.tsx
  • src/components/HowItWorks.tsx
  • src/pages/Contributors/Contributors.tsx
  • src/pages/Tracker/Tracker.tsx
💤 Files with no reviewable changes (8)
  • backend/.env.sample
  • src/components/Features.tsx
  • src/components/Hero.tsx
  • .env.example
  • src/components/Footer.tsx
  • src/components/HowItWorks.tsx
  • src/pages/Tracker/Tracker.tsx
  • src/pages/Contributors/Contributors.tsx

Comment thread backend/routes/auth.js
Comment on lines +60 to +74
const { username, searchedAt } = req.body;
try {
const user = await User.findById(req.user.id);
if (!user) {
return res.status(404).json({ message: 'User not found' });
}

// Remove duplicate if exists (keep only unique searches)
user.trackerHistory = user.trackerHistory.filter(
item => item.username.toLowerCase() !== username.toLowerCase()
);

// Add new search at the beginning
user.trackerHistory.unshift({ username, searchedAt: new Date(searchedAt) });

Copy link
Copy Markdown
Contributor

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

Validate username and searchedAt before processing history.

The route can throw when username is missing/non-string, and invalid searchedAt is not rejected. This turns client input errors into 500s.

Suggested patch
     const { username, searchedAt } = req.body;
+    if (typeof username !== "string" || !username.trim()) {
+        return res.status(400).json({ message: "username is required" });
+    }
+    const parsedSearchedAt = searchedAt ? new Date(searchedAt) : new Date();
+    if (Number.isNaN(parsedSearchedAt.getTime())) {
+        return res.status(400).json({ message: "searchedAt must be a valid date" });
+    }
     try {
         const user = await User.findById(req.user.id);
         if (!user) {
             return res.status(404).json({ message: 'User not found' });
         }
         
         // Remove duplicate if exists (keep only unique searches)
         user.trackerHistory = user.trackerHistory.filter(
-            item => item.username.toLowerCase() !== username.toLowerCase()
+            item => item.username?.toLowerCase() !== username.toLowerCase()
         );
         
         // Add new search at the beginning
-        user.trackerHistory.unshift({ username, searchedAt: new Date(searchedAt) });
+        user.trackerHistory.unshift({ username, searchedAt: parsedSearchedAt });
📝 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 { username, searchedAt } = req.body;
try {
const user = await User.findById(req.user.id);
if (!user) {
return res.status(404).json({ message: 'User not found' });
}
// Remove duplicate if exists (keep only unique searches)
user.trackerHistory = user.trackerHistory.filter(
item => item.username.toLowerCase() !== username.toLowerCase()
);
// Add new search at the beginning
user.trackerHistory.unshift({ username, searchedAt: new Date(searchedAt) });
const { username, searchedAt } = req.body;
if (typeof username !== "string" || !username.trim()) {
return res.status(400).json({ message: "username is required" });
}
const parsedSearchedAt = searchedAt ? new Date(searchedAt) : new Date();
if (Number.isNaN(parsedSearchedAt.getTime())) {
return res.status(400).json({ message: "searchedAt must be a valid date" });
}
try {
const user = await User.findById(req.user.id);
if (!user) {
return res.status(404).json({ message: 'User not found' });
}
// Remove duplicate if exists (keep only unique searches)
user.trackerHistory = user.trackerHistory.filter(
item => item.username?.toLowerCase() !== username.toLowerCase()
);
// Add new search at the beginning
user.trackerHistory.unshift({ username, searchedAt: parsedSearchedAt });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/routes/auth.js` around lines 60 - 74, Validate and sanitize
req.body.username and req.body.searchedAt before using them: ensure username
exists and is a non-empty string, and ensure searchedAt is a valid date (or
omit/replace with Date.now() if invalid). In the route where you fetch User
(User.findById and then mutate user.trackerHistory), add checks that username is
typeof string and trim() !== "" and that new Date(searchedAt) is valid
(isNaN(Date.parse(...)) check) and return a 400 with a clear message if
validation fails; only then perform the existing trackerHistory filtering
(user.trackerHistory.filter(...)) and unshift with a normalized { username:
username.trim(), searchedAt: new Date(validDate) } entry.

Comment thread backend/server.js
Comment on lines +26 to +30
cookie: {
httpOnly: true,
secure: false, // set to true in production with HTTPS
sameSite: 'lax'
}
Copy link
Copy Markdown
Contributor

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify current session/proxy configuration in backend
rg -n "app\\.set\\(['\"]trust proxy['\"]|session\\(|secure:|sameSite:" backend/server.js
rg -n "NODE_ENV|FRONTEND_URL|SESSION_SECRET" backend/.env .env 2>/dev/null || true

Repository: GitMetricsLab/github_tracker

Length of output: 218


Add environment-aware session cookie security and trust proxy configuration.

The session cookie has secure: false hardcoded (line 28), allowing production sessions to transmit over non-HTTPS. Additionally, app.set('trust proxy', 1) is missing, which breaks session handling when deployed behind a reverse proxy.

Set secure based on the environment and configure proxy trust. For cross-origin scenarios (FRONTEND_URL with credentials), also adjust sameSite to 'none' in production.

Suggested patch
+app.set('trust proxy', 1);
+
 app.use(session({
     secret: process.env.SESSION_SECRET,
     resave: false,
     saveUninitialized: false,
     cookie: { 
         httpOnly: true, 
-        secure: false, // set to true in production with HTTPS
-        sameSite: 'lax'
+        secure: process.env.NODE_ENV === 'production',
+        sameSite: process.env.NODE_ENV === 'production' ? 'none' : 'lax'
     }
 }));
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/server.js` around lines 26 - 30, Update the session cookie and proxy
settings to be environment-aware: call app.set('trust proxy', 1) during server
setup, and in the session middleware's cookie config (the cookie object
currently containing httpOnly/secure/sameSite) set secure =
(process.env.NODE_ENV === 'production') and set sameSite = 'none' when in
production and FRONTEND_URL is cross-origin (otherwise keep 'lax'); ensure
secure is true in production so cookies require HTTPS and adjust sameSite to
'none' when sending credentials across origins. Use the existing session
middleware cookie object and the app.set('trust proxy', 1) symbol names to
locate where to apply these changes.

Comment thread frontend/package.json
"dev": "vite --host",
"build": "vite build",
"lint": "eslint .",
"test": "jasmine",
Copy link
Copy Markdown
Contributor

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find all Jasmine spec files
fd -e cjs -e js "spec\." 

# Check jasmine configuration
fd -t f "jasmine.json"

Repository: GitMetricsLab/github_tracker

Length of output: 123


🏁 Script executed:

#!/bin/bash
# Check repository structure
echo "=== Repository structure ===" 
ls -la | head -30

# Check if there are separate frontend and backend directories
echo -e "\n=== Checking for frontend/backend directories ==="
[ -d "frontend" ] && echo "frontend/ exists" || echo "frontend/ does NOT exist"
[ -d "backend" ] && echo "backend/ exists" || echo "backend/ does NOT exist"

# Check location of spec files - are they at root or in backend?
echo -e "\n=== Full paths of spec files ==="
find . -name "*.spec.cjs" -o -name "*.spec.js" 2>/dev/null | head -20

# Read frontend/package.json if it exists
echo -e "\n=== frontend/package.json (lines 1-20) ==="
[ -f "frontend/package.json" ] && head -20 frontend/package.json || echo "frontend/package.json not found"

# Read backend/package.json if it exists
echo -e "\n=== backend/package.json (lines 1-20) ==="
[ -f "backend/package.json" ] && head -20 backend/package.json || echo "backend/package.json not found"

# Check if spec directory exists at root
echo -e "\n=== Check spec/ directory ==="
[ -d "spec" ] && echo "spec/ exists at root" && ls -la spec/ || echo "spec/ does NOT exist at root"

Repository: GitMetricsLab/github_tracker

Length of output: 2655


🏁 Script executed:

#!/bin/bash
# Check for root-level package.json
echo "=== Root-level package.json ==="
[ -f "package.json" ] && cat package.json || echo "No package.json at root"

# Check for jasmine configuration files
echo -e "\n=== Jasmine configuration files ==="
fd -t f -i "jasmine" 2>/dev/null | head -20

# Check if frontend has jasmine config
echo -e "\n=== Frontend directory contents ==="
ls -la frontend/ | grep -E "(jasmine|spec|test)"

# Check if there's a jasmine.json or similar
echo -e "\n=== Looking for test config files ==="
find . -maxdepth 2 -type f \( -name "*jasmine*" -o -name "*.spec.js" -o -name "*.spec.cjs" -o -name "jest.config.*" \) 2>/dev/null

Repository: GitMetricsLab/github_tracker

Length of output: 321


🏁 Script executed:

#!/bin/bash
# Read jasmine configuration
echo "=== spec/support/jasmine.mjs ==="
cat spec/support/jasmine.mjs

# Check what dependencies are in frontend vs backend for jasmine
echo -e "\n=== Jasmine in frontend/package.json dependencies ==="
grep -i "jasmine" frontend/package.json || echo "No jasmine in frontend dependencies"

echo -e "\n=== Jasmine in backend/package.json dependencies ==="
grep -i "jasmine" backend/package.json || echo "No jasmine in backend dependencies"

# Check full devDependencies in both
echo -e "\n=== Frontend devDependencies ==="
grep -A 20 '"devDependencies"' frontend/package.json | head -25

echo -e "\n=== Backend devDependencies ==="
grep -A 20 '"devDependencies"' backend/package.json | head -25

Repository: GitMetricsLab/github_tracker

Length of output: 1379


Move the test script to backend/package.json.

The "test": "jasmine" script in frontend/package.json is configured to run backend tests (spec/auth.routes.spec.cjs, spec/user.model.spec.cjs), not frontend tests. This script and its dependencies should be in backend/package.json to maintain proper separation between frontend and backend. Additionally, the jasmine package and @types/jasmine should be moved to backend's devDependencies, not frontend's.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/package.json` at line 10, The frontend package.json currently
defines the "test" script ("test": "jasmine") and lists jasmine and
`@types/jasmine` in devDependencies though those tests are backend specs; remove
the "test" script and jasmine-related devDependencies from frontend/package.json
and add them into backend/package.json instead: add the "test": "jasmine" script
to backend/package.json and move jasmine and `@types/jasmine` into backend's
devDependencies so backend runs the Jasmine specs (refer to the "test" script
and the jasmine/@types/jasmine entries when updating the two package.json
files).

Comment thread frontend/package.json
"eslint-plugin-react": "^7.37.2",
"eslint-plugin-react-hooks": "^5.0.0",
"eslint-plugin-react-refresh": "^0.4.14",
"express": "^5.2.1",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if backend has its own package.json
fd -t f "package.json" backend/

# If it exists, check its dependencies
if [ -f backend/package.json ]; then
  echo "=== backend/package.json dependencies ==="
  cat backend/package.json | jq '.dependencies, .devDependencies'
fi

Repository: GitMetricsLab/github_tracker

Length of output: 393


🏁 Script executed:

cat -n frontend/package.json

Repository: GitMetricsLab/github_tracker

Length of output: 2227


Remove backend dependencies from frontend package.json devDependencies.

The following backend runtime dependencies are misplaced in frontend/package.json and should not appear there at all: express, mongoose, express-session, passport, passport-local, bcryptjs, and supertest. These packages already exist in backend/package.json where they belong. Their presence in the frontend package.json will:

  • Unnecessarily bloat the frontend bundle
  • Create confusion in dependency management
  • Violate the separation of concerns established by the project structure

Remove lines 49, 50, 53-55 (and bcryptjs on line 44 and supertest on line 56) from devDependencies.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/package.json` at line 49, Remove the backend runtime packages
mistakenly declared in frontend's devDependencies: delete the entries for
"express", "mongoose", "express-session", "passport", "passport-local",
"bcryptjs", and "supertest" from frontend/package.json so only frontend-related
packages remain; locate the devDependencies block in frontend/package.json and
remove those package keys (ensure you don't touch backend/package.json where
these belong) and then run npm/yarn install to update lockfile.

Comment on lines +77 to 83
} catch (err: unknown) {
const githubError = err as GitHubApiError;

if (githubError.status === 403) {
setError('GitHub API rate limit exceeded. Please wait or use a token.');
setRateLimited(true); // Prevent further fetches
} else {
Copy link
Copy Markdown
Contributor

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

Rate-limit state can permanently lock out further fetch attempts.

After Line 82 sets rateLimited to true, the guard at Line 62 prevents all future requests with no recovery path in this hook instance.

♻️ Proposed fix
-      if (!octokit || !username || rateLimited) return;
+      if (!octokit || !username) return;

       setLoading(true);
       setError('');

       try {
         const [issueRes, prRes] = await Promise.all([
           fetchPaginated(octokit, username, 'issue', page, perPage),
           fetchPaginated(octokit, username, 'pr', page, perPage),
         ]);

+        setRateLimited(false);
         setIssues(issueRes.items);
         setPrs(prRes.items);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/hooks/useGitHubData.ts` around lines 77 - 83, The hook
useGitHubData currently sets rateLimited to true on a 403 and the existing guard
then blocks all future fetches with no recovery; modify the 403 handling to
parse a Retry-After header or X-RateLimit-Reset (or fall back to a sensible
default like 60s), call setRateLimited(true) but schedule a timer to call
setRateLimited(false) after that delay, and ensure the timer is stored in a ref
and cleared on unmount or when a new rate-limit event occurs; this uses the
existing symbols rateLimited, setRateLimited, and the 403 catch branch so the
guard that prevents fetches will automatically resume after the timeout.

Comment on lines +36 to +38
if (response.data.message === "User created successfully") {
navigate("/login");
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Avoid redirect logic tied to response text.

Routing on an exact message string is brittle. Prefer status-code (or explicit boolean) checks.

Suggested patch
-      if (response.data.message === "User created successfully") {
+      if (response.status === 201) {
         navigate("/login");
       }
📝 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
if (response.data.message === "User created successfully") {
navigate("/login");
}
if (response.status === 201) {
navigate("/login");
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/pages/Signup/Signup.tsx` around lines 36 - 38, The redirect
currently depends on response.data.message string match; change the check to use
an explicit status or boolean from the API (e.g., response.status === 201 or
response.data.success === true) before calling navigate("/login") in the signup
submit handler (the block that currently inspects response.data.message and
calls navigate). Update the API contract usage to prefer response.status or
response.data.success and handle non-success cases accordingly.

Comment on lines +160 to +164
useEffect(() => {
if (username) {
fetchData(username, page + 1, ROWS_PER_PAGE);
}
}, [fetchData, page, tab, username]);
Copy link
Copy Markdown
Contributor

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

Auto-fetch effect triggers API calls on every username keystroke.

Because this effect depends on username (and tab), each edit in the input can trigger network requests before form submit, which can quickly hit rate limits.

✅ Suggested direction
+ const [submittedUsername, setSubmittedUsername] = useState("");

  useEffect(() => {
-   if (username) {
-     fetchData(username, page + 1, ROWS_PER_PAGE);
+   if (submittedUsername) {
+     fetchData(submittedUsername, page + 1, ROWS_PER_PAGE);
    }
- }, [fetchData, page, tab, username]);
+ }, [fetchData, page, submittedUsername]);

  const handleSubmit = async (
    e: React.FormEvent<HTMLFormElement>,
  ): Promise<void> => {
    e.preventDefault();
    setPage(0);
+   const normalized = username.trim();
+   setSubmittedUsername(normalized);
-   await saveLookupHistory(username);
-   await fetchData(username, 1, ROWS_PER_PAGE);
+   await saveLookupHistory(normalized);
+   await fetchData(normalized, 1, ROWS_PER_PAGE);
  };
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/pages/Tracker/Tracker.tsx` around lines 160 - 164, The effect
currently re-runs on every username (and tab) change causing API calls on each
keystroke; change it to only run for deliberate fetches by introducing a stable
"submittedUsername" state (e.g., submittedUsername) that is set in the form
submit handler instead of using raw username, then update the effect to depend
on submittedUsername and page (and not username/tab) and call
fetchData(submittedUsername, page + 1, ROWS_PER_PAGE); alternatively implement a
debounce that sets submittedUsername after a short pause—update handlers that
trigger fetches to set submittedUsername so fetches only occur on
submit/debounced value, not on every keystroke.

Comment on lines +192 to +193
const matchesStart = !startDate || createdAt >= new Date(startDate);
const matchesEnd = !endDate || createdAt <= new Date(endDate);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

End-date filtering is currently exclusive for most of the selected day.

new Date(endDate) resolves to midnight, so items created later on the same end date are filtered out.

🗓️ Proposed fix
-      const matchesEnd = !endDate || createdAt <= new Date(endDate);
+      const endBoundary = endDate
+        ? new Date(`${endDate}T23:59:59.999`)
+        : null;
+      const matchesEnd = !endBoundary || createdAt <= endBoundary;
📝 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 matchesStart = !startDate || createdAt >= new Date(startDate);
const matchesEnd = !endDate || createdAt <= new Date(endDate);
const matchesStart = !startDate || createdAt >= new Date(startDate);
const endBoundary = endDate
? new Date(`${endDate}T23:59:59.999`)
: null;
const matchesEnd = !endBoundary || createdAt <= endBoundary;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/pages/Tracker/Tracker.tsx` around lines 192 - 193, The end-date
check in matchesEnd uses new Date(endDate) which is midnight and thus excludes
items later that day; update the logic to compare createdAt against the
end-of-day timestamp (e.g., compute an endOfDay from endDate by setting hours to
23:59:59.999 or by creating nextDay = new Date(endDate) + 1 day and using
createdAt < nextDay) so matchesEnd becomes true for any createdAt on the
selected endDate; keep matchesStart as-is using startDate and createdAt.

Comment thread README.md
Comment on lines +92 to +96
```
MONGO_URI=mongodb+srv://alokhacs222729_db_user:IvORbhhzQg71OF2q@cluster0.gevcwty.mongodb.net/?appName=Cluster0
PORT=5000
SESSION_SECRET=your_session_secret_key_here
```
Copy link
Copy Markdown
Contributor

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

Remove hardcoded MongoDB credentials from documentation immediately.

Line 93 exposes a full connection string with embedded credentials. This must be replaced with placeholders, and the exposed credentials should be rotated/revoked.

🔒 Proposed fix
-MONGO_URI=mongodb+srv://alokhacs222729_db_user:IvORbhhzQg71OF2q@cluster0.gevcwty.mongodb.net/?appName=Cluster0
+MONGO_URI=mongodb+srv://<db_user>:<db_password>@cluster0.gevcwty.mongodb.net/<db_name>?retryWrites=true&w=majority
 PORT=5000
 SESSION_SECRET=your_session_secret_key_here
🧰 Tools
🪛 Betterleaks (1.2.0)

[high] 93-93: Detected a MongoDB connection string with embedded credentials, potentially exposing direct database access and sensitive application data.

(mongodb-connection-string)

🪛 markdownlint-cli2 (0.22.1)

[warning] 92-92: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@README.md` around lines 92 - 96, The README currently contains a hardcoded
MongoDB connection string (MONGO_URI) with embedded credentials; replace that
value with a placeholder (e.g.,
MONGO_URI=mongodb+srv://<DB_USER>:<DB_PASS>@<HOST>/<DB_NAME>?retryWrites=true&w=majority)
and update the example block so no real secrets appear, and add a short note to
rotate/revoke the exposed credentials immediately; locate the example using the
MONGO_URI token and update it accordingly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant