# 20260316_CanServiceGetCanUseStatusRefactoring.md ## 작업 목표 - `CanService.getCanUseStatus` 함수의 비효율적인 필터링 및 데이터 로딩 로직 개선. - Kotlin 레벨에서 수행하던 필터링을 DB 레벨(Querydsl)로 이동. - Entity 전체를 조회하는 대신 필요한 필드만 조회(Query Projection)하도록 리팩토링. ## 작업 내용 - [x] `CanService.getCanUseStatus` 현재 기능 검증용 테스트 코드 작성. - [x] `UseCanQueryDto` 생성 (QueryProjection용 DTO). - [x] `CanRepository`에 Querydsl 기반의 고도화된 `getCanUseStatus` 추가 (또는 기존 메서드 수정). - [x] `member.id` 필터링 (기존 유지). - [x] `(can + rewardCan) > 0` 필터링. - [x] `container`(`aos`, `ios`, `else`)별 `paymentGateway` 필터링 (Join 사용). - [x] 필요한 연관 엔티티(`Member`, `Room`, `AudioContent` 등)의 필드만 선택적으로 조회. - [x] `CanService.getCanUseStatus` 리팩토링. - [x] 리포지토리에서 바로 DTO 또는 필요한 데이터만 받아오도록 수정. - [x] Kotlin `filter` 제거. - [x] Kotlin `map` 로직 단순화 또는 QueryProjection으로 흡수 가능한지 판단하여 처리. - [x] 작성한 테스트 코드로 기능 검증. - [x] 테스트 코드에 `@DisplayName` 추가 및 예외/엣지 케이스 테스트 보강. - [x] 성능 및 쿼리 최적화 확인. ## 검증 결과 - **기능 검증**: - `CanServiceTest.kt`를 작성하여 리팩토링 전후의 필터링 및 맵핑 로직이 동일하게 유지됨을 확인. - `@DisplayName`을 추가하여 테스트 의도를 명확히 기술. - 유효하지 않은 타임존 입력 시 `DateTimeException`이 발생하는 예외 케이스 추가. - 데이터가 없을 때 빈 리스트 반환 및 각 `CanUsage`별 nullable 필드(닉네임, 제목 등)가 누락되었을 때의 기본 타이틀 처리 로직 검증. - **성능 개선**: - Kotlin 레벨의 필터링을 DB 레벨(Querydsl)로 이동하여 불필요한 데이터 조회를 줄이고 페이지네이션 정확도 향상. - Entity 전체 조회 대신 필요한 12개 필드만 조회하는 `UseCanQueryDto` 사용 (Projection). - `CHANNEL_DONATION` 시 별도의 Member 조회를 위해 발생하던 N+1 또는 추가 쿼리를 Join을 통해 1번의 쿼리로 최적화. - **코드 품질**: - `CanService`에서 더 이상 사용하지 않는 `memberRepository` 의존성 제거. - 복잡한 맵핑 로직을 QueryProjection DTO 기반으로 깔끔하게 정리. ### 단계별 검증 내용 1. **1차 구현 및 단위 테스트**: `CanServiceTest`를 통해 `aos`, `ios` 컨테이너별 필터링 조건이 올바르게 DB 쿼리에 반영되고 결과가 맵핑되는지 검증 (성공). 2. **쿼리 최적화 확인**: `UseCanCalculate` 및 관련 엔티티들을 `leftJoin` 및 `innerJoin`을 통해 한 번의 쿼리로 가져오도록 구현됨을 코드 레벨에서 확인.