Conversation
- storeDetail 쿼리 신설: 매장 헤더(이미지·평점·리뷰수·찜)·전화·주소·좌표·영업/휴무/안내문 노출. OptionalJwtAuthGuard로 비로그인 조회 + 로그인 시 isWishlisted - StoreImage 테이블 + Store.access_guide_text·regular_closure_text 컬럼 추가 (구매자 조회용, seller 입력 API는 차기) - 시드/스토어 팩토리 보강, 단위(mapper)·통합(service/resolver) 테스트 18건
store_image FK가 ON DELETE RESTRICT라 store 삭제 전 store_image를 정리하지 않으면 2회차 yarn prisma:seed가 FK 위반으로 실패한다. resetSeedScope에 storeImage.deleteMany를 추가해 멱등성을 보장한다. (Codex P2 반영)
feat(store): 구매자 매장 상세 조회(storeDetail)와 StoreImage 스키마 추가
- storeProducts(input): 활성 상품(+활성 매장)만, 카테고리/매장내 검색(상품명·태그)/커서 페이지네이션. 대표 이미지 thumbnail + 할인율 계산 - storeProductCategories(storeId): 매장 보유 활성 상품의 카테고리만(빈 카테고리 제외) + productCount + sort_order 정렬 - product feature에 구매자 조회 레이어 신설(resolver/service/mapper/dto/types/constants), ProductRepository에 listActiveProductsByStore·listStoreProductCategories 추가 - 개인화 없는 public 쿼리. 단위(mapper)·통합(service/resolver) 테스트 19건
비활성/삭제 매장이 활성 상품을 보유하면 storeProductCategories가 카테고리·productCount를 노출하던 불일치를 수정한다. groupBy 필터에 store active/deleted 술어를 추가해 storeProducts와 가시성을 일치시킨다. (Codex P2 반영)
- storeReviews(input): 매장 공개 리뷰 목록(최신순·커서), totalCount(후기 탭 카운트), media·작성자 닉네임·연결 상품명(주문 스냅샷) - 리뷰 좋아요 수 집계 + isLiked(OptionalJwtAuthGuard, 비로그인 false) - 매장 공개 리뷰 조회를 store feature가 소유(StoreReviewRepository 신설). user의 ReviewRepository(본인 리뷰 작성/관리)와 책임 분리, cross-feature 경계 준수 - 단위(mapper)·통합(service/resolver) 테스트 11건
비활성/삭제 매장의 store_id를 알면 storeReviews로 리뷰 내용·미디어·totalCount가 노출되던 문제를 수정한다. listStoreReviews·countStoreReviews where에 store active/deleted 술어를 추가해 storeDetail의 가드와 일치시킨다. (Codex P2 반영)
storeProductCategories는 카테고리를 is_active/deleted_at로 거르는데, storeProducts의 categoryIds와 categoryId 필터는 비활성/삭제 카테고리를 포함해 사이드바와 불일치했다. listActiveProductsByStore의 categoryId 필터와 product_categories select에 category active/deleted 술어를 추가한다. (Codex P2 :778 반영)
탈퇴(soft-delete) 시 nickname이 deleted_<id>로 덮어써지는데, soft-delete extension은 nested user_profile에 deleted_at을 주입하지 않아 storeReviews가 deleted_<id>를 그대로 노출했다. user_profile.deleted_at을 함께 select하고 매퍼에서 탈퇴 프로필은 authorNickname=null로 익명화한다. (Codex P2 :55 반영)
search가 태그로 매칭될 때 tag.deleted_at을 확인하지 않아 삭제된 태그명으로도 상품이 검색되던 문제를 수정한다. product_tags.some.tag 조건에 deleted_at: null을 추가한다. (Codex P2 :759 반영)
feat(store): 구매자 매장 후기 목록 조회(storeReviews)와 좋아요 집계
parseId("0")=0n이 args.cursor/args.categoryId의 truthiness 체크에서 falsy로 떨어져, 잘못된 categoryId가 전체 목록을 반환하고 zero cursor가 페이지를 리셋하던 문제를 수정한다. 0n도 유효 인자로 다루도록 !== undefined로 분기한다. (Codex P2 :740 반영)
storeProducts(#158)와 동일하게 parseId("0")=0n이 args.cursor truthiness 체크에서 falsy로 떨어져 zero cursor가 페이지를 리셋하던 문제를 수정한다. listStoreReviews의 cursor 분기를 !== undefined로 바꾼다.
feat(product): 구매자 매장 상품 목록·카테고리 조회 API
fix(store): storeReviews의 0 값 cursor 보존
🧹 knip — dead-code 리포트전체 리포트
|
🩺 NestJS Doctor — 89/100 (Good)진단 259건 (error 0).
architecture / security 상위 항목
|
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
|
Warning Review limit reached
More reviews will be available in 9 minutes and 49 seconds. Learn how PR review limits work. Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file). ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits. 🚦 How do rate limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (8)
📝 WalkthroughWalkthrough
Changes스토어프론트 API 구현
Sequence Diagram(s)sequenceDiagram
participant Client
participant Resolver as StoreDetailQueryResolver
participant Service as StoreDetailService
participant StoreRepo as StoreRepository
participant WishlistRepo as StoreWishlistRepository
rect rgba(59, 130, 246, 0.5)
note over Client,WishlistRepo: storeDetail 쿼리 (OptionalJwtAuth)
Client->>Resolver: storeDetail(storeId, JwtUser?)
Resolver->>Service: storeDetail(storeId, accountId?)
Service->>StoreRepo: findStoreDetailById(storeId)
StoreRepo-->>Service: StoreDetailRow (store_images 포함)
Service->>Service: NotFoundException if null
par 병렬 조회
Service->>StoreRepo: aggregateReviewStats(storeId)
Service->>WishlistRepo: findWishlistedStoreIds(accountId?)
end
Service-->>Resolver: toStoreDetail(row, reviewStat, isWishlisted)
Resolver-->>Client: StoreDetail
end
sequenceDiagram
participant Client
participant Resolver as StoreReviewQueryResolver
participant Service as StoreReviewService
participant Repo as StoreReviewRepository
rect rgba(16, 185, 129, 0.5)
note over Client,Repo: storeReviews 쿼리 (OptionalJwtAuth, 커서 기반)
Client->>Resolver: storeReviews(input, JwtUser?)
Resolver->>Service: storeReviews(input, accountId?)
par 병렬 조회
Service->>Repo: listStoreReviews(storeId, limit+1, cursor?)
Service->>Repo: countStoreReviews(storeId)
end
Service->>Repo: aggregateLikeCounts(reviewIds)
Service->>Repo: findLikedReviewIds(reviewIds, accountId) if 로그인
Service-->>Resolver: StoreReviewConnection (items, totalCount, hasMore, nextCursor)
Resolver-->>Client: StoreReviewConnection
end
Estimated code review effort🎯 5 (Critical) | ⏱️ ~100 minutes 🚥 Pre-merge checks | ✅ 3 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ 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 |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 93882a4f88
ℹ️ 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".
|
|
||
| created_at DateTime @default(now()) @db.DateTime(3) | ||
| updated_at DateTime @updatedAt @db.DateTime(3) | ||
| deleted_at DateTime? @db.DateTime(3) |
There was a problem hiding this comment.
Register StoreImage with soft-delete filtering
This new soft-deletable model is not added to SOFT_DELETE_MODELS in src/prisma/soft-delete.middleware.ts, so any direct prisma.storeImage.findMany/findFirst/count read will not get the repository-wide deleted_at: null filter that other soft-deletable tables rely on. The current detail query filters nested images manually, but the first direct StoreImage read can return or count deleted carousel images unless StoreImage is registered there.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Actionable comments posted: 7
🧹 Nitpick comments (5)
src/features/store/resolvers/store-review-query.resolver.spec.ts (1)
56-84: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win잘못된
accountId예외 경로도 한 케이스는 잡아두는 게 좋습니다.이번 resolver는
src/global/auth/parse-account-id.ts:5-23를 직접 호출하므로, 빈 문자열·음수·비숫자accountId에서BadRequestException이 나는지 검증하는 테스트가 있어야 주요 분기가 닫힙니다.As per path instructions,
src/**/*.spec.ts: 테스트는 시간/uuid/네트워크/DB 의존성을 mock 또는 stub으로 통제하는지, 정상 흐름뿐 아니라 주요 예외/분기 케이스가 포함되는지 확인하세요.🤖 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 `@src/features/store/resolvers/store-review-query.resolver.spec.ts` around lines 56 - 84, Add a test case in store-review-query.resolver.spec.ts that covers the invalid accountId path used by storeReviews, since it calls parseAccountId directly. Verify that empty string, negative, or non-numeric accountId inputs trigger BadRequestException, alongside the existing login/unlogin happy-path tests. Use the resolver.storeReviews and parseAccountId flow to locate the branch and keep the test deterministic with mocked/stubbed inputs.Source: Path instructions
src/features/store/services/store-review.service.spec.ts (1)
173-181: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win삭제 매장 분기는 아직 검증되지 않습니다.
테스트 이름은
비활성/삭제 매장인데 현재는is_active: false만 확인합니다.deleted_at필터는 별도 조건이라서, 삭제된 매장만 세팅한 케이스를 하나 더 추가해야 이 분기 회귀를 잡을 수 있습니다.As per path instructions,
src/**/*.spec.ts: 테스트는 시간/uuid/네트워크/DB 의존성을 mock 또는 stub으로 통제하는지, 정상 흐름뿐 아니라 주요 예외/분기 케이스가 포함되는지 확인하세요.🤖 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 `@src/features/store/services/store-review.service.spec.ts` around lines 173 - 181, 현재 `storeReviews` 스펙의 “비활성/삭제 매장” 테스트는 `is_active`만 검증하고 있어 `deleted_at` 분기를 놓치고 있습니다. `storeReviews`와 `createStore`/`makeReview`를 사용하는 같은 테스트 파일에 삭제된 매장만 대상으로 하는 케이스를 추가해, `deleted_at`이 설정된 매장에서도 `items`가 비고 `totalCount`가 0인지 확인하세요. 기존 비활성 매장 케이스와 분리해 `is_active`/`deleted_at` 각각의 필터 분기를 모두 커버하도록 유지하세요.Source: Path instructions
src/features/product/resolvers/product-storefront-query.resolver.spec.ts (1)
19-69: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift이 spec은 real DB 통합 대신 resolver 단위로 고립하는 편이 맞습니다.
현재는
createTestingModuleWithRealDb와 직접 Prisma write로 DB 의존성을 그대로 끌고 오면서 happy path만 확인하고 있습니다.ProductStorefrontQueryResolver가 얇은 위임 계층인 만큼, 이 파일은ProductStorefrontService를 mock/stub 해서 인자 전달과 서비스 예외 전파를 검증하고, real DB 경로는 별도 integration/e2e 성격의 테스트로 분리하는 편이 더 안정적입니다. As per path instructions,src/**/*.spec.ts: "테스트는 시간/uuid/네트워크/DB 의존성을 mock 또는 stub으로 통제하는지, 정상 흐름뿐 아니라 주요 예외/분기 케이스가 포함되는지 확인하세요."🤖 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 `@src/features/product/resolvers/product-storefront-query.resolver.spec.ts` around lines 19 - 69, This spec is doing real DB integration work instead of isolating the resolver; refactor ProductStorefrontQueryResolver tests to mock or stub ProductStorefrontService and keep ProductRepository/Prisma out of this unit spec. Update the resolver setup in beforeAll to use a testing module with a mocked ProductStorefrontService, then verify storeProducts and storeProductCategories only pass the correct arguments and return the mocked result. Add at least one case for service error propagation so the resolver’s thin delegation behavior is covered without relying on createTestingModuleWithRealDb, createStore, or direct prisma writes.Source: Path instructions
src/features/store/services/store-detail.service.spec.ts (1)
22-37: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift
*.spec.ts에서 실DB 의존성을 분리해 주세요.Line 23-36은
createTestingModuleWithRealDb,PrismaClient,truncateAll에 직접 기대고 있어서 이 스펙이 DB 상태와 실행 환경에 묶입니다. 이 경로는 Repository를 mock/stub한 단위 스펙으로 두고, 실DB 검증은 별도 통합/e2e 테스트로 분리하는 편이 현재 규칙에 맞습니다. As per path instructions,src/**/*.spec.ts: 테스트는 시간/uuid/네트워크/DB 의존성을 mock 또는 stub으로 통제하는지 확인하세요.🤖 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 `@src/features/store/services/store-detail.service.spec.ts` around lines 22 - 37, This spec is coupled to the real database through createTestingModuleWithRealDb, PrismaClient, and truncateAll; refactor StoreDetailService.spec.ts into a pure unit test by mocking/stubbing StoreRepository and StoreWishlistRepository in the testing module setup and removing any real DB lifecycle calls from beforeAll/beforeEach/afterAll. Keep StoreDetailService as the system under test, and move any database-backed verification into a separate integration/e2e test file so this *.spec.ts no longer depends on external state or environment.Source: Path instructions
src/features/store/resolvers/store-detail-query.resolver.spec.ts (1)
25-45: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift리졸버 스펙도 실DB 대신 mock/stub으로 고정하는 편이 좋겠습니다.
Line 26-35의 real DB 부트스트랩 때문에 이 테스트가 리졸버 계약 검증보다 DB 통합 상태에 더 크게 의존합니다. 이 파일은 Service를 stub해서 리졸버의 인자 전달과 인증 분기만 검증하고, DB 경로는 별도 통합 테스트로 옮기는 구성이 규칙에 더 잘 맞습니다. As per path instructions,
src/**/*.spec.ts: 테스트는 시간/uuid/네트워크/DB 의존성을 mock 또는 stub으로 통제하는지 확인하세요.🤖 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 `@src/features/store/resolvers/store-detail-query.resolver.spec.ts` around lines 25 - 45, The resolver spec is bootstrapping a real database via createTestingModuleWithRealDb, which makes StoreDetailQueryResolver tests depend on DB state instead of just resolver behavior. Replace the real DB setup with a mocked/stubbed testing module by stubbing StoreDetailService and any repository dependencies used by the resolver, and keep the test focused on argument forwarding and auth branching in StoreDetailQueryResolver. Move any DB integration coverage for StoreRepository or StoreWishlistRepository into separate integration tests.Source: Path instructions
🤖 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 `@src/features/product/dto/inputs/store-products.input.ts`:
- Around line 4-17: `StoreProductsInput`의 ID 관련 필드 검증이 빈 문자열("")을 허용하고 있으므로,
`storeId`, `categoryId`, `cursor`가 DTO 단계에서 non-empty만 통과하도록 보강하세요.
`@IsString()`만 쓰는 대신 `IsNotEmpty` 같은 검증을 `StoreProductsInput`에 추가해
`categoryId`/`cursor`가 빈 값으로 들어와 서비스에서 누락값처럼 처리되지 않게 하고, `storeId`도 동일하게 빈 문자열을
차단하도록 수정하세요.
In `@src/features/product/services/product-storefront-mappers.helper.ts`:
- Around line 15-18: The discountRate calculation in the product storefront
mapper can return values above 100 when salePrice is negative, so clamp the
result to the 0–100 range in the mapping logic. Update the discount computation
in product-storefront-mappers.helper.ts so the function that derives
discountRate from salePrice and regularPrice treats invalid or negative
salePrice values safely (for example by normalizing them before calculation or
clamping the final percentage), while keeping the existing zero fallback for
null, non-positive, or inverted prices.
In `@src/features/product/services/product-storefront.service.spec.ts`:
- Around line 33-48: This spec is relying on a real database via
createTestingModuleWithRealDb, truncateAll, and direct Prisma cleanup, but it
should be a unit test controlled with stubs/mocks. Replace the real-db setup in
product-storefront.service.spec.ts by mocking ProductRepository (and any
Prisma-backed behavior) when creating the module for ProductStorefrontService,
and remove the truncate/disconnect lifecycle tied to the actual DB. Keep real
database verification in separate integration/e2e coverage.
- Around line 337-354: 테스트명이 “비활성/삭제 매장” 분기를 모두 검증하는 것처럼 보이지만, 현재
`storeProductCategories` 테스트는 `is_active: false`만 확인하고 `deleted_at` 조건은 전혀 검증하지
않습니다. `storeProductCategories`가 의존하는 `store: { is_active: true, deleted_at: null
}` 분기를 정확히 커버하도록 이 케이스를 둘로 분리하고, 하나는 `is_active: false` 매장, 다른 하나는 `deleted_at`이
설정된 매장으로 만들어 각각 `service.storeProductCategories` 결과가 빈 배열인지 확인하세요.
In `@src/features/store/resolvers/store-review-query.resolver.spec.ts`:
- Around line 25-44: This resolver spec is still tied to the real database
through createTestingModuleWithRealDb and truncate/connection cleanup, so
refactor it to a mock-based unit test. Update StoreReviewQueryResolver spec
setup to use a normal testing module with mocked
StoreReviewService/StoreReviewRepository (and any guard/user dependencies if
present), remove truncateAll/closeTruncateConnection/disconnectTestPrismaClient
usage, and keep DB-backed coverage in a separate integration/e2e test suite.
In `@src/features/store/services/store-review.service.spec.ts`:
- Around line 20-35: The spec is tied to a real database through
createTestingModuleWithRealDb, PrismaClient, and truncateAll(), so refactor
StoreReviewService tests to use mocked/stubbed dependencies instead of real DB
access. Update the setup around createTestingModuleWithRealDb,
StoreReviewRepository, and service initialization so the service is tested in
isolation with deterministic repository behavior, and move any true persistence
coverage into a separate integration/e2e suite. Also make sure the revised
StoreReviewService.spec covers the main success path plus key error/branch cases
without relying on DB state.
In `@src/features/store/services/store-review.service.ts`:
- Around line 38-42: The `storeReviewService` like-status lookup is using a
truthy check on `accountId`, which incorrectly skips `findLikedReviewIds` when
the account ID is `0n`. Update the conditional in `StoreReviewService` to branch
explicitly on `accountId !== undefined` so `0n` is treated as a valid value, and
keep the fallback `new Set<string>()` only for the undefined case.
---
Nitpick comments:
In `@src/features/product/resolvers/product-storefront-query.resolver.spec.ts`:
- Around line 19-69: This spec is doing real DB integration work instead of
isolating the resolver; refactor ProductStorefrontQueryResolver tests to mock or
stub ProductStorefrontService and keep ProductRepository/Prisma out of this unit
spec. Update the resolver setup in beforeAll to use a testing module with a
mocked ProductStorefrontService, then verify storeProducts and
storeProductCategories only pass the correct arguments and return the mocked
result. Add at least one case for service error propagation so the resolver’s
thin delegation behavior is covered without relying on
createTestingModuleWithRealDb, createStore, or direct prisma writes.
In `@src/features/store/resolvers/store-detail-query.resolver.spec.ts`:
- Around line 25-45: The resolver spec is bootstrapping a real database via
createTestingModuleWithRealDb, which makes StoreDetailQueryResolver tests depend
on DB state instead of just resolver behavior. Replace the real DB setup with a
mocked/stubbed testing module by stubbing StoreDetailService and any repository
dependencies used by the resolver, and keep the test focused on argument
forwarding and auth branching in StoreDetailQueryResolver. Move any DB
integration coverage for StoreRepository or StoreWishlistRepository into
separate integration tests.
In `@src/features/store/resolvers/store-review-query.resolver.spec.ts`:
- Around line 56-84: Add a test case in store-review-query.resolver.spec.ts that
covers the invalid accountId path used by storeReviews, since it calls
parseAccountId directly. Verify that empty string, negative, or non-numeric
accountId inputs trigger BadRequestException, alongside the existing
login/unlogin happy-path tests. Use the resolver.storeReviews and parseAccountId
flow to locate the branch and keep the test deterministic with mocked/stubbed
inputs.
In `@src/features/store/services/store-detail.service.spec.ts`:
- Around line 22-37: This spec is coupled to the real database through
createTestingModuleWithRealDb, PrismaClient, and truncateAll; refactor
StoreDetailService.spec.ts into a pure unit test by mocking/stubbing
StoreRepository and StoreWishlistRepository in the testing module setup and
removing any real DB lifecycle calls from beforeAll/beforeEach/afterAll. Keep
StoreDetailService as the system under test, and move any database-backed
verification into a separate integration/e2e test file so this *.spec.ts no
longer depends on external state or environment.
In `@src/features/store/services/store-review.service.spec.ts`:
- Around line 173-181: 현재 `storeReviews` 스펙의 “비활성/삭제 매장” 테스트는 `is_active`만 검증하고
있어 `deleted_at` 분기를 놓치고 있습니다. `storeReviews`와 `createStore`/`makeReview`를 사용하는
같은 테스트 파일에 삭제된 매장만 대상으로 하는 케이스를 추가해, `deleted_at`이 설정된 매장에서도 `items`가 비고
`totalCount`가 0인지 확인하세요. 기존 비활성 매장 케이스와 분리해 `is_active`/`deleted_at` 각각의 필터 분기를
모두 커버하도록 유지하세요.
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 4790ee45-d522-42cf-84bd-b9553e25c1a2
📒 Files selected for processing (40)
prisma/migrations/20260623175315_add_store_image_and_detail_columns/migration.sqlprisma/schema.prismaprisma/seed/idempotent.tsprisma/seed/stores.tssrc/features/product/constants/product-storefront.constants.tssrc/features/product/dto/inputs/store-products.input.tssrc/features/product/product-storefront.graphqlsrc/features/product/product.module.tssrc/features/product/repositories/product.repository.tssrc/features/product/resolvers/product-storefront-query.resolver.spec.tssrc/features/product/resolvers/product-storefront-query.resolver.tssrc/features/product/services/product-storefront-mappers.helper.spec.tssrc/features/product/services/product-storefront-mappers.helper.tssrc/features/product/services/product-storefront.service.spec.tssrc/features/product/services/product-storefront.service.tssrc/features/product/types/product-storefront-output.type.tssrc/features/store/constants/store-detail-error-messages.tssrc/features/store/constants/store-review.constants.tssrc/features/store/dto/inputs/store-reviews.input.tssrc/features/store/repositories/store-review.repository.tssrc/features/store/repositories/store.repository.tssrc/features/store/resolvers/store-detail-query.resolver.spec.tssrc/features/store/resolvers/store-detail-query.resolver.tssrc/features/store/resolvers/store-review-query.resolver.spec.tssrc/features/store/resolvers/store-review-query.resolver.tssrc/features/store/services/store-detail-mappers.helper.spec.tssrc/features/store/services/store-detail-mappers.helper.tssrc/features/store/services/store-detail.service.spec.tssrc/features/store/services/store-detail.service.tssrc/features/store/services/store-mappers.helper.tssrc/features/store/services/store-review-mappers.helper.spec.tssrc/features/store/services/store-review-mappers.helper.tssrc/features/store/services/store-review.service.spec.tssrc/features/store/services/store-review.service.tssrc/features/store/store-detail.graphqlsrc/features/store/store-reviews.graphqlsrc/features/store/store.module.tssrc/features/store/types/store-detail-output.type.tssrc/features/store/types/store-review-output.type.tssrc/test/factories/store.factory.ts
| beforeAll(async () => { | ||
| const { module, prisma: p } = await createTestingModuleWithRealDb({ | ||
| providers: [ProductStorefrontService, ProductRepository], | ||
| }); | ||
| service = module.get(ProductStorefrontService); | ||
| prisma = p; | ||
| }); | ||
|
|
||
| afterAll(async () => { | ||
| await closeTruncateConnection(); | ||
| await disconnectTestPrismaClient(); | ||
| }); | ||
|
|
||
| beforeEach(async () => { | ||
| await truncateAll(); | ||
| }); |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy lift
이 *.spec.ts는 실DB 대신 stub/mock으로 통제하는 편이 좋겠습니다.
createTestingModuleWithRealDb, truncateAll, 직접 Prisma 조작까지 모두 실제 DB에 기대고 있어서 이 스펙이 느리고 환경 의존적으로 바뀝니다. 서비스 단위 테스트라면 ProductRepository를 stub/mock으로 대체하고, 실DB 검증은 별도 integration/e2e 테스트로 분리하는 편이 맞습니다.
As per path instructions, src/**/*.spec.ts: 테스트는 시간/uuid/네트워크/DB 의존성을 mock 또는 stub으로 통제하는지 확인하세요.
🤖 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 `@src/features/product/services/product-storefront.service.spec.ts` around
lines 33 - 48, This spec is relying on a real database via
createTestingModuleWithRealDb, truncateAll, and direct Prisma cleanup, but it
should be a unit test controlled with stubs/mocks. Replace the real-db setup in
product-storefront.service.spec.ts by mocking ProductRepository (and any
Prisma-backed behavior) when creating the module for ProductStorefrontService,
and remove the truncate/disconnect lifecycle tied to the actual DB. Keep real
database verification in separate integration/e2e coverage.
Source: Path instructions
| beforeAll(async () => { | ||
| const { module, prisma: p } = await createTestingModuleWithRealDb({ | ||
| providers: [ | ||
| StoreReviewQueryResolver, | ||
| StoreReviewService, | ||
| StoreReviewRepository, | ||
| ], | ||
| }); | ||
| resolver = module.get(StoreReviewQueryResolver); | ||
| prisma = p; | ||
| }); | ||
|
|
||
| afterAll(async () => { | ||
| await closeTruncateConnection(); | ||
| await disconnectTestPrismaClient(); | ||
| }); | ||
|
|
||
| beforeEach(async () => { | ||
| await truncateAll(); | ||
| }); |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy lift
resolver spec도 실DB 의존으로 고정돼 있습니다.
이 파일도 createTestingModuleWithRealDb와 truncate 흐름에 묶여 있어서 src/**/*.spec.ts 규칙과 어긋납니다. resolver spec은 guard/user/service 상호작용만 검증하도록 mock 기반으로 두고, DB 관통 검증은 별도 integration/e2e로 분리하는 게 안전합니다.
As per path instructions, src/**/*.spec.ts: 테스트는 시간/uuid/네트워크/DB 의존성을 mock 또는 stub으로 통제하는지, 정상 흐름뿐 아니라 주요 예외/분기 케이스가 포함되는지 확인하세요.
🤖 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 `@src/features/store/resolvers/store-review-query.resolver.spec.ts` around
lines 25 - 44, This resolver spec is still tied to the real database through
createTestingModuleWithRealDb and truncate/connection cleanup, so refactor it to
a mock-based unit test. Update StoreReviewQueryResolver spec setup to use a
normal testing module with mocked StoreReviewService/StoreReviewRepository (and
any guard/user dependencies if present), remove
truncateAll/closeTruncateConnection/disconnectTestPrismaClient usage, and keep
DB-backed coverage in a separate integration/e2e test suite.
Source: Path instructions
| beforeAll(async () => { | ||
| const { module, prisma: p } = await createTestingModuleWithRealDb({ | ||
| providers: [StoreReviewService, StoreReviewRepository], | ||
| }); | ||
| service = module.get(StoreReviewService); | ||
| prisma = p; | ||
| }); | ||
|
|
||
| afterAll(async () => { | ||
| await closeTruncateConnection(); | ||
| await disconnectTestPrismaClient(); | ||
| }); | ||
|
|
||
| beforeEach(async () => { | ||
| await truncateAll(); | ||
| }); |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy lift
이 spec은 DB 의존성을 실DB에 묶고 있습니다.
createTestingModuleWithRealDb, PrismaClient, truncateAll()에 의존하면 테스트 안정성과 실행 속도가 DB 상태에 좌우됩니다. 이 경로는 repository mock/stub 기반의 서비스 단위 테스트로 두고, 실DB 검증이 꼭 필요하면 별도 integration/e2e 스위트로 분리하는 편이 맞습니다.
As per path instructions, src/**/*.spec.ts: 테스트는 시간/uuid/네트워크/DB 의존성을 mock 또는 stub으로 통제하는지, 정상 흐름뿐 아니라 주요 예외/분기 케이스가 포함되는지 확인하세요.
🤖 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 `@src/features/store/services/store-review.service.spec.ts` around lines 20 -
35, The spec is tied to a real database through createTestingModuleWithRealDb,
PrismaClient, and truncateAll(), so refactor StoreReviewService tests to use
mocked/stubbed dependencies instead of real DB access. Update the setup around
createTestingModuleWithRealDb, StoreReviewRepository, and service initialization
so the service is tested in isolation with deterministic repository behavior,
and move any true persistence coverage into a separate integration/e2e suite.
Also make sure the revised StoreReviewService.spec covers the main success path
plus key error/branch cases without relying on DB state.
Source: Path instructions
…amp) - StoreImage를 SOFT_DELETE_MODELS에 등록해 직접 조회 시 deleted_at 자동 필터 적용 (Codex P2) - storeProducts/storeReviews input의 ID(storeId·categoryId·cursor)에 @isnotempty 추가 (빈 문자열 차단) - discountRate를 0~100으로 clamp (음수 salePrice 방어) - accountId 0n falsy 분기를 !== undefined로 (storeReviews·storeDetail — account id 0의 좋아요/찜 누락 방지) - product-storefront service spec: 비활성/삭제 매장 케이스 분리 + soft-delete 검증 추가 CodeRabbit Functional + Codex P2 반영. CodeRabbit Major(spec을 mock으로 전환)는 testcontainers realDB 통합 컨벤션 유지로 미반영.
fix: 릴리즈 리뷰 반영 (StoreImage soft-delete·ID 빈값/0n 방어·discountRate clamp)
Coverage report
Test suite run success1403 tests passing in 168 suites. Report generated by 🧪jest coverage report action from 64ea223 |
|
CodeRabbit Major 3건( 이 레포는 testcontainers 기반 realDB 통합 테스트가 모든 기존 spec에 확립된 컨벤션입니다( Functional 지적(빈 문자열 ID 차단 · discountRate clamp · accountId 0n 분기)과 Codex P2(StoreImage soft-delete 등록)는 #162로 반영해 develop에 머지했습니다. |
Summary
store-detail 구매자(유저) 조회 API를 운영(main)에 릴리즈한다. 매장 상세 헤더·상품 탭·후기 탭 조회와
StoreImage스키마를 포함한다.Scope
develop에 누적된 store-detail 도메인 전체:
storeDetail매장 상세 헤더 +StoreImage테이블 ·Store.access_guide_text/regular_closure_text컬럼 · 마이그레이션storeProducts(검색/카테고리/커서) ·storeProductCategories(사이드바)storeReviews후기 목록 + 좋아요 집계/isLikedstoreReviewscursor 0값 후속 정리진행 상황
store_image테이블 +store.access_guide_text/regular_closure_text컬럼 (둘 다 nullable / 신규 테이블 → 기존 데이터 무중단)Impact
store_image테이블 +store컬럼 2개)Test plan
yarn validate통과(누적 테스트 1300+)Summary by CodeRabbit
New Features
Bug Fixes