feat(product): 구매자 매장 상품 목록·카테고리 조회 API#158
Conversation
- storeProducts(input): 활성 상품(+활성 매장)만, 카테고리/매장내 검색(상품명·태그)/커서 페이지네이션. 대표 이미지 thumbnail + 할인율 계산 - storeProductCategories(storeId): 매장 보유 활성 상품의 카테고리만(빈 카테고리 제외) + productCount + sort_order 정렬 - product feature에 구매자 조회 레이어 신설(resolver/service/mapper/dto/types/constants), ProductRepository에 listActiveProductsByStore·listStoreProductCategories 추가 - 개인화 없는 public 쿼리. 단위(mapper)·통합(service/resolver) 테스트 19건
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
🧹 knip — dead-code 리포트전체 리포트
|
🩺 NestJS Doctor — 89/100 (Good)진단 259건 (error 0).
architecture / security 상위 항목
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 703b5ae235
ℹ️ 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".
| by: ['category_id'], | ||
| where: { | ||
| deleted_at: null, | ||
| product: { store_id: storeId, is_active: true, deleted_at: null }, |
There was a problem hiding this comment.
Filter category list by active store
For an inactive or soft-deleted store that still has active products, this relation filter only checks the product itself, so the public storeProductCategories query still returns category names and productCount. That makes the sidebar inconsistent with storeProducts (which already requires store: { is_active: true, deleted_at: null }) and exposes catalog metadata for stores the buyer-facing store detail hides; include the same store active/deleted predicate here.
Useful? React with 👍 / 👎.
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
Coverage report
Test suite run success1386 tests passing in 165 suites. Report generated by 🧪jest coverage report action from b778b39 |
비활성/삭제 매장이 활성 상품을 보유하면 storeProductCategories가 카테고리·productCount를 노출하던 불일치를 수정한다. groupBy 필터에 store active/deleted 술어를 추가해 storeProducts와 가시성을 일치시킨다. (Codex P2 반영)
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 24db098bc6
ℹ️ 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".
| where: { deleted_at: null }, | ||
| select: { category_id: true }, |
There was a problem hiding this comment.
Filter product categories by visible categories
When a category is deactivated or soft-deleted while its product_category rows remain, this selection still returns that hidden category in categoryIds, even though storeProductCategories filters categories by is_active and deleted_at before rendering the sidebar. That makes the public product response inconsistent with the category list the frontend groups against; add the same category active/deleted predicate to this relation selection (and the categoryId relation filter above).
Useful? React with 👍 / 👎.
storeProductCategories는 카테고리를 is_active/deleted_at로 거르는데, storeProducts의 categoryIds와 categoryId 필터는 비활성/삭제 카테고리를 포함해 사이드바와 불일치했다. listActiveProductsByStore의 categoryId 필터와 product_categories select에 category active/deleted 술어를 추가한다. (Codex P2 :778 반영)
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e7efcdfd93
ℹ️ 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".
| product_tags: { | ||
| some: { | ||
| deleted_at: null, | ||
| tag: { name: { contains: args.search } }, |
There was a problem hiding this comment.
Exclude soft-deleted tags from storefront search
When a storeProducts search matches through tags, this nested predicate only requires the product_tags row to be active; if the referenced tag has been soft-deleted, products still surface for that hidden tag name because the soft-delete extension does not inject filters into nested relation predicates. Add deleted_at: null to the tag condition so buyer-facing searches don't use removed tags.
Useful? React with 👍 / 👎.
search가 태그로 매칭될 때 tag.deleted_at을 확인하지 않아 삭제된 태그명으로도 상품이 검색되던 문제를 수정한다. product_tags.some.tag 조건에 deleted_at: null을 추가한다. (Codex P2 :759 반영)
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6ea5913ce5
ℹ️ 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".
| ...(args.cursor ? { id: { lt: args.cursor } } : {}), | ||
| ...(args.categoryId |
There was a problem hiding this comment.
Preserve zero-valued ID filters
When a client supplies categoryId: "0" (or cursor: "0"), parseId returns 0n, but these truthiness checks drop the corresponding filter before querying Prisma. That makes an invalid category filter behave like no filter and returns the store's whole product list (and a zero cursor restarts pagination), whereas passing the parsed value or rejecting non-positive IDs would return no rows/400.
Useful? React with 👍 / 👎.
parseId("0")=0n이 args.cursor/args.categoryId의 truthiness 체크에서 falsy로 떨어져, 잘못된 categoryId가 전체 목록을 반환하고 zero cursor가 페이지를 리셋하던 문제를 수정한다. 0n도 유효 인자로 다루도록 !== undefined로 분기한다. (Codex P2 :740 반영)
Summary
구매자 매장 상품 탭 조회 API를 신설한다. 매장 상세 화면의 상품 영역(좌측 카테고리 사이드바 + 카테고리별 상품 카드 + 매장 내 검색)을 담당한다. store-detail 도메인 작업의 2단계.
Scope
storeProducts(input: StoreProductsInput!): StoreProductConnection!categoryId필터 /search(상품명·태그 부분일치) /cursor페이지네이션thumbnailUrl,discountRate(정가·할인가 기반 계산),categoryIds(FE 섹션 그룹핑용)storeProductCategories(storeId: ID!): [StoreProductCategory!]!productCount+sortOrder정렬ProductRepository에listActiveProductsByStore·listStoreProductCategories추가CategoryTypeenum을 SDL에 정의(기존 Prisma enum이나 GraphQL 미노출이었음)진행 상황
storeDetail은 머지 완료, 다음 PR3 후기 탭)storeProduct)는 store-detail spec에 화면이 없어 제외(별도 figma) — 합의된 Q1Impact
Test plan
yarn validate전체 통과: 165 suites / 1381 tests, lint·tsc·dto:check·arch:check 통과, 커버리지 임계 충족