Skip to content

feat(user): 찜 토글 + isWishlisted 노출 + 카운트 일관성 수정#80

Merged
chanwoo7 merged 2 commits intodevelopfrom
feat/mypage-figma-wishlist-toggle
Apr 29, 2026
Merged

feat(user): 찜 토글 + isWishlisted 노출 + 카운트 일관성 수정#80
chanwoo7 merged 2 commits intodevelopfrom
feat/mypage-figma-wishlist-toggle

Conversation

@chanwoo7
Copy link
Copy Markdown
Member

@chanwoo7 chanwoo7 commented Apr 29, 2026

Summary

마이페이지 figma 02-main-login 명세의 '하트 버튼 클릭 시 찜 추가/해제' 정책을 백엔드에 도입.
mypage figma 정합화 플랜의 마지막 stage.

  • 신규 mutation: addToWishlist / removeFromWishlist (멱등, soft-delete 복원 포함)
  • 신규 query: myWishlist (페이지네이션 + 비활성/삭제 product 제외)
  • RecentViewedProductSummary.isWishlisted 매핑 (mypage / recent-view 모두)
  • 카운트 일관성 버그 수정: countWishlistItems / getViewerCounts.wishlistCount에 deleted_at: null 누락

변경 사항

SDL

  • 신규 user-wishlist.graphql
  • user-mypage.graphql RecentViewedProductSummary에 isWishlisted: Boolean! 추가

Service / Resolver

  • UserWishlistService 신규 (UserBaseService 상속, requireActiveUser 활용)
  • UserWishlistMutationResolver / UserWishlistQueryResolver 신규
  • user-mypage / user-recent-view 매핑에 isWishlisted 계산
  • ProductRepository.existsActiveProduct: 가벼운 active+soft-delete 검증 헬퍼

Repository

  • upsertWishlistItem (멱등 추가, soft-delete 복원)
  • softDeleteWishlistItem (멱등 해제)
  • findWishlistedProductIds (단일 IN 쿼리, N+1 회피)
  • findWishlistItems (목록 + 비활성/삭제 product 제외)

카운트 일관성 수정

  • getViewerCounts.wishlistCount, countWishlistItems에 deleted_at: null 필터 누락 → 수정
  • 기존 mypage.spec의 wishlistCount=2 (soft-delete 1 제외) 케이스가 비로소 정확히 검증됨

회귀 테스트

  • UserWishlistService spec 15건 (add/remove 각 멱등/존재/비활성/store inactive, list 페이지네이션/제외)
  • UserWishlistResolver spec 2건 (NotFound 전파 / 추가→목록→해제 시나리오)
  • mypage spec: recentViewedProducts.isWishlisted 매핑 검증 보강
  • recent-view spec: list isWishlisted 매핑 검증 추가

Breaking 여부

  • ⚠️ 약한 Breaking: RecentViewedProductSummary에 non-null isWishlisted 추가
    • GraphQL 특성상 모르는 필드 무시되므로 사실상 무영향
  • 마이그레이션: 없음 (WishlistItem 모델 / 인덱스 모두 기존 스키마 유지)

Test plan

  • 로컬 yarn test:cov 통과 (866 tests, +20)
  • CI check 통과
  • CI coverage-report 통과
  • CodeQL 통과

마이페이지 figma 02-main-login의 찜 기능을 백엔드에 도입한다.
하트 버튼 클릭 시 추가/해제하는 멱등 mutation과 목록 조회, 그리고
최근 본 상품에 isWishlisted 매핑까지 함께 반영한다.

## 변경 사항

- SDL 신규: user-wishlist.graphql (myWishlist / addToWishlist / removeFromWishlist)
- SDL 갱신: RecentViewedProductSummary.isWishlisted: Boolean!
- 신규 service: UserWishlistService (UserBaseService 상속)
- 신규 resolver: UserWishlistQueryResolver / UserWishlistMutationResolver
- UserRepository: upsertWishlistItem / softDeleteWishlistItem /
  findWishlistedProductIds (단일 IN 쿼리, N+1 회피) / findWishlistItems
- ProductRepository: existsActiveProduct (active+soft-delete 검증, 재사용 가능한 가벼운 헬퍼)
- 카운트 일관성 버그 수정: countWishlistItems / getViewerCounts.wishlistCount에
  deleted_at: null 필터 누락 → soft-delete된 위시리스트도 카운트에 포함되던 문제 수정
- user-mypage.service / user-recent-view.service: 매핑 시 isWishlisted 계산
  (findWishlistedProductIds set으로 일괄 조회, N+1 회피)
- 회귀 테스트 다수
  - UserWishlistService spec 15건
  - UserWishlistResolver spec 2건 (NotFound 전파 / 추가→목록→해제 시나리오)
  - mypage spec: recentViewedProducts.isWishlisted 매핑 검증 보강
  - recent-view spec: list isWishlisted 매핑 검증 추가
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 29, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: c2b937b5-e376-4714-8a8c-245d5410e4fa

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/mypage-figma-wishlist-toggle

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.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 29, 2026

Coverage report

St.
Category Percentage Covered / Total
🟢 Statements 96.69% 2894/2993
🟢 Branches 86.5% 1647/1904
🟢 Functions 93.32% 615/659
🟢 Lines 97.02% 2638/2719

Test suite run success

867 tests passing in 77 suites.

Report generated by 🧪jest coverage report action from 02be4b2

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 29, 2026

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9a0f2d75af

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

async countWishlistItems(accountId: bigint): Promise<number> {
return this.prisma.wishlistItem.count({
where: { account_id: accountId },
where: { account_id: accountId, deleted_at: null },
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Match wishlist count filter to myWishlist visibility

countWishlistItems now excludes soft-deleted rows, but it still counts wishlist rows whose products/stores are inactive or soft-deleted, while findWishlistItems explicitly filters those out (product.is_active, product.deleted_at, store.is_active, store.deleted_at). If a user wishlist entry survives but the product/store is later deactivated, myPageOverview.counts.wishlistCount can be greater than myWishlist.totalCount, creating inconsistent badges vs. list contents in production.

Useful? React with 👍 / 👎.

countWishlistItems / getViewerCounts.wishlistCount 가 wishlist soft-delete만
필터링하고 비활성/삭제 product/store에 연결된 row는 카운트에 포함하던 문제 수정.
findWishlistItems와 동일한 가시성 조건(product/store active+not-deleted)을 공유하도록
visibleWishlistWhere helper로 통일하여 카운트와 목록 길이가 항상 일치하도록 한다.

(Codex 리뷰 P2: count badge vs. list contents 불일치 회피)

- visibleWishlistWhere private helper 도입 (UserRepository)
- getViewerCounts.wishlistCount / countWishlistItems / findWishlistItems 모두 동일 helper 사용
- 회귀 테스트 1건: 4건 wishlist 중 inactive product / soft-delete product /
  inactive store 의 product 3건은 카운트에서 제외, visible 1건만 카운트
@chanwoo7 chanwoo7 merged commit 911dfec into develop Apr 29, 2026
9 checks passed
@chanwoo7 chanwoo7 deleted the feat/mypage-figma-wishlist-toggle branch April 29, 2026 16:48
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