Conversation
MemberProfileController의 책임을 분리
여러번의 저장 쿼리를 saveAll 한 번으로 개선합니다.
클래스 책임에 맞게 클래스 구조를 리팩토링
Walkthrough이 변경사항은 인증, 회원, 그룹, 예산, 선호도 등 여러 도메인에 걸쳐 컨트롤러 구조를 대대적으로 리팩토링하고, 테스트를 대폭 보강하며, 일부 도메인 엔티티와 서비스의 필드 및 메서드를 제거합니다. 기존 컨트롤러와 테스트 클래스가 삭제되고, 새로운 REST API 컨트롤러와 통합 테스트가 추가되었습니다. Changes
Sequence Diagram(s)sequenceDiagram
actor User
participant AuthController
participant MemberService
participant JwtTokenService
User->>AuthController: POST /api/v1/auth/signup (회원가입)
AuthController->>MemberService: 이메일 중복 확인, 회원 저장
AuthController->>JwtTokenService: JWT 토큰 생성
AuthController-->>User: JWT 토큰 반환
User->>AuthTokenController: POST /api/v1/auth/login (로그인)
AuthTokenController->>LoginService: 로그인 인증
AuthTokenController->>JwtTokenService: JWT 토큰 생성
AuthTokenController-->>User: JWT 토큰 반환
User->>MemberAccountController: PATCH /api/v1/members/me/password (비밀번호 변경)
MemberAccountController->>MemberService: 비밀번호 변경
User->>MemberAddressController: PUT /api/v1/members/me/addresses (주소 등록)
MemberAddressController->>MemberProfileService: 주소 저장
User->>MemberBudgetController: GET/PUT/PATCH /api/v1/members/me/budgets (예산 조회/등록/수정)
MemberBudgetController->>BudgetService: 예산 관련 비즈니스 처리
User->>MemberPreferenceController: GET/POST /api/v1/members/me/preferences (선호도 조회/저장)
MemberPreferenceController->>MemberCategoryPreferenceService: 선호도 저장/조회
Possibly related PRs
Poem
✨ Finishing Touches
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 27
🔭 Outside diff range comments (1)
src/main/java/com/stcom/smartmealtable/web/controller/MemberProfileController.java (1)
28-34: 🛠️ Refactor suggestion입력값 유효성 검증이 부족합니다
nickName,memberType,groupId등이 null 이거나 비어 있을 때의 처리 로직이 없습니다. 서비스 예외로 미루기보다 컨트롤러 단계에서@Validated제약을 추가하는 편이 API 일관성에 도움이 됩니다.
🧹 Nitpick comments (50)
src/main/java/com/stcom/smartmealtable/web/dto/group/SchoolGroupUpdateRequest.java (1)
11-23: Create‧Update DTO 중복 구조 개선 제안
SchoolGroupCreateRequest와 필드·검증 애너테이션 구성이 동일합니다. 두 DTO 의 상속/인터페이스 추출 또는 Java 17record활용으로 중복을 제거하면 유지보수가 수월해집니다.src/test/java/com/stcom/smartmealtable/domain/group/SchoolGroupTest.java (1)
32-35: 세부 주소(detailAddress) 검증 누락
주소 변경 로직의 완전성을 보장하려면detailAddress필드까지 검증해 주세요.
예)assertThat(group.getAddress().getDetailAddress()).isEqualTo("행정관 2층");src/test/java/com/stcom/smartmealtable/domain/group/CompanyGroupTest.java (1)
33-35: detailAddress 검증 추가 권장
SchoolGroupTest와 동일하게 세부 주소까지 검증하면 변경 영향 파악이 쉬워집니다.src/test/java/com/stcom/smartmealtable/repository/GroupRepositoryTest.java (1)
38-40: 결과 건수에 대한 명시적 검증 추가
현재는 첫 번째 엔티티만 확인하고 있어 기대 사이즈가 잘못돼도 통과합니다.
assertThat(result).hasSize(1);등을 추가하면 테스트 강도가 향상됩니다.src/main/java/com/stcom/smartmealtable/web/dto/group/GroupDto.java (1)
10-16: 응답 DTO 에 Setter 노출 불필요
@Data는 setter 까지 생성하여 불변성이 깨질 수 있습니다. 읽기 전용 DTO 인 경우@Getter또는 Javarecord전환을 고려해 주세요.src/main/java/com/stcom/smartmealtable/web/controller/GroupController.java (1)
24-31: 빈 키워드 오류 시 HTTP 상태 코드 명확화 필요
keyword.isBlank()인 경우에도ApiResponse.createError만 반환하고 HTTP 상태 코드는 그대로 200일 가능성이 있습니다. 클라이언트 입장에서는 성공과 실패를 HTTP 코드로 구분하는 것이 직관적이므로 400(Bad Request)로 내려주는 방식을 고려해 주세요.만약
ApiResponse내부에서 상태 코드를 설정하지 않는다면,ResponseEntity를 사용하거나@ResponseStatus(HttpStatus.BAD_REQUEST)를 적용하는 것이 좋습니다.src/test/java/com/stcom/smartmealtable/service/GroupServiceIntegrationTest.java (1)
49-53: Reflection 사용 대신 전용 팩토리/생성자 사용 권장테스트에서
ReflectionTestUtils로 내부 필드를 주입하고 있는데, 이는 도메인 모델 캡슐화를 깨뜨립니다. 테스트 전용 정적 팩토리 메서드나 빌더를 도메인 객체에 제공하면 리플렉션 의존성을 제거할 수 있습니다.src/main/java/com/stcom/smartmealtable/web/controller/SchoolGroupController.java (1)
28-33: 리소스 생성 시 201 Created 및 Location 헤더 반환 고려POST 요청으로 학교 그룹을 생성한 후
201 Created상태 코드와 함께Location헤더(신규 리소스 URI)를 반환하면 REST 규약에 더 부합합니다.ResponseEntity.created(URI)를 사용하는 방안을 검토해 주세요.src/test/java/com/stcom/smartmealtable/service/GroupServiceAdditionalIntegrationTest.java (1)
51-65:@Transactional테스트에서 중복@Rollback어노테이션 불필요
@Transactional을 사용한 Spring 테스트는 기본적으로 테스트 종료 시 롤백됩니다. 개별 테스트 메서드에@Rollback을 추가로 선언하지 않아도 동일한 효과가 있으니 제거하여 어노테이션 중복을 줄일 수 있습니다.src/test/java/com/stcom/smartmealtable/service/GroupServiceCompleteIntegrationTest.java (2)
201-204: 미완성 테스트 처리 필요해당 메서드는 실제 검증 로직 없이 주석만 남아 있습니다. CI 안정성을 위해 최소한
@Disabled("추후 CompanyGroup 도입 시 작성 예정")로 표기하거나, 구현 완료 시점을 앞당기는 것을 권장드립니다.
62-68: 중복 초기화 로직 유틸화 제안
Address빌더 호출이 세 번 반복되고 있어 가독성이 떨어집니다. 정적 헬퍼나@BeforeEach내부의 작은 팩토리 메서드로 추출하면 테스트가 더 간결해집니다.src/main/java/com/stcom/smartmealtable/service/MemberService.java (1)
19-24: 불필요한 의존성 주입 제거 고려
addressEntityRepository필드가 선언만 되고 실제 메서드에서 전혀 사용되지 않습니다. 사용 계획이 없다면 주입을 제거하여 의존성·테스트·가독성을 간소화하세요.- private final AddressEntityRepository addressEntityRepository;src/main/java/com/stcom/smartmealtable/service/BudgetService.java (1)
61-70: 일괄 저장 로직은 좋지만 중복·성능 이슈 점검 필요
- 이미 존재하는 일일 예산이 있을 경우
saveAll시 제약 조건 위반으로 실패할 가능성이 있습니다.
- 저장 전 존재 여부를 필터링하거나,
ON CONFLICT전략(예: JPA merge) 고려가 필요합니다.ArrayList초기 용량을YearMonth.now().lengthOfMonth()로 설정하면 불필요한 리사이즈를 줄일 수 있습니다.- List<DailyBudget> budgets = new ArrayList<>(); + int days = startDate.lengthOfMonth() - startDate.getDayOfMonth() + 1; + List<DailyBudget> budgets = new ArrayList<>(days);src/test/java/com/stcom/smartmealtable/repository/FoodCategoryRepositoryTest.java (1)
28-34: ReflectionTestUtils 사용 최소화 제안엔티티에 Setter 혹은 빌더가 있다면
ReflectionTestUtils.setField대신 정식 API로 값을 지정하는 편이 유지보수에 유리합니다.
필드가 불변이어야 한다면 테스트용 팩토리 메서드를 두는 것도 한 방법입니다.src/main/java/com/stcom/smartmealtable/domain/member/MemberProfile.java (1)
55-62: 불필요한 FQN 사용
new java.util.ArrayList<>()대신 상단import java.util.ArrayList;를 추가하고 간결하게new ArrayList<>()로 작성하면 가독성이 좋아집니다.src/test/java/com/stcom/smartmealtable/repository/TermAgreementRepositoryTest.java (2)
39-42: ReflectionTestUtils 남용테스트 목적이라도 필드 접근을 리플렉션으로 우회하면 유지보수성이 떨어집니다.
Term엔티티에 테스트 전용 빌더나 생성자를 제공하는 방법을 고려해 주세요.
52-58: 검증 범위 확장 제안
isAgreed값에 대한 검증이 빠져 있습니다. 또한Optional을 두 번get()하기보다는hasValueSatisfying를 사용하면 NPE 우려 없이 더 읽기 쉬운 테스트가 됩니다.- var found = repository.findById(agreement.getId()); - - // then - assertThat(found).isPresent(); - assertThat(found.get().getTerm().getTitle()).isEqualTo("테스트 약관"); - assertThat(found.get().getMember().getEmail()).isEqualTo("agree@test.com"); + assertThat(repository.findById(agreement.getId())) + .hasValueSatisfying(a -> { + assertThat(a.isAgreed()).isTrue(); + assertThat(a.getTerm().getTitle()).isEqualTo("테스트 약관"); + assertThat(a.getMember().getEmail()).isEqualTo("agree@test.com"); + });src/test/java/com/stcom/smartmealtable/repository/TermRepositoryTest.java (1)
42-56: 테스트 유틸리티 코드 중복
ReflectionTestUtils를 이용해 필드를 세팅하는 보일러플레이트가 여러 테스트에서 반복됩니다.
엔티티에 패키지-private 생성자 또는 빌더를 제공해 테스트 코드 중복을 줄여 보세요.src/test/java/com/stcom/smartmealtable/repository/SocialAccountRepositoryTest.java (1)
36-44: 시간 의존성 제거 권장
LocalDateTime.now()를 사용하면 타임존이나 시스템 시간 변경에 따라 테스트가 오동작할 수 있습니다.
Clock을 주입받아 고정값을 사용하거나LocalDateTime.of(...)로 명시적인 값을 넣어 테스트를 결정론적으로 만드시는 편이 좋습니다.src/test/java/com/stcom/smartmealtable/service/MemberServiceFailureIntegrationTest.java (1)
28-35: @Rollback 어노테이션 사용 일관성클래스 레벨에
@Transactional이 선언되어 있으므로 각 테스트는 기본적으로 롤백됩니다.
특정 테스트 메서드에만@Rollback을 다시 선언하면 의도를 파악하기 어렵습니다. 전부 제거하거나 필요시@Commit으로 명시적으로 커밋하는 형태로 통일하세요.src/test/java/com/stcom/smartmealtable/repository/MemberProfileRepositoryTest.java (1)
46-50: 엔티티 그래프 검증이 확실하지 않습니다
assertThat(found.get().getMember().getEmail())만으로는member연관 엔티티가 실제로 fetch-join 되었는지 확인할 수 없습니다. 트랜잭션이 열려 있으면 LAZY 로딩도 통과하므로,Hibernate.isInitialized(found.get().getMember())등을 이용해 초기화 여부를 명시적으로 검증하거나EntityManagerFactory의 통계 조회로 추가 쿼리 발생 여부를 확인하는 방식이 보다 안전합니다.src/test/java/com/stcom/smartmealtable/service/SocialAccountServiceIntegrationTest.java (1)
44-48: 시간 기반 단정식이 경계 조건에서 실패할 수 있습니다
isAfter(LocalDateTime.now())는 밀리초 단위 경합으로 드물게 실패할 수 있습니다.
isAfterOrEqualTo로 완화하거나,tokenExpiresAt계산 시점과 비교값을 동일 객체로 두고 검증하는 편이 안전합니다.src/main/java/com/stcom/smartmealtable/web/controller/MemberController.java (2)
16-24: DTO에 기본 생성자 부재Lombok
@Data+@AllArgsConstructor조합만으로는 Jackson 직렬화/역직렬화 시 기본 생성자가 없어 실패할 수 있습니다.
@NoArgsConstructor또는@Builder추가를 고려해주세요.
34-39: Boolean 필드 네이밍
isAgreed는 Boolean wrapper 이므로 게터가getIsAgreed()로 생성되어 직관성이 떨어집니다.agreed로 필드명을 바꾸는 것이 일반적입니다.src/test/java/com/stcom/smartmealtable/service/MemberCategoryPreferenceServiceIntegrationTest.java (1)
60-66: Reflection 사용 최소화 권장테스트에서
ReflectionTestUtils.setField로name을 주입하고 있습니다.
엔티티에 테스트용 팩터리 메서드·builder 를 제공하면 리플렉션 없이도 가독성과 안정성을 유지할 수 있습니다.src/test/java/com/stcom/smartmealtable/service/LoginServiceIntegrationTest.java (1)
30-31: 중복된@Rollback어노테이션 제거 제안클래스에 이미
@Transactional이 선언되어 있어 테스트 종료 시 자동 롤백됩니다.
메서드 레벨의@Rollback은 중복 설정이므로 제거해도 동일하게 동작합니다.src/test/java/com/stcom/smartmealtable/service/MemberServiceAdditionalIntegrationTest.java (1)
28-39: 테스트 픽스처 저장 방식 통일 권장
setUp()에서memberRepository.save()를 직접 호출하고 있습니다. 다른 테스트 클래스들은memberService.saveMember()를 사용합니다.
서비스 계층을 통한 저장으로 통일하면 추후 도메인 로직(이벤트, 암호화 등) 변경 시 테스트 누락을 방지할 수 있습니다.src/test/java/com/stcom/smartmealtable/service/MemberServiceIntegrationTest.java (2)
55-61: 리포지토리 직접 저장 → 서비스 계층 사용으로 교체 권장통합 테스트에서는 도메인 규칙(비밀번호 암호화, 이벤트 발행 등)을 포함한 서비스 계층을 거쳐 엔티티를 생성하는 편이 안정적입니다.
memberRepository.save(member);부분을memberService.saveMember(member);로 교체하는 것을 고려해 주세요.
32-35: 메서드 단위@Rollback중복클래스가
@Transactional이므로 메서드 레벨@Rollback은 필요 없습니다. 삭제하여 어노테이션 중복을 줄이세요.src/test/java/com/stcom/smartmealtable/service/SocialAccountServiceCompleteIntegrationTest.java (1)
42-44: Member 생성 시 비밀번호 정책 누락
new Member("test@example.com")형태로 비밀번호 없이 엔티티를 생성하고 있습니다.
다른 서비스 로직(로그인, 암호 정책 검사 등)과의 일관성을 위해Member.builder().rawPassword(...)등을 사용해 실제 비밀번호 필드를 채워 두는 편이 좋습니다.src/test/java/com/stcom/smartmealtable/service/BudgetServiceCompleteIntegrationTest.java (1)
249-256:LocalDate.now()/YearMonth.now()사용으로 인한 플래키 테스트 위험
호출 시점이 자정을 경계로 넘어가면 서비스 내부 시각과 단정 시각이 달라질 수 있습니다.Clock을 주입하거나 테스트에서 고정 시각을 사용해 안정성을 확보하세요.Also applies to: 269-275
src/test/java/com/stcom/smartmealtable/service/BudgetServiceAdditionalIntegrationTest2.java (1)
84-93: 주간 예산 결과 정렬 가정이 명시적이지 않습니다
서비스가 날짜 오름차순으로 반환한다는 계약이 문서화되어 있지 않으면 인덱스-기반 단정이 깨질 수 있습니다.
- 서비스 스펙에 정렬 보장을 명시하거나
- 테스트에서
sorted()후 검증하는 방식으로 변경을 권장합니다.src/main/java/com/stcom/smartmealtable/web/controller/MemberProfileController.java (1)
13-13: 와일드카드 import(*) 사용은 지양해주세요
정확한 클래스를 명시하면 IDE 자동 정리 및 리팩터링 시 충돌을 줄일 수 있습니다.src/test/java/com/stcom/smartmealtable/service/TermServiceIntegrationTest.java (1)
66-76: 리플렉션으로 내부 필드를 설정하는 것은 유지보수성을 해칩니다
엔티티에 빌더/팩토리 메서드를 추가해 테스트 코드에서 리플렉션을 제거하세요. 이는 코드 가독성과 리팩터링 안정성을 높입니다.src/test/java/com/stcom/smartmealtable/service/SocialAccountServiceAdditionalIntegrationTest.java (2)
35-36: @Rollback 애노테이션은 불필요합니다클래스 레벨에
@Transactional이 선언되어 있으므로 각 테스트는 기본적으로 롤백됩니다. 메소드 수준에 별도로@Rollback을 추가하면 중복 선언이 됩니다.
52-57: 검증 범위가 부족합니다 – refreshToken·만료시간도 함께 확인하세요토큰 갱신 로직을 검증할 때 access token 한 가지만 확인하고 있습니다.
refreshToken,tokenExpiresAt도 함께 검증하면 회귀를 더 확실히 방지할 수 있습니다.-assertThat(updated.getAccessToken()).isEqualTo("new"); +assertThat(updated.getAccessToken()).isEqualTo("new"); +assertThat(updated.getRefreshToken()).isEqualTo("new_r"); +assertThat(updated.getTokenExpiresAt()).isAfter(LocalDateTime.now());src/test/java/com/stcom/smartmealtable/service/LoginServiceCompleteIntegrationTest.java (2)
150-155: 토큰 만료 시각 검증 추가 권장Access/Refresh 토큰 값만 확인하고 있어 만료 시각이 제대로 연장되었는지는 알 수 없습니다.
assertThat(updatedAccount.getRefreshToken()).isEqualTo("new_refresh_token"); +assertThat(updatedAccount.getTokenExpiresAt()).isAfter(LocalDateTime.now());
47-84: setup 로직 중복 제거 제안
@BeforeEach가 비교적 무거운 엔티티 저장을 반복합니다.
테스트 수가 증가하면 I/O 비용이 커지므로, 공통 픽스처를@TestInstance(Lifecycle.PER_CLASS)또는@BeforeAll+ 각 테스트에서 필요한 추가 데이터만 준비하는 방식으로 최적화해볼 수 있습니다.src/test/java/com/stcom/smartmealtable/service/LoginServiceAdditionalIntegrationTest.java (2)
60-63: 예외 메시지 검증은 최소화하는 것이 안전합니다구체적인 메시지까지 검증하면 i18n 변경이나 사소한 워딩 수정에도 테스트가 깨집니다.
타입만 검증하거나, 메시지는contains수준으로 완화하는 것을 권장합니다.
138-143: tokenExpiresAt 갱신 여부도 함께 검증하면 좋습니다기존 소셜 계정의 토큰 교체 시 만료 시각까지 변경되는지 확인해 두면 안전합니다.
assertThat(updatedAccount.getRefreshToken()).isEqualTo("new-refresh"); +assertThat(updatedAccount.getTokenExpiresAt()).isAfter(LocalDateTime.now());src/test/java/com/stcom/smartmealtable/repository/MemberCategoryPreferenceRepositoryTest.java (1)
54-60: ReflectionTestUtils 대신 설정자/생성자 사용 권장엔티티 필드 주입에
ReflectionTestUtils를 사용하면 리팩터링 시 취약합니다.
테스트용 생성자·빌더·팩토리 메서드를 제공해 직접 값을 설정하도록 변경해 보세요.src/test/java/com/stcom/smartmealtable/service/MemberProfileServiceAdditionalIntegrationTest.java (1)
5-7: 패키지 네이밍 컨벤션 위반
com.stcom.smartmealtable.domain.Address.Address처럼 대문자 패키지는 자바 컨벤션에서 권장되지 않습니다.
domain.address.Address로 정리하는 것이 가독성과 일관성에 좋습니다.src/test/java/com/stcom/smartmealtable/service/MemberCategoryPreferenceServiceAdditionalIntegrationTest.java (2)
70-79: ReflectionTestUtils 사용은 불필요한 내부 구현 의존을 초래합니다카테고리 이름 세팅을 위해 ReflectionTestUtils 로 private 필드에 직접 접근하고 있습니다.
엔티티에 생성자·빌더·setter 중 하나를 제공해 테스트가 도메인 모델의 캡슐화를 깨지 않도록 해주세요.- category1 = new FoodCategory(); - ReflectionTestUtils.setField(category1, "name", "한식"); + category1 = FoodCategory.builder() + .name("한식") + .build();
121-124: 예외 메시지를 정확히 매치하면 구현 변경에 과도하게 결합됩니다
hasMessage("존재하지 않는 프로필입니다")처럼 전체 문자열을 비교하면
메시지 포맷이 조금만 변해도 테스트가 깨집니다.
hasMessageContaining("존재하지 않는 프로필")정도로 느슨하게 매칭하거나
커스텀 에러 코드를 사용하는 방식을 고려해 주세요.src/main/java/com/stcom/smartmealtable/web/controller/MemberAddressController.java (1)
60-69: 필드 검증 애너테이션이 누락되었습니다
roadAddress,detailAddress,alias는 필수 값처럼 보이나
@NotBlank/@SiZe 등 Bean Validation 애너테이션이 없습니다.
컨트롤러 레이어에서 유효성 검사를 확실히 해 주세요.src/test/java/com/stcom/smartmealtable/service/MemberProfileServiceIntegrationTest.java (1)
46-49: findAll().get(0) 는 데이터 증가 시 오동작할 수 있습니다테스트 픽스처 외에 다른 프로필이 존재할 경우 첫 번째 요소가 원하는 값이 아닐 수 있습니다.
memberId 로 조회하거나 저장 직후 flush 후 ID 로 다시 조회하는 방식이 안전합니다.src/test/java/com/stcom/smartmealtable/service/MemberProfileServiceCompleteIntegrationTest.java (1)
116-119: 예외 메시지의 전체 일치 검증은 변경에 취약합니다여러 테스트에서
hasMessage("존재하지 않는 …")로 전체 문자열을 비교하고 있습니다.
서비스 레이어 메시지가 변경되면 테스트가 무의미하게 실패하므로
hasMessageContaining으로 완화하거나 에러 코드를 사용해 주세요.src/main/java/com/stcom/smartmealtable/web/controller/MemberAccountController.java (1)
38-42: 회원 탈퇴 이후 토큰 무효화·세션 정리 필요
memberService.deleteByMemberId호출 뒤에도 클라이언트 측 액세스/리프레시 토큰은 여전히 유효합니다.
탈퇴 직후 재호출·재인증을 차단하려면 블랙리스트 처리 또는 Spring Security 세션 무효화를 권장합니다.src/main/java/com/stcom/smartmealtable/web/controller/AuthController.java (1)
87-103: DTO 필드에 필수값 애너테이션 추가 권장
password,confirmPassword,fullName및termId,isAgreed에@NotBlank/@NotNull을 부여해 클라이언트 입력 오류를 조기에 차단하는 편이 안전합니다.src/main/java/com/stcom/smartmealtable/web/controller/AuthTokenController.java (1)
80-88: DTO 필드에@NotBlank/@NotNull추가 필요
EmailLoginRequest,SocialLoginRequest,RefreshTokenRequest모두 필수 값이므로 null/빈 문자열 검사를 명시적으로 선언해 주세요.Also applies to: 90-97, 99-103
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (64)
src/main/java/com/stcom/smartmealtable/domain/member/MemberProfile.java(1 hunks)src/main/java/com/stcom/smartmealtable/repository/MemberProfileRepository.java(1 hunks)src/main/java/com/stcom/smartmealtable/service/BudgetService.java(2 hunks)src/main/java/com/stcom/smartmealtable/service/MemberProfileService.java(0 hunks)src/main/java/com/stcom/smartmealtable/service/MemberService.java(1 hunks)src/main/java/com/stcom/smartmealtable/web/controller/AuthController.java(1 hunks)src/main/java/com/stcom/smartmealtable/web/controller/AuthTokenController.java(1 hunks)src/main/java/com/stcom/smartmealtable/web/controller/GroupController.java(1 hunks)src/main/java/com/stcom/smartmealtable/web/controller/LoginController.java(0 hunks)src/main/java/com/stcom/smartmealtable/web/controller/MemberAccountController.java(1 hunks)src/main/java/com/stcom/smartmealtable/web/controller/MemberAddressController.java(1 hunks)src/main/java/com/stcom/smartmealtable/web/controller/MemberBudgetController.java(1 hunks)src/main/java/com/stcom/smartmealtable/web/controller/MemberController.java(2 hunks)src/main/java/com/stcom/smartmealtable/web/controller/MemberPreferenceController.java(1 hunks)src/main/java/com/stcom/smartmealtable/web/controller/MemberProfileController.java(2 hunks)src/main/java/com/stcom/smartmealtable/web/controller/OAuth2Controller.java(0 hunks)src/main/java/com/stcom/smartmealtable/web/controller/SchoolGroupController.java(1 hunks)src/main/java/com/stcom/smartmealtable/web/dto/group/GroupDto.java(1 hunks)src/main/java/com/stcom/smartmealtable/web/dto/group/SchoolGroupCreateRequest.java(1 hunks)src/main/java/com/stcom/smartmealtable/web/dto/group/SchoolGroupUpdateRequest.java(1 hunks)src/test/java/com/stcom/smartmealtable/domain/Budget/BudgetDomainIntegrationTest.java(1 hunks)src/test/java/com/stcom/smartmealtable/domain/group/CompanyGroupTest.java(1 hunks)src/test/java/com/stcom/smartmealtable/domain/group/SchoolGroupTest.java(1 hunks)src/test/java/com/stcom/smartmealtable/repository/AddressEntityRepositoryTest.java(1 hunks)src/test/java/com/stcom/smartmealtable/repository/FoodCategoryRepositoryTest.java(1 hunks)src/test/java/com/stcom/smartmealtable/repository/GroupRepositoryTest.java(1 hunks)src/test/java/com/stcom/smartmealtable/repository/MemberCategoryPreferenceRepositoryTest.java(1 hunks)src/test/java/com/stcom/smartmealtable/repository/MemberProfileRepositoryTest.java(1 hunks)src/test/java/com/stcom/smartmealtable/repository/SocialAccountRepositoryTest.java(1 hunks)src/test/java/com/stcom/smartmealtable/repository/TermAgreementRepositoryTest.java(1 hunks)src/test/java/com/stcom/smartmealtable/repository/TermRepositoryTest.java(1 hunks)src/test/java/com/stcom/smartmealtable/service/BudgetServiceAdditionalIntegrationTest.java(1 hunks)src/test/java/com/stcom/smartmealtable/service/BudgetServiceAdditionalIntegrationTest2.java(1 hunks)src/test/java/com/stcom/smartmealtable/service/BudgetServiceCompleteIntegrationTest.java(1 hunks)src/test/java/com/stcom/smartmealtable/service/BudgetServiceTest.java(0 hunks)src/test/java/com/stcom/smartmealtable/service/GroupServiceAdditionalIntegrationTest.java(1 hunks)src/test/java/com/stcom/smartmealtable/service/GroupServiceCompleteIntegrationTest.java(1 hunks)src/test/java/com/stcom/smartmealtable/service/GroupServiceIntegrationTest.java(1 hunks)src/test/java/com/stcom/smartmealtable/service/GroupServiceTest.java(0 hunks)src/test/java/com/stcom/smartmealtable/service/LoginServiceAdditionalIntegrationTest.java(1 hunks)src/test/java/com/stcom/smartmealtable/service/LoginServiceCompleteIntegrationTest.java(1 hunks)src/test/java/com/stcom/smartmealtable/service/LoginServiceIntegrationTest.java(1 hunks)src/test/java/com/stcom/smartmealtable/service/LoginServiceTest.java(0 hunks)src/test/java/com/stcom/smartmealtable/service/MemberCategoryPreferenceServiceAdditionalIntegrationTest.java(1 hunks)src/test/java/com/stcom/smartmealtable/service/MemberCategoryPreferenceServiceIntegrationTest.java(1 hunks)src/test/java/com/stcom/smartmealtable/service/MemberCategoryPreferenceServiceTest.java(0 hunks)src/test/java/com/stcom/smartmealtable/service/MemberProfileServiceAdditionalIntegrationTest.java(1 hunks)src/test/java/com/stcom/smartmealtable/service/MemberProfileServiceAdditionalIntegrationTest2.java(1 hunks)src/test/java/com/stcom/smartmealtable/service/MemberProfileServiceCompleteIntegrationTest.java(1 hunks)src/test/java/com/stcom/smartmealtable/service/MemberProfileServiceIntegrationTest.java(1 hunks)src/test/java/com/stcom/smartmealtable/service/MemberProfileServiceTest.java(0 hunks)src/test/java/com/stcom/smartmealtable/service/MemberServiceAdditionalIntegrationTest.java(1 hunks)src/test/java/com/stcom/smartmealtable/service/MemberServiceFailureIntegrationTest.java(1 hunks)src/test/java/com/stcom/smartmealtable/service/MemberServiceIntegrationTest.java(1 hunks)src/test/java/com/stcom/smartmealtable/service/MemberServiceTest.java(0 hunks)src/test/java/com/stcom/smartmealtable/service/SocialAccountServiceAdditionalIntegrationTest.java(1 hunks)src/test/java/com/stcom/smartmealtable/service/SocialAccountServiceCompleteIntegrationTest.java(1 hunks)src/test/java/com/stcom/smartmealtable/service/SocialAccountServiceIntegrationTest.java(1 hunks)src/test/java/com/stcom/smartmealtable/service/SocialAccountServiceTest.java(0 hunks)src/test/java/com/stcom/smartmealtable/service/TermServiceAdditionalIntegrationTest.java(1 hunks)src/test/java/com/stcom/smartmealtable/service/TermServiceIntegrationTest.java(1 hunks)src/test/java/com/stcom/smartmealtable/service/TermServiceTest.java(0 hunks)src/test/java/com/stcom/smartmealtable/service/exception/ResourceNotFoundException.java(1 hunks)src/test/java/com/stcom/smartmealtable/web/controller/MemberControllerTest.java(0 hunks)
💤 Files with no reviewable changes (12)
- src/main/java/com/stcom/smartmealtable/service/MemberProfileService.java
- src/test/java/com/stcom/smartmealtable/service/GroupServiceTest.java
- src/main/java/com/stcom/smartmealtable/web/controller/OAuth2Controller.java
- src/main/java/com/stcom/smartmealtable/web/controller/LoginController.java
- src/test/java/com/stcom/smartmealtable/web/controller/MemberControllerTest.java
- src/test/java/com/stcom/smartmealtable/service/MemberServiceTest.java
- src/test/java/com/stcom/smartmealtable/service/LoginServiceTest.java
- src/test/java/com/stcom/smartmealtable/service/TermServiceTest.java
- src/test/java/com/stcom/smartmealtable/service/MemberCategoryPreferenceServiceTest.java
- src/test/java/com/stcom/smartmealtable/service/SocialAccountServiceTest.java
- src/test/java/com/stcom/smartmealtable/service/BudgetServiceTest.java
- src/test/java/com/stcom/smartmealtable/service/MemberProfileServiceTest.java
🧰 Additional context used
🧬 Code Graph Analysis (9)
src/test/java/com/stcom/smartmealtable/repository/TermAgreementRepositoryTest.java (1)
src/test/java/com/stcom/smartmealtable/repository/TermRepositoryTest.java (1)
DataJpaTest(14-57)
src/test/java/com/stcom/smartmealtable/service/LoginServiceIntegrationTest.java (1)
src/main/java/com/stcom/smartmealtable/exception/PasswordFailedExceededException.java (1)
PasswordFailedExceededException(3-12)
src/main/java/com/stcom/smartmealtable/web/dto/group/SchoolGroupUpdateRequest.java (1)
src/main/java/com/stcom/smartmealtable/web/dto/group/SchoolGroupCreateRequest.java (1)
Data(9-24)
src/main/java/com/stcom/smartmealtable/web/controller/SchoolGroupController.java (1)
src/main/java/com/stcom/smartmealtable/web/controller/GroupController.java (1)
RestController(16-39)
src/test/java/com/stcom/smartmealtable/repository/FoodCategoryRepositoryTest.java (1)
src/test/java/com/stcom/smartmealtable/repository/MemberCategoryPreferenceRepositoryTest.java (1)
DataJpaTest(20-84)
src/test/java/com/stcom/smartmealtable/repository/TermRepositoryTest.java (2)
src/test/java/com/stcom/smartmealtable/repository/FoodCategoryRepositoryTest.java (1)
DataJpaTest(15-42)src/test/java/com/stcom/smartmealtable/repository/TermAgreementRepositoryTest.java (1)
DataJpaTest(16-60)
src/test/java/com/stcom/smartmealtable/repository/MemberCategoryPreferenceRepositoryTest.java (2)
src/test/java/com/stcom/smartmealtable/repository/FoodCategoryRepositoryTest.java (1)
DataJpaTest(15-42)src/test/java/com/stcom/smartmealtable/repository/MemberProfileRepositoryTest.java (1)
DataJpaTest(15-52)
src/test/java/com/stcom/smartmealtable/service/SocialAccountServiceAdditionalIntegrationTest.java (1)
src/test/java/com/stcom/smartmealtable/service/SocialAccountServiceIntegrationTest.java (1)
SpringBootTest(15-49)
src/test/java/com/stcom/smartmealtable/service/SocialAccountServiceIntegrationTest.java (1)
src/test/java/com/stcom/smartmealtable/service/SocialAccountServiceAdditionalIntegrationTest.java (1)
SpringBootTest(19-80)
🔇 Additional comments (13)
src/main/java/com/stcom/smartmealtable/web/controller/SchoolGroupController.java (1)
44-48: 삭제 엔드포인트 중복 여부 확인 요청
/api/v1/schools/{id}과/api/v1/groups/{id}두 곳에서 모두groupService.deleteGroup을 호출하고 있습니다. 역할이 겹치면 클라이언트가 어떤 엔드포인트를 사용해야 할지 혼란스러울 수 있으니, 도메인별 책임 구분 또는 하나의 엔드포인트 통합을 검토해 주세요.src/test/java/com/stcom/smartmealtable/service/GroupServiceCompleteIntegrationTest.java (1)
88-92: 예외 메시지의 도메인 용어가 혼동을 줄 수 있습니다현재 테스트는 존재하지 않는 그룹에 대해
"존재하지 않는 회원입니다"라는 메시지를 기대합니다. ‘회원’ 대신 ‘그룹’이 더 적절한 표현이므로, 서비스 구현 또는 테스트 중 한쪽을 수정하세요. 테스트 기준으로 정정 예시:- .hasMessage("존재하지 않는 회원입니다"); + .hasMessage("존재하지 않는 그룹입니다");세 곳 모두 동일하게 반영해야 합니다.
Also applies to: 194-197, 226-230
src/test/java/com/stcom/smartmealtable/domain/Budget/BudgetDomainIntegrationTest.java (1)
135-140: 사용률 0% 검증 개선 👍
stripTrailingZeros()를 이용한 비교로 불필요한 스케일 차이 문제를 제거한 점이 좋습니다. 테스트 안정성이 향상되었습니다.src/main/java/com/stcom/smartmealtable/repository/MemberProfileRepository.java (1)
18-20: EntityGraph 경로 수정 확인 완료
"addressHistory", "group"를 개별 경로로 분리하여 잘못된 JPQL 생성 문제를 해결했습니다. 정상 동작할 것으로 보입니다.src/test/java/com/stcom/smartmealtable/service/MemberServiceFailureIntegrationTest.java (1)
54-62: 플러시 누락 가능성
memberRepository.save(member);이후 바로 동일 트랜잭션에서 조회하므로 현재는 문제없지만, 서비스 메서드가 별도 트랜잭션(예:@Transactional(propagation = REQUIRES_NEW))으로 동작하도록 변경될 경우 테스트가 실패할 수 있습니다.em.flush();추가를 고려해 주세요.src/test/java/com/stcom/smartmealtable/repository/AddressEntityRepositoryTest.java (1)
43-49: 테스트 로직 이상 없음CRUD 흐름이 명확하며 검증 대상도 충분합니다. 추가 의견 없습니다.
src/test/java/com/stcom/smartmealtable/service/LoginServiceIntegrationTest.java (1)
29-46:isNewUser플래그 기대값 검증 재검토 필요
memberService.saveMember()로 이미 회원을 생성한 뒤 로그인하면 기존 회원이므로isNewUser는false가 되어야 자연스럽습니다.
현재 테스트는true를 기대하고 있어 도메인 의도와 불일치할 가능성이 큽니다. 의도된 시나리오(첫 로그인 vs. 기존 로그인)를 확인하고 기대값을 조정하거나 서비스 로직을 점검해 주세요.
또한 메서드 시그니처에throws Exception이 불필요하게 선언되어 있습니다.src/test/java/com/stcom/smartmealtable/service/TermServiceAdditionalIntegrationTest.java (1)
59-71: 예외 메시지 단정식이 구현과 맞는지 확인 필요
필수 약관에 동의해야 합니다메시지를 검증하고 있으나, 실제 서비스 메시지가 변경되면 테스트가 과도하게 깨질 수 있습니다.
비즈니스 메시지가 빈번히 변한다면hasMessageContaining대신 예외 타입만 검증하거나 상수로 관리하는 방법을 고려해 보세요.src/test/java/com/stcom/smartmealtable/service/MemberProfileServiceAdditionalIntegrationTest2.java (1)
24-26:jakarta.transaction.Transactional사용 시 테스트 롤백 동작 확인 필요
Spring Test 는 기본적으로org.springframework.transaction.annotation.Transactional과 연동됩니다. 패키지가 다른 경우 설정에 따라 롤백이 적용되지 않을 수 있으니 의도한 동작인지 확인 바랍니다.src/test/java/com/stcom/smartmealtable/service/LoginServiceCompleteIntegrationTest.java (1)
86-97: isNewUser 플래그 의미 재검토 필요프로필이 없는 기존 회원의 첫 로그인에서
isNewUser가true로 검증되고 있습니다.
플래그가 “신규 회원 여부”를 뜻한다면 기존 회원에게true가 나오지 않아야 합니다. 비즈니스 규칙을 다시 확인해주세요.src/test/java/com/stcom/smartmealtable/service/LoginServiceAdditionalIntegrationTest.java (1)
149-169: 새 소셜 로그인 테스트에서 profileId 기대값 확인신규 회원 생성 시
result.getProfileId()가 null 인지, 아니면 기본 프로필이 자동 생성돼야 하는지 요구사항을 다시 점검해 주세요.src/test/java/com/stcom/smartmealtable/service/MemberProfileServiceAdditionalIntegrationTest.java (1)
68-71: Entity 상태 확인 시 flush/clear 권장삭제 후 같은 트랜잭션 내에서 다시 조회하면 1차 캐시에 남은 엔티티를 볼 위험이 있습니다.
em.flush(); em.clear();후 조회하면 실제 DB 상태를 검증할 수 있습니다.src/main/java/com/stcom/smartmealtable/web/controller/MemberPreferenceController.java (1)
28-43: Java 16Stream#toList()사용 시 런타임 JDK 버전 확인 필요
Stream.toList()는 JDK 16+ API입니다. 운영 환경이 11 / 8 이라면 컴파일조차 되지 않습니다.
JDK 17 사용이 확정되지 않았다면collect(Collectors.toList())로 변경하거나 빌드 툴 체계를 재확인해 주세요.
| @@ -0,0 +1 @@ | |||
|
No newline at end of file |
|||
There was a problem hiding this comment.
🛠️ Refactor suggestion
ResourceNotFoundException 클래스 구현 및 위치 재배치 필요
현재 파일이 src/test/java에 빈 상태로 추가되어 있어 빌드 오류 및 예외 처리가 불가합니다. 실제 예외 클래스는 src/main/java/com/stcom/smartmealtable/service/exception 경로로 이동하고, 아래와 같이 구현을 추가하세요:
+package com.stcom.smartmealtable.service.exception;
+
+public class ResourceNotFoundException extends RuntimeException {
+ public ResourceNotFoundException(String message) {
+ super(message);
+ }
+}Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In
src/test/java/com/stcom/smartmealtable/service/exception/ResourceNotFoundException.java
at line 1, the file is empty and incorrectly placed in the test directory
causing build errors. Move this file to
src/main/java/com/stcom/smartmealtable/service/exception and implement the
ResourceNotFoundException class properly as a custom exception extending
RuntimeException or Exception, including constructors for message and cause to
enable correct exception handling.
| @Data | ||
| @AllArgsConstructor |
There was a problem hiding this comment.
기본 생성자(@NoArgsConstructor) 부재로 JSON 역직렬화 실패 가능성
Spring MVC/Jackson은 기본 생성자가 없으면 @RequestBody 바인딩 시 객체를 생성하지 못해 HttpMessageNotReadableException 이 발생할 수 있습니다. @AllArgsConstructor 만으로는 해결되지 않으므로 기본 생성자를 추가하거나 @JsonCreator 기반 생성자 방식을 명시해야 합니다.
import lombok.AllArgsConstructor;
+import lombok.NoArgsConstructor;
...
@Data
@AllArgsConstructor
+@NoArgsConstructor
public class SchoolGroupUpdateRequest {📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| @Data | |
| @AllArgsConstructor | |
| import lombok.AllArgsConstructor; | |
| import lombok.NoArgsConstructor; | |
| ... | |
| @Data | |
| @AllArgsConstructor | |
| @NoArgsConstructor | |
| public class SchoolGroupUpdateRequest { | |
| // existing fields and methods | |
| } |
🤖 Prompt for AI Agents
In
src/main/java/com/stcom/smartmealtable/web/dto/group/SchoolGroupUpdateRequest.java
around lines 9 to 10, the class lacks a no-argument constructor which can cause
JSON deserialization failures in Spring MVC/Jackson. To fix this, add a
no-argument constructor by annotating the class with @NoArgsConstructor or
explicitly define a default constructor. This will ensure proper object creation
during @RequestBody binding and prevent HttpMessageNotReadableException.
| org.springframework.test.util.ReflectionTestUtils.setField(group, "address", address); | ||
| org.springframework.test.util.ReflectionTestUtils.setField(group, "name", "테스트IT"); | ||
| org.springframework.test.util.ReflectionTestUtils.setField(group, "industryType", IndustryType.IT); | ||
|
|
There was a problem hiding this comment.
🛠️ Refactor suggestion
ReflectionTestUtils 남용은 테스트 유지보수성을 저하시킴
프로덕션 코드에 적절한 생성자/팩터리를 추가해 테스트에서 리플렉션을 제거하는 편이 안전하고 가독성이 높습니다.
🤖 Prompt for AI Agents
In src/test/java/com/stcom/smartmealtable/domain/group/CompanyGroupTest.java
around lines 20 to 23, ReflectionTestUtils is used to set private fields
directly, which harms test maintainability. To fix this, add appropriate
constructors or factory methods in the production CompanyGroup class that allow
setting these fields during object creation, then update the test to use these
constructors or factories instead of reflection.
| import lombok.AllArgsConstructor; | ||
| import lombok.Data; | ||
|
|
||
| @Data | ||
| @AllArgsConstructor | ||
| public class SchoolGroupCreateRequest { |
There was a problem hiding this comment.
🛠️ Refactor suggestion
역직렬화를 위해 기본 생성자 추가 필요
@AllArgsConstructor만 선언되어 있어 Jackson이 DTO를 역직렬화할 때 기본 생성자를 찾지 못해 HttpMessageNotReadableException이 발생할 수 있습니다. Lombok의 @NoArgsConstructor(access = AccessLevel.PROTECTED) 등을 함께 선언해 주세요.
@Data
-@AllArgsConstructor
+@AllArgsConstructor
+@NoArgsConstructor(access = AccessLevel.PROTECTED)Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In
src/main/java/com/stcom/smartmealtable/web/dto/group/SchoolGroupCreateRequest.java
around lines 6 to 11, the class only has @AllArgsConstructor, so Jackson cannot
find a default constructor during deserialization, causing
HttpMessageNotReadableException. Add Lombok's @NoArgsConstructor with access =
AccessLevel.PROTECTED to provide a protected no-args constructor for
deserialization.
| @TestConfiguration | ||
| static class FakeKakaoConfig { | ||
| @Bean | ||
| KakaoAddressApiService kakaoAddressApiService() { | ||
| return new KakaoAddressApiService() { | ||
| @Override | ||
| public Address createAddressFromRequest(AddressRequest requestDto) { | ||
| return Address.builder() | ||
| .roadAddress(requestDto.getRoadAddress()) | ||
| .detailAddress(requestDto.getDetailAddress()) | ||
| .build(); | ||
| } | ||
| }; | ||
| } | ||
| } |
There was a problem hiding this comment.
테스트용 Bean 주입 충돌 가능성
FakeKakaoConfig에서 동일 타입의 Bean을 추가로 등록합니다. 본 애플리케이션 컨텍스트에 KakaoAddressApiService Bean이 이미 존재한다면 NoUniqueBeanDefinitionException이 발생합니다. @Primary, @Qualifier 또는 @MockBean을 활용해 충돌을 명시적으로 방지해 주세요.
🤖 Prompt for AI Agents
In
src/test/java/com/stcom/smartmealtable/service/GroupServiceAdditionalIntegrationTest.java
around lines 30 to 44, the FakeKakaoConfig defines a KakaoAddressApiService bean
that may conflict with an existing bean of the same type in the application
context, causing NoUniqueBeanDefinitionException. To fix this, annotate the
FakeKakaoConfig's KakaoAddressApiService bean with @Primary or use @Qualifier to
distinguish it, or alternatively replace it with @MockBean in the test to
explicitly avoid bean injection conflicts.
| @PostMapping("/signup/terms") | ||
| public ApiResponse<Void> agreeTerms(@UserContext MemberDto memberDto, | ||
| @RequestBody List<TermAgreementRequest> agreements) { | ||
| termService.agreeTerms( | ||
| memberDto.getMemberId(), | ||
| agreements.stream() | ||
| .map(dto -> new TermAgreementRequestDto(dto.getTermId(), dto.getIsAgreed())) | ||
| .toList() | ||
| ); | ||
| return ApiResponse.createSuccessWithNoContent(); | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
약관 동의 로직의 입력 검증 부족
agreements 리스트에 대한 @Valid·@NotNull 검증이 없습니다. null 리스트 혹은 요소 누락 시 의도치 않은 DB 상태가 발생할 수 있습니다.
🤖 Prompt for AI Agents
In src/main/java/com/stcom/smartmealtable/web/controller/AuthController.java
around lines 69 to 79, the agreeTerms method lacks input validation for the
agreements list. Add @Valid and @NotNull annotations to the agreements parameter
to ensure the list is not null and its elements are validated. This prevents
unintended database states caused by null or incomplete agreement data.
| @PathVariable("date") @DateTimeFormat(iso = ISO.DATE) String date, | ||
| @RequestParam("limit") Long limit) { | ||
| budgetService.registerDefaultDailyBudgetBy(memberDto.getProfileId(), limit, LocalDate.parse(date)); | ||
| return ApiResponse.createSuccessWithNoContent(); | ||
| } | ||
|
|
||
| @PatchMapping("/daily/{date}") | ||
| public ApiResponse<Void> editDailyBudget(@UserContext MemberDto memberDto, | ||
| @PathVariable("date") @DateTimeFormat(iso = ISO.DATE) String date, | ||
| @RequestParam("limit") Long limit) { | ||
| budgetService.editDailyBudgetCustom(memberDto.getProfileId(), LocalDate.parse(date), limit); | ||
| return ApiResponse.createSuccessWithNoContent(); |
There was a problem hiding this comment.
limit 파라미터 검증 누락
예산 한도는 음수값이 들어와선 안 됩니다. @Positive(또는 @PositiveOrZero) 애너테이션을 적용해 런타임 검사를 추가해 주세요.
-@RequestParam("limit") Long limit
+@RequestParam("limit") @Positive Long limitAlso applies to: 78-90
🤖 Prompt for AI Agents
In
src/main/java/com/stcom/smartmealtable/web/controller/MemberBudgetController.java
at lines 39-50 and 78-90, the limit parameter lacks validation to prevent
negative values. Add the @Positive or @PositiveOrZero annotation to the limit
parameter in both methods to enforce runtime validation that disallows negative
budget limits.
| public ApiResponse<DailyBudgetResponse> dailyBudgetByDate(@UserContext MemberDto memberDto, | ||
| @PathVariable("date") @DateTimeFormat(iso = ISO.DATE) String date) { | ||
| DailyBudget dailyBudget = budgetService.getDailyBudgetBy(memberDto.getProfileId(), LocalDate.parse(date)); | ||
| return ApiResponse.createSuccess(DailyBudgetResponse.of(dailyBudget)); | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
String 파라미터를 다시 파싱하는 불필요한 오버헤드
@PathVariable LocalDate date 로 직접 바인딩하면 LocalDate.parse(...) 호출이 불필요하며, 포맷 오류도 Spring MVC가 400으로 처리해 줍니다.
-@PathVariable("date") @DateTimeFormat(iso = ISO.DATE) String date
+@PathVariable("date") @DateTimeFormat(iso = ISO.DATE) LocalDate date서비스 호출부에서도 LocalDate.parse(date) 제거하세요.
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In
src/main/java/com/stcom/smartmealtable/web/controller/MemberBudgetController.java
around lines 31 to 35, the method parameter date is currently a String and then
parsed to LocalDate inside the method, causing unnecessary overhead. Change the
@PathVariable parameter type from String to LocalDate and remove the
LocalDate.parse(date) call in the service invocation. This lets Spring MVC
handle the date parsing and format validation automatically.
| @PostMapping("/logout") | ||
| public ApiResponse<Void> logout(HttpServletRequest request) { | ||
| String jwt = request.getHeader("Authorization"); | ||
| if (Objects.nonNull(jwt)) { | ||
| jwtBlacklistService.addToBlacklist(jwt); | ||
| } | ||
| return ApiResponse.createSuccessWithNoContent(); | ||
| } |
There was a problem hiding this comment.
Bearer 토큰 파싱 오류 가능성
Authorization 헤더 전체를 블랙리스트에 저장하면 "Bearer " 접두사가 포함돼 검증 시 매치에 실패할 수 있습니다. 접두사를 제거하고 공백·대소문자를 방어적으로 처리하세요.
-String jwt = request.getHeader("Authorization");
-if (Objects.nonNull(jwt)) {
- jwtBlacklistService.addToBlacklist(jwt);
-}
+String bearer = request.getHeader("Authorization");
+if (StringUtils.hasText(bearer) && bearer.startsWith("Bearer ")) {
+ String jwt = bearer.substring(7);
+ jwtBlacklistService.addToBlacklist(jwt);
+}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| @PostMapping("/logout") | |
| public ApiResponse<Void> logout(HttpServletRequest request) { | |
| String jwt = request.getHeader("Authorization"); | |
| if (Objects.nonNull(jwt)) { | |
| jwtBlacklistService.addToBlacklist(jwt); | |
| } | |
| return ApiResponse.createSuccessWithNoContent(); | |
| } | |
| @PostMapping("/logout") | |
| public ApiResponse<Void> logout(HttpServletRequest request) { | |
| String bearer = request.getHeader("Authorization"); | |
| if (StringUtils.hasText(bearer) && bearer.startsWith("Bearer ")) { | |
| String jwt = bearer.substring(7); | |
| jwtBlacklistService.addToBlacklist(jwt); | |
| } | |
| return ApiResponse.createSuccessWithNoContent(); | |
| } |
🤖 Prompt for AI Agents
In
src/main/java/com/stcom/smartmealtable/web/controller/AuthTokenController.java
around lines 51 to 58, the logout method adds the entire Authorization header
value to the blacklist, including the "Bearer " prefix. To fix this, parse the
header to remove the "Bearer " prefix in a case-insensitive manner and trim any
whitespace before adding the token to the blacklist. This ensures the stored
token matches the format used during validation.
| @PostMapping("/token/refresh") | ||
| public ApiResponse<AccessTokenRefreshResponse> refreshAccessToken(@UserContext MemberDto memberDto, | ||
| @RequestBody RefreshTokenRequest request) { | ||
| String accessToken = jwtTokenService.createAccessToken(memberDto.getMemberId(), memberDto.getProfileId()); | ||
| return ApiResponse.createSuccess(new AccessTokenRefreshResponse(accessToken, 3600, "Bearer")); | ||
| } |
There was a problem hiding this comment.
리프레시 토큰 검증이 전혀 이루어지지 않습니다
refreshAccessToken 는 전달된 리프레시 토큰을 무시하고 새 액세스 토큰을 발급합니다. 악성 사용자가 만료된/위조된 토큰으로도 무제한 재발급이 가능해집니다.
-@PostMapping("/token/refresh")
-public ApiResponse<AccessTokenRefreshResponse> refreshAccessToken(@UserContext MemberDto memberDto,
- @RequestBody RefreshTokenRequest request) {
- String accessToken = jwtTokenService.createAccessToken(memberDto.getMemberId(), memberDto.getProfileId());
+@PostMapping("/token/refresh")
+public ApiResponse<AccessTokenRefreshResponse> refreshAccessToken(@RequestBody RefreshTokenRequest request) {
+ jwtTokenService.validateRefreshToken(request.getRefreshToken()); // 서명·만료 검증
+ String accessToken = jwtTokenService.createAccessTokenFromRefresh(request.getRefreshToken());
return ApiResponse.createSuccess(new AccessTokenRefreshResponse(accessToken, 3600, "Bearer"));
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| @PostMapping("/token/refresh") | |
| public ApiResponse<AccessTokenRefreshResponse> refreshAccessToken(@UserContext MemberDto memberDto, | |
| @RequestBody RefreshTokenRequest request) { | |
| String accessToken = jwtTokenService.createAccessToken(memberDto.getMemberId(), memberDto.getProfileId()); | |
| return ApiResponse.createSuccess(new AccessTokenRefreshResponse(accessToken, 3600, "Bearer")); | |
| } | |
| @PostMapping("/token/refresh") | |
| public ApiResponse<AccessTokenRefreshResponse> refreshAccessToken(@RequestBody RefreshTokenRequest request) { | |
| jwtTokenService.validateRefreshToken(request.getRefreshToken()); // 서명·만료 검증 | |
| String accessToken = jwtTokenService.createAccessTokenFromRefresh(request.getRefreshToken()); | |
| return ApiResponse.createSuccess(new AccessTokenRefreshResponse(accessToken, 3600, "Bearer")); | |
| } |
🤖 Prompt for AI Agents
In
src/main/java/com/stcom/smartmealtable/web/controller/AuthTokenController.java
around lines 73 to 78, the refreshAccessToken method does not validate the
provided refresh token before issuing a new access token. To fix this, add logic
to verify the refresh token's validity and authenticity using jwtTokenService or
equivalent before creating and returning a new access token. If the refresh
token is invalid or expired, respond with an appropriate error instead of
issuing a new token.
Summary by CodeRabbit
신규 기능
기능 개선 및 변경
버그 수정
테스트
문서화 및 기타