Skip to content

fix: soft-delete 가드 누락 지점 보강 (셀러 조회·리뷰 집계) - #222

Merged
chanwoo7 merged 2 commits into
developfrom
fix/soft-delete-guard-gaps
Aug 27, 2026
Merged

fix: soft-delete 가드 누락 지점 보강 (셀러 조회·리뷰 집계)#222
chanwoo7 merged 2 commits into
developfrom
fix/soft-delete-guard-gaps

Conversation

@chanwoo7

@chanwoo7 chanwoo7 commented Aug 27, 2026

Copy link
Copy Markdown
Member

무엇을 왜

#221의 전수 조사에서 soft-delete 가드가 빠진 지점들이 나왔습니다. 이 PR은 그중 "같은 파일에서 형제 필드는 가드하는데 이것만 안 한다"가 명백한 곳만 고칩니다. 예컨대 상품 상세 include에서 images와 option_groups는 걸러주면서 product_categories는 안 거르는 식인데, 이건 정책이 아니라 누락입니다. 반면 유저 본인 리뷰 목록에 삭제된 매장/상품이 보이는 건(to-one 무필터) 이력 표시라는 의도일 수 있어 정책 판단으로 넘겼고, mutation 결과 include는 방금 쓴 행이라 실피해가 낮아 함께 보류했습니다. 둘 다 #207에 기록해 뒀습니다.

고친 곳

  • 상품 조회 3경로 (셀러 목록 · 상세 · 비활성 포함 상세) — product_categories/product_tags에 링크와 대상 양쪽의 가드를 추가했습니다. 삭제된 카테고리에 연결돼 있다는 이유로 상품 화면에 유령 카테고리가 뜨던 경로입니다.
  • 셀러 옵션 그룹 · 커스텀 템플릿 read 3곳option_items/text_tokens 가드. 같은 파일의 구매자 노출용 include에는 전부 가드가 있었습니다.
  • 셀러 주문 상세 — 유저측 상세는 상태 이력부터 첨부까지 5단 relation을 전부 거르는데 셀러측은 하나도 안 걸렀습니다. 동일하게 맞추고, 목록·상세의 items.some에도 가드를 얹어 soft-delete 아이템만 남은 주문이 목록에 뜨거나 상세가 열리는 일이 없게 했습니다.
  • 리뷰 가능 집계(findReviewableOrderIds) — 형제 메서드는 "삭제된 주문의 아이템 노출 방지" 주석과 함께 order 필터를 거는데 이쪽만 빠져 있어 맞췄습니다.

카테고리/태그에서 한 가지 판단이 있었습니다. 가드는 deleted_at만 걸고 is_active는 걸지 않았는데, 셀러 화면은 관리자가 카테고리를 비활성화해도 자기 상품의 기존 지정을 계속 볼 수 있어야 하기 때문입니다. 명세에 없는 결정이라 코드 주석에도 남겼습니다.

리뷰에서 하나 더

Codex가 유효한 빈틈을 짚었습니다. include만 가드하면 셀러 목록에서 "삭제된 연결로 필터에는 걸리는데 정작 그 연결은 화면에서 숨겨지는" 반쪽 상태가 된다는 것. listProductsByStore의 categoryId 필터와 태그 검색 predicate에도 같은 가드를 적용해 마무리했습니다.

검증

각 수정에 회귀 테스트를 붙여 총 7건입니다 — 카테고리·태그 링크/대상 제외와 삭제된 연결의 필터 미매칭(repository), 옵션 아이템·텍스트 토큰 제외(repository), 셀러 주문 상세의 아이템·이력 제외와 soft-delete 아이템만 남은 주문의 상세 NotFound·목록 제외(service), soft-delete 주문의 리뷰 가능 집계 제외(repository). 테스트를 위해 주문 팩토리에 deleted_at override를 추가했습니다. yarn validate 전체 green입니다(192 suites / 1,656 tests).

Refs #207

이슈 #207 전수 조사에서 발견된, 같은 파일 내 형제 필드는 가드가 있는데
빠져 있던 명백한 불일치 지점을 보강한다.

- product.repository 상품 조회 3경로(listProductsByStore·findProductById·
  findProductByIdIncludingInactive): product_categories/product_tags에
  링크·대상 soft-delete 가드 추가. is_active는 셀러 화면에서 기존 지정을
  계속 보여줘야 하므로 걸지 않는다(명세 외 정책 결정).
- product.repository 셀러 옵션·템플릿 read 3곳(findOptionGroupById·
  listOptionGroupsByProduct·findCustomTemplateById): option_items/
  text_tokens 가드 추가.
- order.repository 셀러 주문 상세(findOrderDetailByStore): 유저측 상세와
  동일하게 status_histories·items·option_items·custom_texts·free_edits·
  attachments 가드 추가. 셀러 목록·상세의 items.some에도 가드를 얹어
  soft-delete 아이템만 남은 주문이 노출되지 않게 한다.
- order.repository findReviewableOrderIds: 형제 메서드
  (listReviewableOrderItems)와 동일하게 order 관계 필터에 가드 추가.
- 테스트 팩토리: createOrder/createOrderItem에 deleted_at override 지원.

회귀 테스트 6건: 상품 상세 카테고리·태그 링크 제외(repository), 옵션
아이템·텍스트 토큰 제외(repository), 셀러 주문 상세 아이템·이력 제외,
soft-delete 아이템만 있는 주문의 상세 NotFound·목록 제외(service),
soft-delete 주문의 리뷰 가능 집계 제외(repository).
전체 validate green (192 suites / 1,655 tests).

