refactor(product): 상품 카드 조립 5벌 → 공용 매퍼 1벌, 필드명 통일 - #343
Conversation
같은 상품이 화면마다 다른 코드로 조립되고 있었다. 대표 이미지 선택(sort_order
최소 1건)·할인율 산식·지역 표기가 5곳에 복제돼 있어, 한 곳만 고치면 같은 상품이
화면별로 다른 가격표를 달게 된다.
- `toProductCardCore(id, product)` 신설(product feature). 카드 공통 9필드
(id·storeId·name·thumbnailUrl·storeName·regionLabel·regularPrice·salePrice·
discountRate)를 한 곳에서 만든다. 조인 행(찜·최근 본 상품)은 상품 id가
`product_id`로 한 단계 바깥에 있어 id를 따로 받는다.
- 호출부 5곳으로 교체: 홈 인기 케이크, 검색 결과, 찜 목록, 최근 본 상품 목록,
마이페이지 개요. 마지막 하나는 타입 통일 과정에서 컴파일러가 찾아낸 네 번째
복제본이다.
- 출력 타입은 `extends ProductCardCore`로 바꿔 필드 누락이 타입 오류가 되게 했다.
SDL: user feature의 두 카드 타입이 쓰던 별도 어휘를 상품 쪽 정본으로 맞췄다.
productId → id, productName → name, representativeImageUrl → thumbnailUrl.
RecentViewedProductSummary에는 storeId·discountRate·regionLabel이 새로 실린다 —
상세 URL이 /store/{storeId}/products/{id}라 storeId 없이는 이동이 막혔다.
recent_product_view select도 그만큼 넓혔다(같은 store 조인이라 쿼리 수는 그대로).
테스트: 매퍼 순수 단위 spec 8건(id 변환·"0" id·대표 이미지 없음·할인가 없음·
지역 표기 4분기) + 새 필드 회귀 1건.
5개 SDL 타입을 ProductCard 1타입으로 합치는 건 하지 않았다. GraphQL은 타입 간
필드 상속이 없어 한 타입으로 합치려면 화면마다 안 쓰는 필드
(ratingAverage·isWishlisted·rank)를 nullable로 풀거나 가짜 값을 채워야 한다 —
계약이 나빠진다. 중복의 실체는 조립 코드였고 그건 이 PR에서 사라졌다.
|
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: Advanced Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
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 |
🩺 NestJS Doctor — 89/100 (Good)진단 385건 (error 0).
architecture / security 상위 항목
|
🧹 knip — dead-code 리포트전체 리포트
|
Coverage report
Test suite run success2837 tests passing in 275 suites. Report generated by 🧪jest coverage report action from b9f50b3 |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
배경
같은 상품이 화면마다 다른 코드로 조립되고 있었다. 대표 이미지 선택(sort_order 최소 1건)·할인율 산식·지역 표기가 5곳에 복제돼 있어, 한 곳만 고치면 같은 상품이 화면별로 다른 가격표를 달게 된다.
변경
toProductCardCore(id, product)하나로 모았다. 카드 공통 9필드를 만든다.조인 행(찜·최근 본 상품)은 상품 id가
product_id로 한 단계 바깥에 있어 id를 따로 받는다.교체한 호출부 5곳:
product-home-mappers.helper.tsproduct-search-mappers.helper.tsuser-wishlist.service.tsuser-recent-view.service.tsuser-mypage.service.ts마지막 하나는 애초 계획에 없었다. 출력 타입을
extends ProductCardCore로 바꾸자 컴파일러가 찾아낸 네 번째 복제본이다. 타입을 통일해 두면 다음 복제도 같은 방식으로 잡힌다.SDL
user feature의 두 카드 타입만 별도 어휘를 쓰고 있었다. 상품 쪽 정본으로 맞췄다.
productIdidproductNamenamerepresentativeImageUrlthumbnailUrlRecentViewedProductSummary에storeId·discountRate·regionLabel이 새로 실린다. 상세 URL이/store/{storeId}/products/{id}인데 storeId가 없어 이동이 막혀 있었다.recent_product_viewselect를 그만큼 넓혔고, 같은store조인이라 쿼리 수는 그대로다.하지 않은 것 — SDL 타입 5개 → 1개
계획(Phase 0 항목 12)은
PopularCake·SearchProduct·StoreProduct·WishlistItemSummary·RecentViewedProductSummary를ProductCard1타입으로 합치는 것이었다. 하지 않았다.GraphQL은 타입 간 필드 상속이 없다(인터페이스도 구현 타입에서 전부 재선언해야 한다). 한 타입으로 합치려면 화면마다 안 쓰는 필드를 이렇게 처리해야 한다.
ratingAverage·reviewCount— 홈 인기·최근 본 상품은 집계하지 않는다 → nullable로 풀거나 0을 채운다isWishlisted— 홈 인기·검색 비로그인은 판정하지 않는다 → 같은 문제rank— 인기 목록에만 있다 → nullableStoreProduct의description·currency·categoryIds— 다른 4곳엔 없다계약이 나빠진다. 중복의 실체는 SDL 타입 수가 아니라 조립 코드였고, 그건 이 PR에서 사라졌다. TypeScript 쪽은
extends ProductCardCore로 이미 단일 소스다.테스트
product-card.helper.spec.ts순수 단위 8건 — id 변환,"0"id(조인 행에서 실제로 나온다), 대표 이미지 없음, 할인가 없음, 지역 표기 4분기.yarn validate그린 — 275 suites / 2,837 tests.FE-BREAKING
있음. 찜 목록·최근 본 상품·마이페이지 개요를 쓰는 화면이 전부 영향받는다.