Skip to content

fix(wishlist): scope wishlist to the authenticated user#525

Open
sricharan12-hub wants to merge 1 commit into
niharika-mente:mainfrom
sricharan12-hub:fix/wishlist-per-user
Open

fix(wishlist): scope wishlist to the authenticated user#525
sricharan12-hub wants to merge 1 commit into
niharika-mente:mainfrom
sricharan12-hub:fix/wishlist-per-user

Conversation

@sricharan12-hub

Copy link
Copy Markdown
Contributor

Summary

Fixes #508 — the wishlist was shared globally across every user.

getWishlist, addToWishlist, and removeFromWishlist all ran an unbounded Wishlist.findOne(), so there was a single wishlist document for the whole platform. If User A added a product, User B saw it too — a data-integrity and privacy failure.

Root cause

Two problems compounded each other:

  1. The Wishlist model had no user field, so wishlists couldn't be distinguished per user.
  2. The wishlist routes had no authentication (// ✅ No authentication middleware), so req.user didn't even exist — the suggested findOne({ userId: req.user._id }) fix couldn't work as-is.

Changes

  • Model (Wishlist.model.js): added a user reference that is required and unique, guaranteeing exactly one wishlist per user.
  • Routes (wishlist.route.js): applied the existing protect middleware (same pattern as orders/returns) to all three routes.
  • Controller (WishlistController.controller.js):
    • Every query is now scoped to req.user._id.
    • add/remove use atomic findOneAndUpdate with upsert + $addToSet / $pull — lazy-creates the wishlist, prevents duplicate entries, and avoids create races.
    • Validates productId400 for missing/invalid ids, 404 for unknown products.

The frontend already sends the auth token on every request (shared axios interceptor), so the logged-in UI is unaffected; logged-out requests now correctly receive 401 instead of a shared wishlist.

Tests

New tests/wishlist.test.js (supertest + mongodb-memory-server) — 15/15 passing, covering authentication, validation, de-duplication, graceful no-op removal, and most importantly cross-user isolation (User A's wishlist is invisible to User B; one user's removal never affects another).

Coverage on the new logic: 89.28% controller / 100% model statements — above the 80% requirement.

Note: the backend has no lint script and the repo's root ESLint config is missing its dependency (@eslint/js) in this environment, so npm run lint can't run here; the change follows existing style and passes node --check.

Closes #508

The wishlist controller used an unbounded Wishlist.findOne(), so every
user shared a single global wishlist — User A's additions were visible
to User B, a data-integrity and privacy bug (niharika-mente#508).

- Add a required, unique `user` reference to the Wishlist model so each
  user has exactly one wishlist
- Require authentication (protect) on all wishlist routes; these were
  previously unauthenticated, so req.user did not exist
- Scope every query to req.user._id and use atomic findOneAndUpdate with
  upsert + $addToSet / $pull (lazy create, no duplicates, no races)
- Validate productId (400 on missing/invalid, 404 on unknown product)
- Add tests covering auth, validation, de-duplication and cross-user
  isolation (89% controller / 100% model statement coverage)

Closes niharika-mente#508
@vercel

vercel Bot commented Jun 28, 2026

Copy link
Copy Markdown

@sricharan12-hub is attempting to deploy a commit to the niharika-mente's projects Team on Vercel.

A member of the Team first needs to authorize it.

@Aamod007 Aamod007 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM

@Aamod007 Aamod007 self-requested a review July 2, 2026 17:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Backend: Wishlist controller shares a single global wishlist across all users

2 participants