[volume-5] 상품 목록 브랜드 필터링 및 상품 Redis 캐시 적용#206
Merged
letter333 merged 144 commits intoLoopers-dev-lab:letter333from Mar 14, 2026
Merged
[volume-5] 상품 목록 브랜드 필터링 및 상품 Redis 캐시 적용#206letter333 merged 144 commits intoLoopers-dev-lab:letter333from
letter333 merged 144 commits intoLoopers-dev-lab:letter333from
Conversation
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- member-erd.md: 회원 테이블 ERD 설계 - member-signup-design.md: 시퀀스/클래스 다이어그램, 패키지 구조 - CLAUDE.md: 개발 규칙 및 문서 작성 가이드 반영 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Member 도메인 객체 구현 (순수 Java, JPA 어노테이션 없음) - 필드 검증: loginId, password, name, birthday, email - 비밀번호 규칙: 8~16자, 영문+숫자+특수문자, 생년월일 포함 불가 - encryptPassword()로 암호화된 비밀번호 교체 지원 test: add MemberTest with 14 unit test cases Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…ure/member-signup
… entity Member 도메인의 Infrastructure 레이어 구현: - MemberEntity (JPA 영속성 엔티티, Domain↔Entity 변환) - MemberRepository 인터페이스 (도메인 레이어) - MemberJpaRepository (Spring Data JPA) - MemberRepositoryImpl (Repository 구현체) - MemberEntityTest, MemberRepositoryImplIntegrationTest - spring-security-crypto 의존성 추가 - docker-java.properties (Docker Engine 29 TestContainers 호환) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- MemberService.signUp(): 중복 검사 → 도메인 생성 → 비밀번호 암호화 → 저장 - PasswordEncoderConfig: BCryptPasswordEncoder Bean 등록 - MemberServiceTest: 정상 가입, loginId 중복, email 중복 통합 테스트 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- MemberInfo: Domain → 응답 변환 record (password, birthday 제외) - MemberFacade: MemberService 위임 및 MemberInfo 변환 - MemberInfoTest, MemberFacadeTest 추가 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- POST /api/v1/members → 201 Created - MemberV1Dto: SignUpRequest/SignUpResponse record - MemberV1ApiSpec: Swagger 스펙 인터페이스 - MemberV1Controller: Facade 위임 및 응답 변환 - MemberV1ApiE2ETest: 정상 가입(201), 검증 실패(400), 중복(409) E2E 테스트 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Controller에서 birthday null/빈 문자열/잘못된 형식 시 400 BAD_REQUEST 반환 - birthday 관련 E2E 테스트 2건 추가 - 회원가입 API .http 파일 생성 - CLAUDE.md 프로젝트 규칙 보강 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- 내 정보 조회 기능 시퀀스/클래스 다이어그램 작성 - 회원가입 시퀀스 다이어그램 Entity 반환 화살표 누락 수정 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- MemberRepository 인터페이스에 findByLoginId 추가 - MemberJpaRepository, MemberRepositoryImpl 구현 - 통합 테스트 2건 추가 (존재/미존재 케이스) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- MemberService.authenticate() 메서드 추가 (loginId 조회 + 비밀번호 검증) - ErrorType에 UNAUTHORIZED(401) 추가 - 통합 테스트 3건 추가 (성공, 회원 미존재, 비밀번호 불일치) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- GET /api/v1/members/me 엔드포인트 추가 (X-Loopers-LoginId, X-Loopers-LoginPw 헤더 인증) - MemberInfo에 birthday 필드 추가, MyInfoResponse DTO 추가 - MemberFacade.getMyInfo(), MemberV1ApiSpec, MemberV1Controller 구현 - ApiControllerAdvice에 MissingRequestHeaderException 핸들러 추가 - E2E 테스트 4건 추가 (200, 401×2, 400) - 통합 테스트 생성자 주입으로 리팩터링 (필드 주입 → 생성자 주입) - member-v1.http에 내 정보 조회 요청 추가 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- password MIN(8자), MAX(16자) 성공 테스트 추가 - name MIN(한글 2자), MAX(한글 20자) 성공 테스트 추가 - birthday 오늘 날짜(경계값) 성공 테스트 추가 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
feature/member-profile-lookup
Member.changePassword() 메서드를 통해 현재 비밀번호 검증, 동일 비밀번호 방지, 새 비밀번호 룰 검증(길이/패턴/생년월일), 암호화까지 도메인 엔티티에서 캡슐화 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
MemberService.updatePassword() 추가, MemberRepository에 updatePassword 메서드 정의, MemberRepositoryImpl에서 JPA dirty checking 기반 UPDATE 구현, 통합 테스트 추가 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
PATCH /api/v1/members/me/password 엔드포인트 추가, 헤더 PW와 Body currentPassword 일치 검증, E2E 테스트 8건 추가 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
API 응답 규칙, 의존성 방향, 인증 헤더 규칙, TDD 단계별 진행 규칙, 테스트 경계값 케이스 가이드 추가 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
feat: 비밀번호 변경 API 구현
도메인 계층의 PasswordEncoder 의존성을 제거하고, 유즈케이스 검증(현재 비밀번호 확인, 동일 비밀번호 확인)을 MemberService로 이동하여 의존성 방향 규칙 준수 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
refactor: 비밀번호 변경 검증 책임을 서비스 레이어로 분리
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…loop-pack-be-l2-vol3-java into feature/member-signup
feat: 회원 도메인 기능 구현 (가입, 조회, 비밀번호 변경)
MemberInfo에 withMaskedName() 메서드 추가하여 이름의 마지막 글자를 *로 마스킹하는 기능 구현 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
feat: 내 정보 조회 시 이름 마스킹 기능 추가
LOGIN_ID_PATTERN을 추가하여 영문 대소문자와 숫자만 허용 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- @component → @Service/@repository 어노테이션 일관성 통일 (coupon 도메인) - getMyCoupons() 3개 COUNT 쿼리를 SUM+CASE 1개 통합 쿼리로 최적화 - getIssuableCoupons() 전체 ID 메모리 로딩을 DB LEFT JOIN 쿼리로 대체 - OrderFacade 쿠폰 검증/할인 계산 로직을 MemberCouponService로 추출 - 미사용 import 정리 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- 통합 쿼리(getStatusCounts)로 대체된 개별 COUNT 메서드 3건 제거 - LEFT JOIN 쿼리로 대체된 getIssuedCouponIds, findAllIssuable 체인 제거 - MemberCouponListInfo 미사용 import 제거 - validateAndCalculateDiscount → validateAndGetCoupon으로 변경하여 OrderFacade에서 MemberCoupon 재조회 없이 쿠폰 사용 처리 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
refactor: 코드 품질 개선 및 데드 코드 정리
SELECT ... FOR UPDATE 네이티브 쿼리로 상품 row를 잠근 후 재고를 변경하여 동시 주문 시 Lost Update로 인한 과매도(overselling)를 방지한다. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Product: 기존 재고용 비관적 락(findByIdForUpdate) 재사용하여 likeCount 증감 시 Lost Update 방지 - Brand: @Version 낙관적 락 + TransactionTemplate 재시도(최대 3회)로 동시성 문제 해결 - BrandEntity에 version 필드 추가, BrandRepository에 likeCount 전용 메서드 추가 - ApiControllerAdvice에 ObjectOptimisticLockingFailureException 핸들러 추가 - Product/Brand 각각 동시성 테스트(10 스레드) 추가 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
useCoupon 호출 시 SELECT FOR UPDATE로 row-level lock을 획득하여 동시 사용 요청에서 정확히 1건만 성공하도록 보장한다. 원자적 UPDATE 대신 비관적 락을 선택한 이유: - OrderFacade 구조상 할인 계산을 위한 SELECT 생략 불가 - 도메인 객체(MemberCoupon.use())에서 에러 세분화 유지 - 프로젝트 전체 동시성 패턴과 일관성 확보 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
주문 취소 시 재고 복구·쿠폰 반환 등 부수 효과의 이중 실행을 방지하기 위해 Order에 비관적 락(SELECT FOR UPDATE)을 적용하고, 단일 locking read 패턴으로 MySQL REPEATABLE READ 환경에서의 stale read 문제를 해결한다. - OrderJpaRepository: @lock(PESSIMISTIC_WRITE) 적용 JPQL 추가 - OrderService: getOrderForUpdate, saveOrder 메서드 추가 - OrderFacade: cancelOrder, changeOrderStatusForAdmin 비관적 락 기반으로 변경 - 단위 테스트 수정 및 동시성 통합 테스트(OrderCancelConcurrencyTest) 추가 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
createOrder, cancelOrder, changeOrderStatusForAdmin에서 Product 락을 클라이언트 요청 순서대로 획득하던 것을 productId 오름차순으로 정렬하여 순환 대기(Circular Wait) 조건을 원천 차단한다. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- 락 없이 취소하는 위험 경로(OrderService.cancelOrder) 제거 - 취소는 OrderFacade에서 비관적 락 + 재고복원 + 쿠폰취소를 포함한 완전한 흐름으로만 실행 - 주문 상태 변경 동시성 테스트 추가 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
feat: 동시성 문제 해결 — 비관적 락 및 데드락 방지 적용
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- MemberCouponRepository에서 미사용 existsByMemberIdAndCouponId 제거 - LikeFacadeTest의 transactionTemplate 모킹을 mockTransactionTemplate()으로 추출 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Product/Brand의 like_count 증감을 낙관적 락 + 엔티티 수정 방식에서 네이티브 SQL(like_count + 1) 원자적 UPDATE로 변경 - LikeFacade의 브랜드 좋아요에서 TransactionTemplate 재시도 로직 제거 - LikeFacadeConcurrencyTest 신규 추가: 10명 동시 좋아요/취소 시 like_count 정합성 검증 - ProductLikeCountPersistenceTest 신규 추가: DB 반영 검증 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- MemberCouponEntity에 @Version 필드 추가로 낙관적 락 적용 - 비관적 락(lockById, findByIdForUpdate) 제거 → findByIdWithCoupon 사용 - OrderFacade.createOrder()에 @retryable 추가 (OptimisticLock 실패 시 최대 3회 재시도) - spring-retry 의존성 및 @EnableRetry 설정 추가 - 동시성 테스트에서 ObjectOptimisticLockingFailureException 처리 추가 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
상품 목록 API에 brandId 필터 파라미터를 추가하고, 필터(brandId, categoryId, keyword)와 정렬(PRICE_ASC, LIKES_DESC) 조합이 정상 동작하는지 검증하는 E2E 테스트 4건을 보강 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
feat: 상품 목록 조회 브랜드 필터링, 인덱스 최적화 및 시드 데이터 배치 Job 추가
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
Important Review skippedToo many files! This PR contains 244 files, which is 94 over the limit of 150. ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (13)
📒 Files selected for processing (244)
You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
📝 Coding Plan
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 Tip CodeRabbit can suggest fixes for GitHub Check annotations.Configure the |
- 상품 목록 조회 Cache-Aside 패턴 적용 (키워드 검색은 캐시 우회) - ProductCacheEvictEvent/Listener로 상품 생성/수정/삭제 시 캐시 무효화 - CachedPage DTO로 Page 직렬화/역직렬화 처리 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- ProductDetailCacheRepository 직접 호출을 ProductCacheEvictEvent 발행으로 변경 - OrderFacade에서 루프 내 개별 evict 대신 Set으로 모아 한 번에 이벤트 발행 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Never Do 항목에 리팩토링 시 테스트 수정 금지 규칙 추가 - CommerceBatchApplicationTest에서 spring.batch.job.enabled=false 설정하여 Job 미지정 시 컨텍스트 로드 실패 방지 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
📌 Summary
🧭 Context & Decision
문제 정의
선택지와 결정
🏗️ Design Overview
변경 범위
ProductDetailCacheRepository(인터페이스),ProductDetailCacheRepositoryImpl(Redis 구현체)주요 컴포넌트 책임
ProductDetailCacheRepository: 상품 상세 캐시 조회/저장/삭제 인터페이스 (application 계층)ProductDetailCacheRepositoryImpl: Redis Master-Replica 기반 캐시 구현 (infrastructure 계층, 읽기: Replica, 쓰기: Master)ProductFacade: Cache-Aside 로직 오케스트레이션 — 캐시 조회 → miss 시 DB 조회 → 캐시 저장LikeFacade/OrderFacade: 좋아요 토글, 주문/취소 시 해당 상품 캐시 evict🔁 Flow Diagram
Main Flow — 상품 상세 조회 (Cache-Aside)
sequenceDiagram autonumber participant Client participant ProductFacade participant CacheRepo participant ProductService participant DB Client->>ProductFacade: getProduct(productId) ProductFacade->>CacheRepo: get(productId) alt Cache Hit CacheRepo-->>ProductFacade: ProductDetailInfo else Cache Miss CacheRepo-->>ProductFacade: empty ProductFacade->>ProductService: getActiveProduct(productId) ProductService->>DB: SELECT DB-->>ProductService: Product ProductService-->>ProductFacade: Product ProductFacade->>CacheRepo: put(productId, info) end ProductFacade-->>Client: ProductDetailInfoMain Flow — 브랜드 ID 필터링