Claude-Session: https://claude.ai/code/session_01KfiGgWooJdsa4iPQPmqvBj
@coderabbitai

coderabbitai Bot commented Aug 27, 2026

Copy link
Copy Markdown

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 Plus

Run ID: e2ca4a10-da49-4e09-8bf6-dd1dce5022ad

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

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.

@github-actions

Copy link
Copy Markdown

🩺 NestJS Doctor — 89/100 (Good)

진단 283건 (error 0).

Category error warning info
architecture 0 0 13
correctness 0 130 0
performance 0 24 17
schema 0 0 86
security 0 13 0
architecture / security 상위 항목
  • info architecture/architecture/no-barrel-export-internals: Barrel file re-exports internal type 'IAuditLogRepository'.
  • warning security/security/no-exposed-env-vars: Direct 'process.env.NODE_ENV' access in 'AuthController'. Use ConfigService instead.
  • warning security/security/require-guards-on-endpoints: Endpoint 'start' has no @UseGuards() at class or method level.
  • warning security/security/require-guards-on-endpoints: Endpoint 'callback' has no @UseGuards() at class or method level.
  • warning security/security/require-guards-on-endpoints: Endpoint 'refresh' has no @UseGuards() at class or method level.
  • warning security/security/require-guards-on-endpoints: Endpoint 'logout' has no @UseGuards() at class or method level.
  • warning security/security/require-guards-on-endpoints: Endpoint 'sellerLogin' has no @UseGuards() at class or method level.
  • warning security/security/require-guards-on-endpoints: Endpoint 'sellerRefresh' has no @UseGuards() at class or method level.
  • warning security/security/require-guards-on-endpoints: Endpoint 'sellerLogout' has no @UseGuards() at class or method level.
  • warning security/security/require-guards-on-endpoints: Endpoint 'devIssueToken' has no @UseGuards() at class or method level.
  • info architecture/architecture/no-barrel-export-internals: Barrel file re-exports internal module '@/features/conversation/repositories/conversation.repository'.
  • info architecture/architecture/no-barrel-export-internals: Barrel file re-exports internal type 'ConversationRepository'.
  • info architecture/architecture/no-barrel-export-internals: Barrel file re-exports internal module '@/features/order/repositories/order.repository'.
  • info architecture/architecture/no-barrel-export-internals: Barrel file re-exports internal type 'OrderRepository'.
  • info architecture/architecture/no-barrel-export-internals: Barrel file re-exports internal module '@/features/product/repositories/product.repository'.

오탐 포함 가능 · 기준 docs/guide/architecture-conventions.md

@github-actions

Copy link
Copy Markdown

🧹 knip — dead-code 리포트

Unused exports (2)
전체 리포트
Unused exports (2)
RegionRepository  src/features/region/index.ts:3:10
StoreRepository   src/features/store/index.ts:3:10

청소 후보(오탐 가능) · 기준 docs/guide/architecture-conventions.md

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

Copy link
Copy Markdown

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: cd20058197

ℹ️ 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_categories: {
// 링크·대상 카테고리의 soft-delete 가드. is_active는 셀러 화면에서
// 기존 지정을 계속 보여줘야 하므로 걸지 않는다.
where: { ...activeWhere, category: activeWhere },

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 Apply soft-delete guards to seller-list predicates

When sellerProducts filters by a category or searches by a tag that is linked only through a soft-deleted ProductCategory/ProductTag (or a deleted target), the top-level some predicates still match because they lack activeWhere. These new include guards then hide the matching relation while the product remains in the results, so deleted taxonomy continues to affect seller filtering and search; apply the same link and target guards to the relation predicates in listProductsByStore.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

반영: listProductsByStore의 categoryId·search 태그 predicate에도 include와 동일한 링크·대상 soft-delete 가드 추가. 회귀 테스트 1건 동반.

@github-actions

github-actions Bot commented Aug 27, 2026

Copy link
Copy Markdown

Coverage report

St.
Category Percentage Covered / Total
🟢 Statements 97.66% 5013/5133
🟢 Branches 93.96% 2037/2168
🟢 Functions 96.22% 967/1005
🟢 Lines 98.21% 4564/4647

Test suite run success

1656 tests passing in 191 suites.

Report generated by 🧪jest coverage report action from da3725d

@codecov

codecov Bot commented Aug 27, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Codex 리뷰 반영(PR #222): listProductsByStore의 categoryId·search 태그
predicate가 include와 달리 무가드라, 삭제된 연결만 가진 상품이 필터에
걸린 채 연결은 숨겨지는 불일치가 있었다. include와 동일한 가드를 적용하고
회귀 테스트 1건(삭제된 연결·태그로는 목록 필터 미매칭)을 추가한다.

Claude-Session: https://claude.ai/code/session_01KfiGgWooJdsa4iPQPmqvBj
@chanwoo7
chanwoo7 merged commit 7fc6897 into develop Aug 27, 2026
11 checks passed
@chanwoo7
chanwoo7 deleted the fix/soft-delete-guard-gaps branch August 27, 2026 14:49
chanwoo7 added a commit that referenced this pull request Aug 27, 2026
Codex 리뷰 반영(PR #222): listProductsByStore의 categoryId·search 태그
predicate가 include와 달리 무가드라, 삭제된 연결만 가진 상품이 필터에
걸린 채 연결은 숨겨지는 불일치가 있었다. include와 동일한 가드를 적용하고
회귀 테스트 1건(삭제된 연결·태그로는 목록 필터 미매칭)을 추가한다.
chanwoo7 added a commit that referenced this pull request Aug 27, 2026
fix: soft-delete 가드 누락 지점 보강 (셀러 조회·리뷰 집계)
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