Skip to content

[Refactor] 매물 페이지 #88

Merged
MeongW merged 40 commits intodevelopfrom
refactor/homeCreate
Aug 17, 2025
Merged

[Refactor] 매물 페이지 #88
MeongW merged 40 commits intodevelopfrom
refactor/homeCreate

Conversation

@seonju21
Copy link
Contributor

@seonju21 seonju21 commented Aug 17, 2025

🚀 관련 이슈

🔑 주요 변경사항

  • 매물 메인페이지 필터링, 페이지네이션
  • 매물 상세 페이지 상세 정보 표시

✔️ 체크 리스트

  • Merge 하려는 브랜치가 올바른가? (main branch에 실수로 PR 생성 금지)
  • Merge 하려는 PR 및 Commit들을 로컬에서 실행했을 때 에러가 발생하지 않았는가?
  • 라벨을 등록했는가?
  • 리뷰어를 지정했는가?

📢 To Reviewers

📸 스크린샷 or 실행영상

↗️ 개선 사항

Summary by CodeRabbit

  • 신기능
    • 매물 생성/수정 시 이미지 업로드 지원(멀티파트).
    • 고급 검색 추가(가격/면적/층수/반려동물/주차/정렬·페이지네이션).
    • 내 매물 조회, 좋아요 토글, 좋아요 목록 조회 제공.
    • 시설 카테고리/항목 조회 엔드포인트 추가.
  • 변경
    • 매물 상세/목록 API 개편: 경로·파라미터 정리, ID 타입 Integer로 통일, 페이지 기본값(1, 21).
    • 컨트롤러 구조를 인터페이스+구현으로 분리.
    • 폼 데이터의 날짜 입력(LocalDate) 자동 변환 지원.
  • 제거
    • 신고, 조회수 증가, 분리된 좋아요/취소 등 일부 기존 엔드포인트 정리/통합.

leeedongjaee and others added 30 commits August 11, 2025 11:39
- HomeCreateRequestDto, HomeUpdateRequestDto 신규 생성
- HomeCreateDTO에서 imageUrls 필드 제거 (파일 업로드만 지원)
- HomeImageVO 필드명 수정 (ImageUrl → imageUrl)
- Swagger 어노테이션 추가 및 예제값 설정
- selectHomeFacilitiesByHomeDetailId 중복 제거
- selectHomeMaintenanceFeesByHomeId 중복 제거
- selectFacilityCategories 중복 제거
- selectFacilityItemsByCategoryId 중복 제거
- incrementViewCount 중복 제거
- HomeController 인터페이스 정의
- HomeControllerImpl 구현 클래스 생성
- API 정의와 비즈니스 로직 분리
- 테스트 가능성 및 유지보수성 향상
- 불필요한 디버깅 로그 제거
- 이미지 업로드 로직 단순화
- S3 경로 처리 개선 (home/{homeId}/{fileName} 형식)
- 에러 처리 및 로깅 메시지 최적화
- updateHome 메서드에 이미지 파라미터 추가
- 매물 수정 시 이미지 업로드 기능 지원
- 메서드 호출 공백 일관성 개선
- 코드 포맷팅 통일
- LocalDateTime.toLocalDate() 호출 제거
- buildDate가 이미 LocalDate 타입으로 처리되도록 수정
- HomeCreateRequestDto/HomeUpdateRequestDto import 경로 수정
- buildDate 타입을 LocalDateTime에서 LocalDate로 변경
- 필드명 매핑 수정 (bathroomCount -> bathroomCnt, isParkingAvailable -> isParking)
- MaintenanceFeeDTO를 MaintenanceFeeItem으로 변환하는 로직 추가
- Integer를 Long으로 변환하는 로직 추가
- multipart/form-data에서 LocalDate 타입 변환 지원
- ISO_LOCAL_DATE 포맷 (yyyy-MM-dd) 처리
- 빈 문자열 처리 지원
@seonju21 seonju21 self-assigned this Aug 17, 2025
@seonju21 seonju21 added the ♻️ refactor 리팩토링 작업 label Aug 17, 2025
@coderabbitai
Copy link

coderabbitai bot commented Aug 17, 2025

Walkthrough

홈 도메인 전반을 DTO/VO 기반으로 재구성하고, 컨트롤러를 인터페이스+구현 클래스로 분리했습니다. 매퍼(Java/XML), 서비스(API/구현), DTO/VO, enum을 대폭 변경·추가했으며, 이미지 업로드(S3 서비스 인터페이스)·시설/유지비/좋아요·검색/카운트 기능을 통합했습니다. ServletConfig에 LocalDate 컨버터가 추가되었습니다.

Changes

Cohort / File(s) Summary
Controller API 분리/확장
src/main/java/.../home/controller/HomeController.java, .../home/controller/HomeControllerImpl.java
컨트롤러를 인터페이스/구현으로 분리. 엔드포인트 전면 재정의(생성/조회/목록/검색/수정/삭제/상태/내 매물/좋아요/시설 카테고리·아이템). 인증 파라미터 전환(Authentication), ID Long→Integer, 멀티파트 처리 추가.
Service 재설계
.../home/service/HomeService.java, .../home/service/HomeServiceImpl.java
DTO 중심 시그니처로 전환(HomeCreateDTO/HomeResponseDTO/HomeSearchDTO). 생성시 이미지 업로드, 검색/카운트, 상태변경, 좋아요 토글, 시설 조회 추가. 구 메서드 제거/대체.
Mapper API/SQL 전면 개편
.../home/mapper/HomeMapper.java, src/main/resources/.../home/mapper/HomeMapper.xml
VO 타입 기반으로 CRUD 세분화(홈/상세/이미지/시설/유지비/좋아요). 조건검색·카운트·페이징 추가. 반환/파라미터 타입 정비 및 다수 쿼리 추가·개명.
DTO 추가/교체
.../home/dto/HomeCreateDTO.java, .../home/dto/HomeCreateRequestDto.java, .../home/dto/HomeUpdateRequestDto.java, .../home/dto/HomeResponseDTO.java, .../home/dto/HomeSearchDTO.java
생성/갱신 요청 DTO, 응답 DTO, 검색 DTO 신설. 이미지/시설/유지비 필드 포함. 빌더/롬복 적용.
VO 신설 및 교체
.../home/vo/HomeVO.java, .../home/vo/HomeDetailVO.java, .../home/vo/HomeImageVO.java, .../home/vo/HomeFacilityVO.java, .../home/vo/HomeMaintenanceFeeVO.java, .../home/vo/HomeLikeVO.java, .../home/vo/FacilityCategory.java, .../home/vo/FacilityItem.java
홈/상세/이미지/시설/유지비/좋아요/시설분류 VO 도입. 데이터 액세스 계층 표준화.
구 DTO/VO/Response 제거
.../home/vo/HomeRegisterVO.java, .../home/dto/response/HomeResponseDto.java, .../home/dto/response/MaintenanceFeeItemResponseDto.java, .../home/dto/response/FacilityResponseDto.java, .../home/dto/request/HomeCreateRequestDto.java, .../home/dto/request/HomeUpdateRequestDto.java, .../home/dto/request/HomeReportRequestDto.java
레거시 VO/DTO/리포트 제거 및 새로운 DTO/VO로 대체.
Enum 변경
.../home/enums/HomeStatus.java, .../home/enums/HomeDirection.java
HomeStatus: SOLD→CONTRACTED, getKey() 추가. HomeDirection: getKey() 추가.
AI 분석 서비스 영향
.../fraud/service/AiFraudAnalyzerService.java
HomeRegisterVO→HomeVO 전환, 홈 조회 예외 처리 방식 변경(try-catch), 일부 필드 매핑 제거.
설정
.../global/config/ServletConfig.java
LocalDate 문자열 변환기 등록(addFormatters).

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Client
  participant HomeControllerImpl
  participant HomeService
  participant HomeMapper
  participant S3 as S3Service

  Client->>HomeControllerImpl: POST /api/homes (multipart form)
  HomeControllerImpl->>HomeService: createHome(createDTO, images, userId)
  HomeService->>HomeMapper: insertHome(HomeVO)
  HomeService->>HomeMapper: insertHomeDetail(HomeDetailVO)
  HomeService->>HomeMapper: insertHomeFacility(...)*N
  HomeService->>HomeMapper: insertHomeMaintenanceFee(...)*M
  alt images present
    HomeService->>S3: upload(image)*K
    S3-->>HomeService: url
    HomeService->>HomeMapper: insertHomeImage(url)*K
  end
  HomeService-->>HomeControllerImpl: homeId
  HomeControllerImpl-->>Client: ApiResponse(homeId)
Loading
sequenceDiagram
  autonumber
  participant Client
  participant HomeControllerImpl
  participant HomeService
  participant HomeMapper

  Client->>HomeControllerImpl: GET /api/homes/search?...
  HomeControllerImpl->>HomeService: searchHomes(searchDTO)
  HomeService->>HomeMapper: selectHomeListByCondition(searchDTO)
  HomeMapper-->>HomeService: List<HomeVO>
  loop for each home
    HomeService->>HomeMapper: selectHomeImagesByHomeId(homeId)
  end
  HomeService-->>HomeControllerImpl: List<HomeResponseDTO>
  HomeControllerImpl-->>Client: PageResponse(payload, counts)
Loading
sequenceDiagram
  autonumber
  participant Client
  participant HomeControllerImpl
  participant HomeService
  participant HomeMapper

  Client->>HomeControllerImpl: POST /api/homes/{id}/like
  HomeControllerImpl->>HomeService: toggleHomeLike(userId, homeId)
  HomeService->>HomeMapper: selectHomeLikeExists(userId, homeId)
  alt exists
    HomeService->>HomeMapper: deleteHomeLike(userId, homeId)
  else not exists
    HomeService->>HomeMapper: insertHomeLike(userId, homeId)
  end
  HomeService-->>HomeControllerImpl: Void
  HomeControllerImpl-->>Client: ApiResponse(Void)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Assessment against linked issues

Objective Addressed Explanation
계약 전 채팅 로직 구현, API 구현, 채팅 리스트 API (#1) 채팅 관련 컨트롤러/서비스/엔티티 변경 없음.
SSE 기반 채팅 알림 구현 (#1) SSE 엔드포인트/설정/브로드캐스트 로직 미포함.
WebSocket+STOMP 메시징 기반 송수신 (#1) WebSocket 설정/핸들러/토픽 관련 코드 미포함.
로그인 사용자 기반 채팅방 조회 (#1) 채팅방/메시지 조회 로직 및 매퍼 없음.

Assessment against linked issues: Out-of-scope changes

Code Change Explanation
홈 도메인 전면 리팩토링 및 API 확장 (src/main/java/org/scoula/domain/home/controller/, .../service/, .../mapper/, .../vo/, .../dto/*, src/main/resources/.../HomeMapper.xml — 전체 파일들) 링크된 이슈는 채팅 모듈에 관한 사항이며, 홈 CRUD/검색/이미지/시설/좋아요/상태/카운트 관련 변경은 범위를 벗어남.
AiFraudAnalyzerService 홈 조회/매핑 변경 (src/main/java/org/scoula/domain/fraud/service/AiFraudAnalyzerService.java — 해당 메서드 전체) 채팅 기능과 무관한 AI 사기 분석 로직 변경으로, 이슈 목표와 직접적 연관 없음.
ServletConfig LocalDate 컨버터 추가 (src/main/java/org/scoula/global/config/ServletConfig.java — addFormatters 메서드 추가) 채팅 알림/웹소켓 설정과 무관한 폼 데이터 변환 설정으로, 이슈 범위를 벗어남.

Possibly related PRs

Suggested reviewers

  • MeongW
  • Whatdoyumin

Poem

새 집 목록 폴짝폴짝, VO 들고 뛰어가요 🐇
컨트롤러 둘로 나뉘고, DTO 꽃이 피었죠
시설·사진 싱그럽게, 좋아요도 살짝 톡!
맵퍼는 길을 넓히고, 상태는 계약 완료!
오늘도 코드밭에 바람, 리뷰는 가볍게 쓱—

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor/homeCreate

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 20

🔭 Outside diff range comments (1)
src/main/java/org/scoula/domain/fraud/service/AiFraudAnalyzerService.java (1)

310-323: home 조회 null 처리 누락: NPE 위험 (homeId null 케이스 포함)

findHomeById가 null을 반환해도 예외가 발생하지 않아, 아래의 home.get...에서 NPE가 발생합니다. 또한 homeId 자체가 null일 수 있는 경우도 선제 차단 필요합니다.

다음과 같이 방어 코드를 추가해 주세요.

       Long homeId = request.getHomeId();
-      HomeVO home = null;
-      try {
-          home = homeMapper.findHomeById(homeId);
-      } catch (Exception e) {
-          throw new BusinessException(FraudErrorCode.INVALID_HOME_ID);
-      }
+      if (homeId == null) {
+          throw new BusinessException(FraudErrorCode.INVALID_HOME_ID);
+      }
+      HomeVO home;
+      try {
+          home = homeMapper.findHomeById(homeId);
+      } catch (Exception e) {
+          throw new BusinessException(FraudErrorCode.INVALID_HOME_ID);
+      }
+      if (home == null) {
+          throw new BusinessException(FraudErrorCode.INVALID_HOME_ID);
+      }
       request.setAddress(home.getAddr1() + " " + home.getAddr2());
       request.setPropertyPrice(home.getDepositPrice());
       request.setMonthlyRent(home.getMonthlyRent() != null ? home.getMonthlyRent() : 0);
       request.setLeaseType(home.getLeaseType().toString());
       request.setResidenceType(home.getResidenceType().toString());
       request.setRegisteredUserName(home.getUserName());
🧹 Nitpick comments (32)
src/main/java/org/scoula/domain/home/enums/HomeStatus.java (1)

26-39: from(...)이 라벨만 허용 — enum 키(AVAILABLE/RESERVED/CONTRACTED)도 허용하도록 확장 제안

현재는 "입주가능/예약중/계약완료" 라벨만 역직렬화됩니다. 키 문자열(예: "CONTRACTED")도 허용하면 프론트·DB·테스트 데이터의 혼용을 안전하게 흡수할 수 있습니다.

아래처럼 키 매칭(대소문자 무시)을 추가해 주세요.

 @JsonCreator(mode = JsonCreator.Mode.DELEGATING)
 public static HomeStatus from(String value) {
-    if (value == null || value.trim().isEmpty()) {
-        throw new IllegalArgumentException("매물 상태 값이 null이거나 비어있습니다.");
-    }
-
-    String trimmedValue = value.trim();
-    for (HomeStatus status : values()) {
-        if (status.description.equals(trimmedValue)) {
-            return status;
-        }
-    }
-    throw new IllegalArgumentException("알 수 없는 매물 상태입니다: " + value);
+    if (value == null || value.trim().isEmpty()) {
+        throw new IllegalArgumentException("매물 상태 값이 null이거나 비어있습니다.");
+    }
+    final String trimmed = value.trim();
+    for (HomeStatus status : values()) {
+        // 1) 한글 라벨 매칭
+        if (status.getDescription().equals(trimmed)) {
+            return status;
+        }
+        // 2) enum 키 매칭 (대소문자 무시)
+        if (status.name().equalsIgnoreCase(trimmed)) {
+            return status;
+        }
+    }
+    throw new IllegalArgumentException("알 수 없는 매물 상태입니다: " + value);
 }
src/main/java/org/scoula/global/config/ServletConfig.java (1)

81-94: LocalDate 바인딩: Converter 대신 표준 Registrar 사용 권장(간결/일관)

Spring 표준 Registrar를 사용하면 ISO 형식 바인딩을 일관되게 적용하고, 코드가 간결해집니다. 현재 구현도 동작은 하지만 유지보수 관점에서 Registrar가 더 낫습니다.

아래처럼 교체를 제안합니다.

   @Override
   public void addFormatters(FormatterRegistry registry) {
-      // LocalDate converter for form data
-      registry.addConverter(
-              new Converter<String, LocalDate>() {
-                  @Override
-                  public LocalDate convert(String source) {
-                      if (source == null || source.trim().isEmpty()) {
-                          return null;
-                      }
-                      return LocalDate.parse(source, DateTimeFormatter.ISO_LOCAL_DATE);
-                  }
-              });
+      // LocalDate: ISO-8601 (yyyy-MM-dd)
+      org.springframework.format.datetime.standard.DateTimeFormatterRegistrar registrar =
+              new org.springframework.format.datetime.standard.DateTimeFormatterRegistrar();
+      registrar.setUseIsoFormat(true);
+      registrar.registerFormatters(registry);
   }

추가로, Converter 방식을 유지한다면 잘못된 날짜 형식에 대한 예외 메시지를 명확히 하여 400 Bad Request로 매핑되도록 하는 것도 좋습니다(바인딩 오류 가독성 향상).

-                      return LocalDate.parse(source, DateTimeFormatter.ISO_LOCAL_DATE);
+                      try {
+                          return LocalDate.parse(source, DateTimeFormatter.ISO_LOCAL_DATE);
+                      } catch (java.time.format.DateTimeParseException e) {
+                          throw new IllegalArgumentException("유효하지 않은 날짜 형식입니다(예: 2024-12-31): " + source, e);
+                      }

참고: Registrar 사용 시에는 별도 예외 처리가 기본 바인딩 오류로 위임됩니다.

src/main/java/org/scoula/domain/home/vo/HomeImageVO.java (1)

5-10: Lombok 중복 사용(@DaTa + @Getter/@Setter) — 불필요한 중복 제거 권장

@DaTa가 이미 getter/setter/equals/hashCode/toString를 생성합니다. @Getter/@Setter는 중복이므로 제거하면 가독성과 일관성이 좋아집니다.

-@Data
-@Getter
-@Setter
+@Data
 @AllArgsConstructor
 @NoArgsConstructor
 @Builder
 public class HomeImageVO {
src/main/java/org/scoula/domain/home/vo/FacilityCategory.java (1)

5-10: Lombok 중복 사용(@DaTa + @Getter/@Setter) — 불필요한 중복 제거 권장

여기도 @DaTa만으로 충분합니다.

-@Data
-@Getter
-@Setter
+@Data
 @AllArgsConstructor
 @NoArgsConstructor
 @Builder
 public class FacilityCategory {
src/main/java/org/scoula/domain/home/vo/FacilityItem.java (1)

5-10: Lombok 중복 사용(@DaTa + @Getter/@Setter) — 불필요한 중복 제거 권장

중복 어노테이션 제거로 간결화해 주세요.

-@Data
-@Getter
-@Setter
+@Data
 @AllArgsConstructor
 @NoArgsConstructor
 @Builder
 public class FacilityItem {
src/main/java/org/scoula/domain/home/vo/HomeFacilityVO.java (1)

3-10: Lombok 중복 사용 및 와일드카드 import 정리 제안

@DaTa는 @Getter/@Setter를 포함하므로 중복입니다. 또한 와일드카드 import는 유지보수성 측면에서 지양하는 것이 좋습니다.

아래처럼 정리 권장:

-import lombok.*;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;

-@Getter
-@Setter
src/main/java/org/scoula/domain/home/dto/HomeCreateDTO.java (2)

66-73: 중복 중첩 DTO 제거: MaintenanceFeeDTO 공용 클래스로 추출 권장

Create/Update DTO 양쪽에 동일한 중첩 클래스가 중복 정의되어 있습니다. 상위 패키지의 공용 DTO로 추출하면 중복 제거와 스키마 일관성 유지에 유리합니다.

예시(신규 파일):

// src/main/java/org/scoula/domain/home/dto/MaintenanceFeeDTO.java
package org.scoula.domain.home.dto;

import lombok.*;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class MaintenanceFeeDTO {
    private Integer maintenanceId;
    private Integer fee;
}

그 후 본 파일과 Update DTO에서는 List<MaintenanceFeeDTO>를 import 하여 사용하세요.


23-65: 유효성 검증 추가 고려

주요 필드에 Bean Validation을 부여하면 조기 검증과 문서화 품질이 향상됩니다. 실제 요구사항에 따라 최소한 아래 항목 검토를 권장합니다.

  • addr1: @notblank
  • residenceType, leaseType: @NotNull
  • depositPrice, monthlyRent, maintenanceFee: @NotNull, @PositiveOrZero
  • roomCnt, bathroomCnt, homeFloor, buildingTotalFloors: @PositiveOrZero
  • 면적 필드(Float): @positive (또는 Double/BigDecimal로 전환 고려)
src/main/java/org/scoula/domain/home/dto/HomeUpdateRequestDto.java (1)

25-25: DTO 명명 컨벤션 통일 필요: HomeUpdateRequestDto → HomeUpdateRequestDTO

아래 파일들에서 클래스명과 파일명을 HomeUpdateRequestDTO로 변경하고, 관련 import 및 사용처도 일괄 업데이트해주세요.

  • src/main/java/org/scoula/domain/home/dto/HomeUpdateRequestDto.java
    • 클래스 선언(25행)
    • 파일명 → HomeUpdateRequestDTO.java
  • src/main/java/org/scoula/domain/home/controller/HomeController.java
    • import 선언(10행)
    • 메서드 시그니처 내 사용(@ModelAttribute, 59행)
  • src/main/java/org/scoula/domain/home/controller/HomeControllerImpl.java
    • import 선언(12행)
    • 메서드 시그니처 내 사용(150행)
-public class HomeUpdateRequestDto {
+public class HomeUpdateRequestDTO {
src/main/java/org/scoula/domain/home/enums/HomeDirection.java (1)

27-29: from(String) 개선 제안: 키/설명 모두 허용

현재 @JsonCreator는 한글 설명값만 허용합니다. 클라이언트가 E/SE... 키를 보낼 가능성까지 고려해 키와 설명을 모두 수용하도록 개선하면 호환성이 좋아집니다.

예시 구현(참고용):

@JsonCreator
public static HomeDirection from(String value) {
    if (value == null) throw new IllegalArgumentException("Unknown home direction: null");
    // 키 시도
    try {
        return HomeDirection.valueOf(value.trim().toUpperCase());
    } catch (IllegalArgumentException ignore) {
        // 설명 매칭
        for (HomeDirection direction : HomeDirection.values()) {
            if (direction.getDescription().equals(value)) {
                return direction;
            }
        }
    }
    throw new IllegalArgumentException("Unknown home direction: " + value);
}
src/main/java/org/scoula/domain/home/vo/HomeLikeVO.java (1)

5-12: Lombok 중복 사용 및 와일드카드 import 정리 제안

@DaTa는 @Getter/@Setter를 포함합니다. 와일드카드 import도 명시 import로 정리하는 것이 좋습니다.

-import lombok.*;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;

-@Getter
-@Setter
src/main/java/org/scoula/domain/home/vo/HomeVO.java (2)

11-16: Lombok 어노테이션 중복 (@DaTa + @Getter/@Setter)

@DaTa가 이미 getter/setter/toString/equals/hashCode 등을 생성하므로 @Getter/@Setter는 제거 가능합니다. 중복은 해롭진 않지만 노이즈를 줄이는 편이 좋습니다.

적용 예:

 @Data
-@Getter
-@Setter
 @AllArgsConstructor
 @NoArgsConstructor
 @Builder

32-37: 면적 타입 Float 사용은 정밀도 문제 유발 가능성 (Double/BigDecimal 고려)

면적(supplyArea, exclusiveArea, area)은 UI/계약서 표기에 정밀도가 중요한 경우가 많습니다. Float 보다는 Double(또는 회계적 정밀도가 필요하면 BigDecimal) 사용을 권장합니다.

적용 예:

-      private Float supplyArea;
+      private Double supplyArea;
...
-      private Float exclusiveArea;
+      private Double exclusiveArea;
...
-      private Float area;
+      private Double area;
src/main/java/org/scoula/domain/home/vo/HomeDetailVO.java (2)

9-14: Lombok 어노테이션 중복 (@DaTa + @Getter/@Setter)

@DaTa로 충분하며 @Getter/@Setter는 불필요합니다.

적용 예:

 @Data
-@Getter
-@Setter
 @AllArgsConstructor
 @NoArgsConstructor
 @Builder

25-27: 면적 Float 정밀도 고려 및 필드 중복 설계 점검

  • 면적(area)은 Float 대신 Double/BigDecimal 고려를 권장합니다.
  • area/landCategory/homeFloor 등이 HomeVO에도 존재합니다. 도메인 분리가 의도된 것인지(요약 vs 상세) 명확하면 좋겠습니다.

도메인 경계 확인: HomeVO와 HomeDetailVO 간 중복 필드가 설계적으로 의도된 것인지 확인해 주세요.

src/main/java/org/scoula/domain/home/dto/HomeCreateRequestDto.java (1)

98-99: 이미지 업로드 제약 검토(개수/용량/확장자)

API 요청 DTO 차원에서 @Size(max = N) 등 기본 제약을 두는 것이 운영 안정성에 유리합니다. 서비스 레벨의 S3 업로드 정책과 함께 정합적으로 적용을 권장합니다.

       @ApiModelProperty(value = "매물 이미지 목록")
-      private List<MultipartFile> images;
+      @Size(max = 10)
+      private List<MultipartFile> images;
src/main/java/org/scoula/domain/fraud/service/AiFraudAnalyzerService.java (1)

565-571: AI 요청 전문(JSON) 디버그 로그는 PII 노출 가능성 있음

전체 요청을 그대로 로그로 남기면 주소/이름 등 민감정보가 포함될 수 있습니다. 운영 환경에서는 마스킹/필드 선택 로깅 또는 로그 레벨 하향(TRACE) 전환을 권장합니다.

적용 예(요약 필드만 출력 또는 비활성화):

-                  String requestJson = mapper.writeValueAsString(aiRequest);
-                  log.debug("[디버깅] AI 서버 전송 데이터: {}", requestJson);
+                  // 민감정보 최소화: 요약 정보만 로깅
+                  log.debug("[디버깅] AI 서버 전송 요약 - homeId: {}, leaseType: {}, residenceType: {}",
+                      LogSanitizerUtil.sanitizeValue(aiRequest.getHomeId()),
+                      LogSanitizerUtil.sanitizeValue(aiRequest.getLeaseType()),
+                      LogSanitizerUtil.sanitizeValue(aiRequest.getResidenceType()));
src/main/java/org/scoula/domain/home/dto/HomeSearchDTO.java (2)

46-49: 페이지네이션 파라미터 검증 추가 제안 (@min, 상한 설정)

page/size에 대한 유효성 검증이 없어 음수/과도한 값이 들어오면 성능/오류를 유발할 수 있습니다. Bean Validation으로 최소/최대 값을 제한하세요.

다음 어노테이션 추가를 제안합니다(Controller의 @validated와 함께 사용 권장):

-      private Integer page = 1;
-      private Integer size = 21;
+      @javax.validation.constraints.Min(1)
+      private Integer page = 1;
+      @javax.validation.constraints.Min(1)
+      @javax.validation.constraints.Max(100)
+      private Integer size = 21;

필요 시 javax.validation.constraints.* 임포트를 파일 상단에 추가하세요.


55-57: 오프셋 계산 방어 로직 추가

page가 0 이하일 경우 음수 오프셋이 발생합니다. 방어적으로 0 이상으로 고정하세요.

-          return (page - 1) * size;
+          return Math.max(0, (page - 1) * size);
src/main/java/org/scoula/domain/home/dto/HomeResponseDTO.java (2)

35-35: 오탈자: maintenaceFee → maintenanceFee (API/도메인 전반 오염 가능)

필드명이 오탈자로 고정되어 있습니다. 외부 API/DB 매핑에 퍼지기 전에 정정하는 것을 권장합니다.

리네이밍에는 범위가 크므로 단계적 적용을 권장합니다:

  • DTO 필드명을 maintenanceFee로 변경하고, Jackson 사용 시 @JsonAlias("maintenaceFee")로 하위호환 유지
  • Service/VO/Mapper의 동일 오탈자도 일괄 정정
    원하시면 전체 리팩터링용 변경 스크립트/PR 패치를 도와드리겠습니다.

54-59: 컬렉션 필드 null 회피를 위한 기본값 권장

facilities/maintenanceFees/imageUrls가 null이면 클라이언트에서 방어 코드가 필요합니다. 빌더 기본값으로 빈 리스트를 제공하세요.

-      private List<FacilityItem> facilities;
+      @Builder.Default
+      private List<FacilityItem> facilities = new java.util.ArrayList<>();
       private String description;
-      private List<HomeMaintenanceFeeVO> maintenanceFees;
+      @Builder.Default
+      private List<HomeMaintenanceFeeVO> maintenanceFees = new java.util.ArrayList<>();
 
-      private List<String> imageUrls;
+      @Builder.Default
+      private List<String> imageUrls = new java.util.ArrayList<>();
src/main/java/org/scoula/domain/home/service/HomeService.java (2)

12-59: 서비스 네이밍 컨벤션 미준수 (Interface 접미사 누락)

가이드라인에 따르면 서비스는 *ServiceInterface/*ServiceImpl 패턴을 사용해야 합니다. 현재 인터페이스명이 HomeService입니다.

  • 인터페이스를 HomeServiceInterface로 리네임하고 구현체는 HomeServiceImpl 유지
  • 컨트롤러/구현체 의존성 주입 시 타입도 함께 수정
    큰 변경이므로 범위 조정 필요 시 알려주세요.

34-36: status를 String으로 받는 인터페이스는 타입 안정성 부족 — Enum 사용 권장

상태 전환은 HomeStatus로 한정하는 것이 안전합니다. 유효하지 않은 문자열 유입을 컴파일 타임에 차단하세요.

-      void updateHomeStatus(Integer homeId, String status, Integer userId);
+      void updateHomeStatus(Integer homeId, HomeStatus status, Integer userId);

컨트롤러 @RequestParam도 Enum으로 매핑하거나, 문자열 입력 시 Enum 변환/검증 로직을 추가해야 합니다.

src/main/java/org/scoula/domain/home/controller/HomeControllerImpl.java (5)

31-35: Swagger 문서화 어노테이션 누락 (팀 러닝/가이드라인 불일치)

컨트롤러 엔드포인트에 Swagger 어노테이션이 없습니다. 팀 가이드라인/러닝에 따라 @Tag/@operation 등을 추가해 주세요.

예시(클래스 및 한두 개 메서드에 적용, 나머지 동일 패턴으로 확장):

 @Log4j2
 @RestController
 @RequestMapping("/api/homes")
 @RequiredArgsConstructor
+@io.swagger.v3.oas.annotations.tags.Tag(name = "Homes", description = "매물 API")
 public class HomeControllerImpl implements HomeController {
       @Override
       @PostMapping(consumes = "multipart/form-data")
+      @io.swagger.v3.oas.annotations.Operation(summary = "매물 등록", description = "매물과 이미지를 등록합니다.")
       public ResponseEntity<ApiResponse<Integer>> createHome(
               @Valid @RequestPart HomeCreateRequestDto requestDto, Authentication authentication) {
       @Override
       @GetMapping("/{homeId}")
+      @io.swagger.v3.oas.annotations.Operation(summary = "매물 상세 조회")
       public ResponseEntity<ApiResponse<HomeResponseDTO>> getHome(@PathVariable Integer homeId) {

필요 시 공통 ApiResponse 스키마도 @ApiResponses로 기술해 주세요.


110-124: 페이지 응답 래퍼 불일치 — 모든 엔드포인트에서 ApiResponse 일원화 권장

가이드라인상 모든 응답을 ApiResponse로 감싸야 합니다. 현재 getHomeList는 PageResponse를 직접 반환합니다.

-      public ResponseEntity<PageResponse<HomeResponseDTO>> getHomeList(
+      public ResponseEntity<ApiResponse<PageResponse<HomeResponseDTO>>> getHomeList(
               @RequestParam(defaultValue = "1") int page,
               @RequestParam(defaultValue = "21") int size) {
@@
-          return ResponseEntity.ok(PageResponse.of(homes, pageRequest, totalCount));
+          return ResponseEntity.ok(ApiResponse.success(PageResponse.of(homes, pageRequest, totalCount)));
       }

searchHomes에도 동일하게 적용해 주세요.


126-144: searchHomes도 ApiResponse 래퍼 적용 필요

위 코멘트와 동일한 이유로 ApiResponse로 래핑하여 일관성 유지하세요.

-      public ResponseEntity<PageResponse<HomeResponseDTO>> searchHomes(
+      public ResponseEntity<ApiResponse<PageResponse<HomeResponseDTO>>> searchHomes(
               @ModelAttribute HomeSearchDTO searchDTO) {
@@
-          return ResponseEntity.ok(PageResponse.of(homes, pageRequest, totalCount));
+          return ResponseEntity.ok(ApiResponse.success(PageResponse.of(homes, pageRequest, totalCount)));
       }

45-48: 민감/대용량 필드 로깅 레벨 하향 (PII/노이즈 방지)

요청 DTO 전체와 description을 INFO로 찍으면 PII/불필요한 로그가 축적될 수 있습니다. DEBUG로 내리거나 요약 정보만 로깅하세요.

-          log.info("매물 등록 요청 데이터: {}", requestDto);
-          log.info("컨트롤러에서 확인한 description 값: {}", requestDto.getDescription());
+          log.debug("매물 등록 요청 수신: addr1={}, residenceType={}, images={}",
+                  requestDto.getAddr1(), requestDto.getResidenceType(),
+                  requestDto.getImages() != null ? requestDto.getImages().size() : 0);

223-236: status 파라미터 Enum 매핑 또는 검증 필요

문자열 status는 유효성 문제가 있습니다. HomeStatus로 직접 매핑하거나, 문자열을 Enum으로 검증/변환 후 서비스에 전달하세요.

Enum 직접 매핑 예시:

-      public ResponseEntity<ApiResponse<Void>> updateHomeStatus(
-              @PathVariable Integer homeId,
-              @RequestParam String status,
+      public ResponseEntity<ApiResponse<Void>> updateHomeStatus(
+              @PathVariable Integer homeId,
+              @RequestParam HomeStatus status,
               Authentication authentication) {
@@
-          homeService.updateHomeStatus(homeId, status, userId);
+          homeService.updateHomeStatus(homeId, status, userId);

컨트롤러 상단에 HomeStatus 임포트를 추가하세요.

src/main/java/org/scoula/domain/home/service/HomeServiceImpl.java (2)

41-43: 과도한 상세 데이터 로깅 — PII/로그 노이즈 이슈

DTO/상세 VO 전체와 description을 INFO로 출력 중입니다. DEBUG로 내리거나 마스킹/요약하세요.

-          log.info("서비스에서 받은 DTO: {}", createDTO);
-          log.info("서비스에서 확인한 description 값: {}", createDTO.getDescription());
+          log.debug("서비스에서 받은 DTO 요약: addr1={}, residenceType={}, images={}",
+                  createDTO.getAddr1(), createDTO.getResidenceType(), images != null ? images.size() : 0);
@@
-          log.info("DB에 저장할 HomeDetailVO 객체: {}", homeDetail);
-          log.info("최종 DB 저장 직전의 description 값: {}", homeDetail.getDescription());
+          log.debug("DB 저장 직전 요약: homeFloor={}, isPet={}, isParking={}",
+                  homeDetail.getHomeFloor(), homeDetail.getIsPet(), homeDetail.getIsParking());

Also applies to: 89-92


137-140: 주석과 실제 S3 키 경로 불일치 (혼동 유발 가능)

주석은 uploads/home/...를 언급하나 실제 코드는 home/... 경로를 사용합니다. 주석을 코드와 일치시키세요.

-                              // S3에 업로드 (uploads/home/{homeId}/{fileName} 형식으로 저장됨)
+                              // S3에 업로드 (home/{homeId}/{fileName} 형식으로 저장됨)
src/main/java/org/scoula/domain/home/controller/HomeController.java (1)

70-75: 매물 상태(status) 문자열 대신 Enum 사용 고려

상태 값은 도메인 Enum(HomeStatus 등)으로 한정하는 것이 타입 안정성과 스키마 문서화(스웨거) 측면에서 유리합니다. 서비스/매퍼에서도 enum.name() 혹은 TypeHandler로 매핑하면 안전합니다.

src/main/resources/org/scoula/domain/home/mapper/HomeMapper.xml (1)

83-86: EXISTS 서브쿼리 표기 간단화 제안(선택 사항)

성능상 차이는 미미하나 관례적으로 EXISTS (SELECT 1 ...) 표기 권장입니다. 가독성 개선 목적의 제안입니다.

-        WHERE h.home_status = 'AVAILABLE' AND EXISTS(select * from home_identity_verification as hiv where h.home_id = hiv.home_id)
+        WHERE h.home_status = 'AVAILABLE'
+          AND EXISTS (SELECT 1 FROM home_identity_verification hiv WHERE hiv.home_id = h.home_id)
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between e9763cb and ed9a86e.

📒 Files selected for processing (30)
  • src/main/java/org/scoula/domain/fraud/service/AiFraudAnalyzerService.java (2 hunks)
  • src/main/java/org/scoula/domain/home/controller/HomeController.java (1 hunks)
  • src/main/java/org/scoula/domain/home/controller/HomeControllerImpl.java (1 hunks)
  • src/main/java/org/scoula/domain/home/dto/HomeCreateDTO.java (1 hunks)
  • src/main/java/org/scoula/domain/home/dto/HomeCreateRequestDto.java (1 hunks)
  • src/main/java/org/scoula/domain/home/dto/HomeResponseDTO.java (1 hunks)
  • src/main/java/org/scoula/domain/home/dto/HomeSearchDTO.java (1 hunks)
  • src/main/java/org/scoula/domain/home/dto/HomeUpdateRequestDto.java (1 hunks)
  • src/main/java/org/scoula/domain/home/dto/request/HomeCreateRequestDto.java (0 hunks)
  • src/main/java/org/scoula/domain/home/dto/request/HomeReportRequestDto.java (0 hunks)
  • src/main/java/org/scoula/domain/home/dto/request/HomeUpdateRequestDto.java (0 hunks)
  • src/main/java/org/scoula/domain/home/dto/response/FacilityResponseDto.java (0 hunks)
  • src/main/java/org/scoula/domain/home/dto/response/HomeResponseDto.java (0 hunks)
  • src/main/java/org/scoula/domain/home/dto/response/MaintenanceFeeItemResponseDto.java (0 hunks)
  • src/main/java/org/scoula/domain/home/enums/HomeDirection.java (1 hunks)
  • src/main/java/org/scoula/domain/home/enums/HomeStatus.java (2 hunks)
  • src/main/java/org/scoula/domain/home/mapper/HomeMapper.java (1 hunks)
  • src/main/java/org/scoula/domain/home/service/HomeService.java (1 hunks)
  • src/main/java/org/scoula/domain/home/service/HomeServiceImpl.java (1 hunks)
  • src/main/java/org/scoula/domain/home/vo/FacilityCategory.java (1 hunks)
  • src/main/java/org/scoula/domain/home/vo/FacilityItem.java (1 hunks)
  • src/main/java/org/scoula/domain/home/vo/HomeDetailVO.java (1 hunks)
  • src/main/java/org/scoula/domain/home/vo/HomeFacilityVO.java (1 hunks)
  • src/main/java/org/scoula/domain/home/vo/HomeImageVO.java (1 hunks)
  • src/main/java/org/scoula/domain/home/vo/HomeLikeVO.java (1 hunks)
  • src/main/java/org/scoula/domain/home/vo/HomeMaintenanceFeeVO.java (1 hunks)
  • src/main/java/org/scoula/domain/home/vo/HomeRegisterVO.java (0 hunks)
  • src/main/java/org/scoula/domain/home/vo/HomeVO.java (1 hunks)
  • src/main/java/org/scoula/global/config/ServletConfig.java (2 hunks)
  • src/main/resources/org/scoula/domain/home/mapper/HomeMapper.xml (1 hunks)
💤 Files with no reviewable changes (7)
  • src/main/java/org/scoula/domain/home/dto/request/HomeCreateRequestDto.java
  • src/main/java/org/scoula/domain/home/dto/response/FacilityResponseDto.java
  • src/main/java/org/scoula/domain/home/dto/response/MaintenanceFeeItemResponseDto.java
  • src/main/java/org/scoula/domain/home/vo/HomeRegisterVO.java
  • src/main/java/org/scoula/domain/home/dto/request/HomeReportRequestDto.java
  • src/main/java/org/scoula/domain/home/dto/request/HomeUpdateRequestDto.java
  • src/main/java/org/scoula/domain/home/dto/response/HomeResponseDto.java
🧰 Additional context used
📓 Path-based instructions (5)
src/main/java/org/scoula/**/controller/*Controller{,Impl}.java

📄 CodeRabbit Inference Engine (CLAUDE.md)

Use interface-implementation pattern for controllers: *Controller.java (interface) and *ControllerImpl.java (implementation)

Files:

  • src/main/java/org/scoula/domain/home/controller/HomeControllerImpl.java
  • src/main/java/org/scoula/domain/home/controller/HomeController.java
src/main/java/org/scoula/**/controller/**/*.java

📄 CodeRabbit Inference Engine (CLAUDE.md)

src/main/java/org/scoula/**/controller/**/*.java: All controller endpoints should return a consistent ApiResponse<T> wrapper
Add Swagger annotations to controller endpoints for API documentation

Files:

  • src/main/java/org/scoula/domain/home/controller/HomeControllerImpl.java
  • src/main/java/org/scoula/domain/home/controller/HomeController.java
src/main/java/org/scoula/**/service/*Service{Interface,Impl}.java

📄 CodeRabbit Inference Engine (CLAUDE.md)

Use interface-implementation pattern for services: *ServiceInterface.java (interface) and *ServiceImpl.java (implementation)

Files:

  • src/main/java/org/scoula/domain/home/service/HomeServiceImpl.java
src/main/java/org/scoula/domain/*/mapper/*Mapper.java

📄 CodeRabbit Inference Engine (CLAUDE.md)

src/main/java/org/scoula/domain/*/mapper/*Mapper.java: Define MyBatis mapper interfaces under src/main/java/org/scoula/domain/*/mapper/*Mapper.java
Annotate MyBatis mapper interfaces with @Mapper

Files:

  • src/main/java/org/scoula/domain/home/mapper/HomeMapper.java
src/main/resources/org/scoula/domain/*/mapper/*Mapper.xml

📄 CodeRabbit Inference Engine (CLAUDE.md)

src/main/resources/org/scoula/domain/*/mapper/*Mapper.xml: Place MyBatis XML mappers at src/main/resources/org/scoula/domain/*/mapper/*Mapper.xml
Name MyBatis XML mappers *Mapper.xml to match their corresponding *Mapper.java interfaces

Files:

  • src/main/resources/org/scoula/domain/home/mapper/HomeMapper.xml
🧠 Learnings (5)
📚 Learning: 2025-08-12T03:59:30.512Z
Learnt from: CR
PR: ITZEEP/backend#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-12T03:59:30.512Z
Learning: Applies to src/main/java/org/scoula/**/controller/*Controller{,Impl}.java : Use interface-implementation pattern for controllers: `*Controller.java` (interface) and `*ControllerImpl.java` (implementation)

Applied to files:

  • src/main/java/org/scoula/domain/home/controller/HomeControllerImpl.java
📚 Learning: 2025-08-12T03:59:30.512Z
Learnt from: CR
PR: ITZEEP/backend#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-12T03:59:30.512Z
Learning: Applies to src/main/java/org/scoula/**/controller/**/*.java : Add Swagger annotations to controller endpoints for API documentation

Applied to files:

  • src/main/java/org/scoula/domain/home/controller/HomeControllerImpl.java
📚 Learning: 2025-08-12T03:59:30.512Z
Learnt from: CR
PR: ITZEEP/backend#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-12T03:59:30.512Z
Learning: Applies to src/main/java/org/scoula/domain/*/mapper/*Mapper.java : Define MyBatis mapper interfaces under `src/main/java/org/scoula/domain/*/mapper/*Mapper.java`

Applied to files:

  • src/main/java/org/scoula/domain/home/mapper/HomeMapper.java
  • src/main/resources/org/scoula/domain/home/mapper/HomeMapper.xml
📚 Learning: 2025-08-12T03:59:30.512Z
Learnt from: CR
PR: ITZEEP/backend#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-12T03:59:30.512Z
Learning: Applies to src/main/resources/org/scoula/domain/*/mapper/*Mapper.xml : Name MyBatis XML mappers `*Mapper.xml` to match their corresponding `*Mapper.java` interfaces

Applied to files:

  • src/main/resources/org/scoula/domain/home/mapper/HomeMapper.xml
📚 Learning: 2025-08-12T03:59:30.512Z
Learnt from: CR
PR: ITZEEP/backend#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-12T03:59:30.512Z
Learning: Applies to src/main/resources/org/scoula/domain/*/mapper/*Mapper.xml : Place MyBatis XML mappers at `src/main/resources/org/scoula/domain/*/mapper/*Mapper.xml`

Applied to files:

  • src/main/resources/org/scoula/domain/home/mapper/HomeMapper.xml
🧬 Code Graph Analysis (15)
src/main/java/org/scoula/domain/home/dto/HomeCreateDTO.java (5)
src/main/java/org/scoula/domain/home/dto/HomeResponseDTO.java (1)
  • Data (18-61)
src/main/java/org/scoula/domain/home/vo/HomeDetailVO.java (1)
  • Data (9-28)
src/main/java/org/scoula/domain/home/dto/HomeSearchDTO.java (1)
  • Data (13-62)
src/main/java/org/scoula/domain/home/vo/HomeVO.java (1)
  • Data (11-40)
src/main/java/org/scoula/domain/home/vo/HomeImageVO.java (1)
  • Data (5-15)
src/main/java/org/scoula/domain/home/vo/FacilityCategory.java (6)
src/main/java/org/scoula/domain/home/vo/HomeDetailVO.java (1)
  • Data (9-28)
src/main/java/org/scoula/domain/home/vo/HomeVO.java (1)
  • Data (11-40)
src/main/java/org/scoula/domain/home/vo/HomeImageVO.java (1)
  • Data (5-15)
src/main/java/org/scoula/domain/home/vo/HomeFacilityVO.java (1)
  • Data (5-14)
src/main/java/org/scoula/domain/home/vo/FacilityItem.java (1)
  • Data (5-15)
src/main/java/org/scoula/domain/home/vo/HomeLikeVO.java (1)
  • Data (7-17)
src/main/java/org/scoula/domain/home/vo/HomeVO.java (3)
src/main/java/org/scoula/domain/home/vo/FacilityItem.java (1)
  • Data (5-15)
src/main/java/org/scoula/domain/home/vo/HomeLikeVO.java (1)
  • Data (7-17)
src/main/java/org/scoula/domain/home/vo/HomeMaintenanceFeeVO.java (1)
  • Data (5-15)
src/main/java/org/scoula/domain/home/vo/HomeImageVO.java (8)
src/main/java/org/scoula/domain/home/vo/HomeDetailVO.java (1)
  • Data (9-28)
src/main/java/org/scoula/domain/home/dto/HomeCreateDTO.java (2)
  • Data (17-74)
  • Data (66-73)
src/main/java/org/scoula/domain/home/vo/HomeVO.java (1)
  • Data (11-40)
src/main/java/org/scoula/domain/home/vo/FacilityCategory.java (1)
  • Data (5-14)
src/main/java/org/scoula/domain/home/vo/HomeFacilityVO.java (1)
  • Data (5-14)
src/main/java/org/scoula/domain/home/vo/FacilityItem.java (1)
  • Data (5-15)
src/main/java/org/scoula/domain/home/vo/HomeLikeVO.java (1)
  • Data (7-17)
src/main/java/org/scoula/domain/home/vo/HomeMaintenanceFeeVO.java (1)
  • Data (5-15)
src/main/java/org/scoula/domain/home/dto/HomeCreateRequestDto.java (2)
src/main/java/org/scoula/domain/home/dto/HomeUpdateRequestDto.java (2)
  • ApiModel (20-128)
  • ApiModel (113-127)
src/main/java/org/scoula/domain/home/dto/HomeCreateDTO.java (2)
  • Data (17-74)
  • Data (66-73)
src/main/java/org/scoula/domain/home/dto/HomeUpdateRequestDto.java (2)
src/main/java/org/scoula/domain/home/dto/HomeCreateRequestDto.java (2)
  • ApiModel (20-119)
  • ApiModel (104-118)
src/main/java/org/scoula/domain/home/dto/HomeCreateDTO.java (2)
  • Data (17-74)
  • Data (66-73)
src/main/java/org/scoula/domain/home/vo/HomeLikeVO.java (6)
src/main/java/org/scoula/domain/home/vo/HomeDetailVO.java (1)
  • Data (9-28)
src/main/java/org/scoula/domain/home/vo/HomeVO.java (1)
  • Data (11-40)
src/main/java/org/scoula/domain/home/vo/HomeImageVO.java (1)
  • Data (5-15)
src/main/java/org/scoula/domain/home/vo/FacilityCategory.java (1)
  • Data (5-14)
src/main/java/org/scoula/domain/home/vo/HomeFacilityVO.java (1)
  • Data (5-14)
src/main/java/org/scoula/domain/home/vo/FacilityItem.java (1)
  • Data (5-15)
src/main/java/org/scoula/domain/home/vo/HomeFacilityVO.java (1)
src/main/java/org/scoula/domain/home/vo/FacilityCategory.java (1)
  • Data (5-14)
src/main/java/org/scoula/domain/home/vo/HomeDetailVO.java (9)
src/main/java/org/scoula/domain/home/dto/HomeResponseDTO.java (1)
  • Data (18-61)
src/main/java/org/scoula/domain/home/dto/HomeCreateDTO.java (2)
  • Data (17-74)
  • Data (66-73)
src/main/java/org/scoula/domain/home/vo/HomeVO.java (1)
  • Data (11-40)
src/main/java/org/scoula/domain/home/vo/HomeImageVO.java (1)
  • Data (5-15)
src/main/java/org/scoula/domain/home/vo/FacilityCategory.java (1)
  • Data (5-14)
src/main/java/org/scoula/domain/home/vo/HomeFacilityVO.java (1)
  • Data (5-14)
src/main/java/org/scoula/domain/home/vo/FacilityItem.java (1)
  • Data (5-15)
src/main/java/org/scoula/domain/home/vo/HomeLikeVO.java (1)
  • Data (7-17)
src/main/java/org/scoula/domain/home/vo/HomeMaintenanceFeeVO.java (1)
  • Data (5-15)
src/main/java/org/scoula/domain/home/dto/HomeSearchDTO.java (2)
src/main/java/org/scoula/domain/home/dto/HomeResponseDTO.java (1)
  • Data (18-61)
src/main/java/org/scoula/domain/home/dto/HomeCreateDTO.java (2)
  • Data (17-74)
  • Data (66-73)
src/main/java/org/scoula/domain/home/vo/FacilityItem.java (2)
src/main/java/org/scoula/domain/home/vo/FacilityCategory.java (1)
  • Data (5-14)
src/main/java/org/scoula/domain/home/vo/HomeFacilityVO.java (1)
  • Data (5-14)
src/main/java/org/scoula/domain/home/controller/HomeControllerImpl.java (1)
src/main/java/org/scoula/global/common/exception/BusinessException.java (1)
  • BusinessException (4-21)
src/main/java/org/scoula/domain/home/dto/HomeResponseDTO.java (3)
src/main/java/org/scoula/domain/home/vo/HomeDetailVO.java (1)
  • Data (9-28)
src/main/java/org/scoula/domain/home/dto/HomeCreateDTO.java (2)
  • Data (17-74)
  • Data (66-73)
src/main/java/org/scoula/domain/home/dto/HomeSearchDTO.java (1)
  • Data (13-62)
src/main/java/org/scoula/domain/home/service/HomeServiceImpl.java (2)
src/main/java/org/scoula/global/common/exception/BusinessException.java (1)
  • BusinessException (4-21)
src/main/java/org/scoula/domain/home/controller/HomeControllerImpl.java (1)
  • Log4j2 (31-326)
src/main/java/org/scoula/domain/home/controller/HomeController.java (1)
src/main/java/org/scoula/domain/chat/controller/AiClauseImproveTestController.java (1)
  • Api (24-151)
🔇 Additional comments (14)
src/main/java/org/scoula/domain/home/enums/HomeStatus.java (2)

22-24: getKey() 추가 👍 — API에서 key/label 이원화에 유용

라벨(@jsonvalue)과 키(getKey)의 동시 제공으로 직렬화/표시 분리가 용이해졌습니다. 다른 enum에도 동일 패턴을 일관 적용하면 클라이언트 측 사용성이 좋아집니다.


9-9: CONTRACTED로 상수명 변경 — 자동 검색 결과 미발견, 추가 확인 필요

자동화 스크립트로 HomeStatus.SOLD 참조 및 "SOLD" 하드코딩은 발견되지 않았습니다.
다만 아래 영역에서 수동으로 한 번 더 점검해 주세요:

  • DB 마이그레이션·시드 데이터(SQL)
  • 매퍼/XML 파일 내 문자열
  • 프론트엔드 코드(.js/.ts/.vue) 내 하드코딩
  • 외부 API 연동 문서·페이로드에서 enum key 직접 사용 여부
src/main/java/org/scoula/global/config/ServletConfig.java (1)

74-79: 전역 ObjectMapper에 JavaTimeModule 및 날짜 직렬화 옵션이 이미 적용되어 있습니다

  • src/main/java/org/scoula/global/config/RootConfig.java
    • objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
    • objectMapper.registerModule(new JavaTimeModule())
  • ServletConfig.configureMessageConverters에서 주입된 동일한 objectMapper를 사용하므로 LocalDate 직렬화/역직렬화가 올바르게 처리됩니다

추가 조치 없이도 JSON에서 LocalDate가 ISO-8601 문자열로 직렬화됩니다.

src/main/java/org/scoula/domain/home/dto/HomeUpdateRequestDto.java (2)

62-76: 필드 스키마 불일치 확인 요청: area/landCategory 업데이트 필요 여부

Create DTO에는 area, landCategory가 존재하지만, Update DTO에는 빠져 있습니다. 의도된 제한인지, 누락인지 확인 부탁드립니다. 누락이라면 추가 및 매퍼/서비스 로직 보강이 필요합니다.


56-58: 단일 관리비(maintenanceFee) vs 항목별 관리비(maintenanceFees) 중복 의미 명확화 필요

Update DTO에 합계형 maintenanceFee와 항목별 maintenanceFees가 공존합니다. 합계가 항목들의 합과 불일치할 가능성이 있으므로, 다음 중 하나로 정리하는 것이 안전합니다.

  • 합계는 서버에서 maintenanceFees 합으로만 계산하고, 클라이언트 입력을 받지 않는다.
  • 혹은 둘 다 받되, 서비스 계층에서 일관성 검증(합/일치) 로직을 추가한다.

원하시면 서비스 계층에 일관성 검증 헬퍼 추가를 제안드리겠습니다.

Also applies to: 96-97

src/main/java/org/scoula/domain/home/enums/HomeDirection.java (1)

27-29: getKey() 추가 LGTM

Enum 키 문자열 접근자가 생겨서 DB/프론트 연동 시 가독성이 좋아집니다.

src/main/java/org/scoula/domain/home/vo/HomeLikeVO.java (1)

16-16: likedAt 정밀도 검토 요청

정렬/중복 제어/감사 로그 등을 고려하면 LocalDate 대신 LocalDateTime(또는 타임스탬프)이 더 유용할 수 있습니다. 도메인 요구사항에 따라 현재 결정이 의도된 것인지 확인 부탁드립니다.

src/main/java/org/scoula/domain/home/vo/HomeMaintenanceFeeVO.java (1)

11-15: 구현 깔끔: 별도 이슈 없음

단순 VO로 목적에 부합하고, 타입/명명도 직관적입니다.

src/main/java/org/scoula/domain/fraud/service/AiFraudAnalyzerService.java (1)

1-1: 패키지 네이밍(‘org.scoula’ vs ‘org.scoola’) 일관성 확인 완료
전체 코드베이스에서 package org.scoula… 만 선언되어 있으며, package org.scoola… 선언은 존재하지 않습니다.
네이밍 불일치로 인한 컴파일/빈 주입 오류 우려 없음.

src/main/java/org/scoula/domain/home/service/HomeServiceImpl.java (1)

454-458: 동적 정렬 파라미터 치환 사용 없음 확인

매퍼 XML(src/main/resources)에서 ${sortBy}, ${sortDirection} 및 일반적인 ${...} 패턴이 검색되지 않아 SQL 인젝션 위험이 없습니다. 추가 검증이나 수정은 필요 없습니다.

src/main/java/org/scoula/domain/home/controller/HomeController.java (3)

81-86: 찜 토글 엔드포인트 시그니처/권한 전달 적절

토글 목적의 POST + Authentication 전달 방식 일관되고 명확합니다. 나머지 계층에서 idempotency/중복 처리만 보장되면 충분합니다.


91-99: 편의시설 조회 엔드포인트 구성 적절

카테고리/아이템 분리 및 명확한 경로 설계, 반환 타입 모두 적절합니다.


28-32: 파일 업로드 필드 존재 확인
HomeCreateRequestDto 클래스에 이미 private List<MultipartFile> images 필드가 정의되어 있어, multipart/form-data 요청 시 이미지 업로드가 누락되지 않습니다. 추가 조치가 필요 없습니다.

src/main/java/org/scoula/domain/home/mapper/HomeMapper.java (1)

31-33: 검색/카운트 시 DTO 파라미터 네이밍 통일 적절

@param("search")로 DTO를 감싸는 패턴 일관적입니다. XML의 #{search.*} 참조와도 맞습니다.

Also applies to: 37-39

Comment on lines 38 to 46
@ApiOperation(value = "매물 목록 조회", notes = "페이징된 매물 목록을 조회합니다.")
@GetMapping
public ResponseEntity<PageResponse<HomeResponseDto>> getAllHomes(
@ApiParam(value = "페이지 번호", defaultValue = "1") @RequestParam(defaultValue = "1")
String pageStr,
@ApiParam(value = "페이지 크기", defaultValue = "10") @RequestParam(defaultValue = "10")
String sizeStr) {
ResponseEntity<PageResponse<HomeResponseDTO>> getHomeList(
@ApiParam(value = "페이지 번호 (1부터 시작)", defaultValue = "1")
@RequestParam(defaultValue = "1")
int page,
@ApiParam(value = "페이지 크기", defaultValue = "21") @RequestParam(defaultValue = "21")
int size);

Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

페이지 응답도 ApiResponse로 일관되게 감싸주세요

코딩 가이드라인에 따라 모든 컨트롤러 응답은 ApiResponse로 감싸져야 합니다. 현재 getHomeList, searchHomes는 PageResponse를 직접 반환하고 있어 일관성이 깨집니다.

아래처럼 반환 타입을 변경하는 것을 제안합니다.

-      ResponseEntity<PageResponse<HomeResponseDTO>> getHomeList(
+      ResponseEntity<ApiResponse<PageResponse<HomeResponseDTO>>> getHomeList(
         @ApiParam(value = "페이지 번호 (1부터 시작)", defaultValue = "1")
                 @RequestParam(defaultValue = "1")
                 int page,
         @ApiParam(value = "페이지 크기", defaultValue = "21") @RequestParam(defaultValue = "21")
                 int size);

-      ResponseEntity<PageResponse<HomeResponseDTO>> searchHomes(
+      ResponseEntity<ApiResponse<PageResponse<HomeResponseDTO>>> searchHomes(
               @ApiParam(value = "검색 조건") @ModelAttribute HomeSearchDTO searchDTO);

Also applies to: 47-51

🤖 Prompt for AI Agents
In src/main/java/org/scoula/domain/home/controller/HomeController.java around
lines 38-46 (and also 47-51), the controller methods return
PageResponse<HomeResponseDTO> directly which breaks the guideline requiring
ApiResponse<T> wrappers; change the method signatures to return
ResponseEntity<ApiResponse<PageResponse<HomeResponseDTO>>> (and update imports),
update annotations if necessary, and ensure the service/controller
implementation and any tests build and return ApiResponse.of(pageResponse) (or
the project’s standard ApiResponse factory) so all controller responses are
consistently wrapped.

Comment on lines 146 to 206
@Override
@PutMapping("/{homeId}")
public ResponseEntity<ApiResponse<Void>> updateHome(
@PathVariable Integer homeId,
@Valid @ModelAttribute HomeUpdateRequestDto updateDto,
@RequestParam(value = "newImages", required = false) List<MultipartFile> newImages,
Authentication authentication) {

Integer userId = getCurrentUserId(authentication);

log.info(
"매물 수정 요청: homeId={}, userId={}, 새 이미지 개수={}, 삭제할 이미지 개수={}",
homeId,
userId,
newImages != null ? newImages.size() : 0,
updateDto.getDeleteImageIds() != null ? updateDto.getDeleteImageIds().size() : 0);

// 요청 DTO의 homeId 설정 (경로 변수의 homeId 사용)
updateDto.setHomeId(homeId);

// HomeUpdateRequestDto를 HomeCreateDTO로 변환
HomeCreateDTO updateDTO =
HomeCreateDTO.builder()
.addr1(updateDto.getAddr1())
.addr2(updateDto.getAddr2())
.residenceType(updateDto.getResidenceType())
.leaseType(updateDto.getLeaseType())
.depositPrice(updateDto.getDepositPrice())
.monthlyRent(updateDto.getMonthlyRent())
.maintenaceFee(updateDto.getMaintenanceFee())
.roomCnt(updateDto.getRoomCnt())
.supplyArea(updateDto.getSupplyArea())
.exclusiveArea(updateDto.getExclusiveArea())
.buildDate(updateDto.getBuildDate())
.homeFloor(updateDto.getHomeFloor())
.buildingTotalFloors(updateDto.getBuildingTotalFloors())
.homeDirection(updateDto.getHomeDirection())
.bathroomCnt(updateDto.getBathroomCnt())
.isPet(updateDto.getIsPet())
.isParking(updateDto.getIsParking())
.facilityItemIds(updateDto.getFacilityItemIds())
.maintenanceFees(
updateDto.getMaintenanceFees() != null
? updateDto.getMaintenanceFees().stream()
.map(
fee ->
HomeCreateDTO.MaintenanceFeeDTO
.builder()
.maintenanceId(
fee
.getMaintenanceId())
.fee(fee.getFee())
.build())
.collect(java.util.stream.Collectors.toList())
: null)
.build();

homeService.updateHome(homeId, updateDTO, newImages, userId);

return ResponseEntity.ok(ApiResponse.success(null, "매물이 성공적으로 수정되었습니다."));
}
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

수정 API에서 삭제 이미지/시설 변경사항 반영 누락

updateDto.getDeleteImageIds()를 로깅만 하고 실제 삭제/동기화 로직이 없습니다. 서비스 계층에 반영하여 이미지/시설/관리비의 추가·삭제를 함께 처리하세요.

[suggest_optional_refactor]
필요 시 매퍼 메서드 존재 여부를 확인하는 스크립트를 실행해 주세요(존재 시 즉시 적용 가능합니다).


🏁 Script executed:

#!/bin/bash
# 매퍼/인터페이스에 업데이트/삭제 관련 메서드가 정의되어 있는지 확인
rg -n -C2 --type=java --type=xml -P '(update|delete).*Home(Image|Facility|MaintenanceFee)?' src/main/java src/main/resources

Length of output: 19594


매물 수정 시 이미지·편의시설·관리비 동기화 로직 미구현

현재 HomeControllerImpl.updateHome에서 삭제할 이미지 ID를 로깅만 하고, HomeServiceImpl.updateHome(…)에는 실제 삭제·추가 로직이 빠져 있습니다. 아래 항목을 서비스 계층에 반드시 구현하세요.

• HomeServiceImpl.updateHome 메서드(약 335–347라인)
– 기존 이미지 중 updateDto.getDeleteImageIds()에 해당하는 항목 삭제
– 새 이미지 업로드 로직
– updateDto.getFacilityItemIds() 기반 편의시설 삭제(deleteHomeFacilitiesByHomeDetailId) 및 재등록
– updateDto.getMaintenanceFees() 기반 관리비 삭제(deleteHomeMaintenanceFeesByHomeId) 및 재등록

• 매퍼 메서드(HomeMapper.xml 및 HomeMapper 인터페이스)에 필요한 deleteXXXByHomeId, insertXXX 메서드는 이미 정의되어 있으므로 즉시 호출 가능합니다.


private Integer monthlyRent;

private Integer maintenaceFee;
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

필드명 오탈자: maintenaceFee → maintenanceFee (전역 정리 필요)

DTO/VO/Response 간 필드명이 불일치합니다. 특히 이 DTO의 maintenaceFee 오탈자는 API 계약과 매퍼/서비스 매핑 오류를 유발할 수 있습니다. Update DTO는 maintenanceFee로 올바르게 표기되어 있어 불일치가 확실합니다.

우선 이 파일의 필드명을 수정하고, 연관된 VO/DTO/Mapper/XML/프론트 계약을 일괄 교정해 주세요.

-      private Integer maintenaceFee;
+      private Integer maintenanceFee;

레포 전역에서 불일치 지점을 점검하는 스크립트:


🏁 Script executed:

#!/bin/bash
# maintenaceFee 오탈자/정상 표기 모두 검색하여 영향도 확인
rg -nP -C2 --type=java '\bmaintenaceFee\b|\bmaintenanceFee\b'

Length of output: 10967


필드명 오탈자 수정: ‘maintenaceFee’ → ‘maintenanceFee’

DTO/VO/Response/Service/Controller 전역에서 필드명이 일치하지 않아 API 계약 및 매퍼 오류를 유발합니다. 아래 위치를 일괄 교정해주세요.

  • src/main/java/org/scoula/domain/home/vo/HomeVO.java (필드 및 getter/setter 변경)
  • src/main/java/org/scoula/domain/home/dto/HomeCreateDTO.java
  • src/main/java/org/scoula/domain/home/dto/HomeResponseDTO.java
  • src/main/java/org/scoula/domain/home/service/HomeServiceImpl.java
    • getMaintenaceFee() → getMaintenanceFee()
    • .maintenaceFee(...) → .maintenanceFee(...)
  • src/main/java/org/scoula/domain/home/controller/HomeControllerImpl.java
    • .maintenaceFee(...) → .maintenanceFee(...)
  • 기타 매퍼(XML)·프론트 API 계약 스펙
-      private Integer maintenaceFee;
+      private Integer maintenanceFee;

전역에서 rg -nP '\bmaintenaceFee\b'로 잔여 오타가 없는지 확인 바랍니다.

📝 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.

Suggested change
private Integer maintenaceFee;
private Integer maintenanceFee;
🤖 Prompt for AI Agents
In src/main/java/org/scoula/domain/home/dto/HomeCreateDTO.java around line 35,
the field name maintenaceFee is misspelled; rename the field to maintenanceFee
and update its getter/setter accordingly, then propagate the rename across the
codebase: update src/main/java/org/scoula/domain/home/vo/HomeVO.java (field and
getter/setter), src/main/java/org/scoula/domain/home/dto/HomeResponseDTO.java,
src/main/java/org/scoula/domain/home/service/HomeServiceImpl.java
(getMaintenaceFee() → getMaintenanceFee(), builder/call sites
.maintenaceFee(...) → .maintenanceFee(...)),
src/main/java/org/scoula/domain/home/controller/HomeControllerImpl.java
(.maintenaceFee(...) → .maintenanceFee(...)), any mapper XMLs and frontend API
contract/spec; after applying edits, run rg -nP '\bmaintenaceFee\b' to confirm
no remaining occurrences and run tests/compile to ensure no build breaks.

Comment on lines 27 to 29
@ApiModelProperty(value = "시/도 및 시/군/구", example = "서울특별시 강남구", required = true)
private String addr1;

Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

검증 애노테이션(@Valid) 누락: 런타임 유효성 보장 필요

Swagger의 required 표시는 문서용입니다. 실제 요청 검증을 위해 JSR-303 애노테이션을 추가해 주세요. (컨트롤러에서 @Valid 적용도 필요)

다음과 같이 주요 필드에 최소한의 제약을 권장합니다:

       @ApiModelProperty(value = "시/도 및 시/군/구", example = "서울특별시 강남구", required = true)
+      @NotBlank
       private String addr1;

@@
       private String addr2;

@@
       @ApiModelProperty(
               value = "거주 유형",
               example = "APARTMENT",
               required = true,
               allowableValues = "APARTMENT, VILLA, ONEROOM, OFFICETEL, HOUSE")
+      @NotNull
       private ResidenceType residenceType;

@@
       @ApiModelProperty(
               value = "임대 유형",
               example = "WOLSE",
               required = true,
               allowableValues = "JEONSE, WOLSE")
+      @NotNull
       private LeaseType leaseType;

@@
       @ApiModelProperty(value = "보증금 (원)", example = "50000000", required = true)
-      private Integer depositPrice;
+      @NotNull
+      @Min(0)
+      private Integer depositPrice;

       @ApiModelProperty(value = "월세 (원)", example = "1000000", notes = "전세인 경우 0")
-      private Integer monthlyRent;
+      @Min(0)
+      private Integer monthlyRent;

       @ApiModelProperty(value = "관리비 (원)", example = "150000")
-      private Integer maintenanceFee;
+      @Min(0)
+      private Integer maintenanceFee;

       @ApiModelProperty(value = "방 개수", example = "3")
-      private Integer roomCnt;
+      @NotNull
+      @Min(0)
+      private Integer roomCnt;

컨트롤러 단에서의 검증 활성화도 확인해 주세요:

  • 메서드 파라미터에 @Valid HomeCreateRequestDto request 적용
  • 클래스 레벨에 @Validated 적용(필요 시)

교차 필드 검증(예: JEONSE면 monthlyRent=0, WOLSE면 monthlyRent>0)은 별도 커스텀 Validator로 확장 가능합니다. 원하시면 샘플 Validator도 제공하겠습니다.
[offer_assistance]

검증 활성화 여부 점검 스크립트:

Also applies to: 33-39, 40-46, 47-55, 56-58


🏁 Script executed:

#!/bin/bash
# 컨트롤러 계층에서 @Valid 사용 여부 확인
rg -n -C2 '@(Valid|Validated)\b' --type=java

Length of output: 19842


HomeCreateRequestDto 필드에 JSR-303 검증 애노테이션 추가 필요

컨트롤러(HomeControllerImpl)에서 이미 @Valid @RequestPart를 통해 검증이 활성화된 것을 확인했습니다. 런타임 유효성 보장을 위해 DTO 필드에 다음과 같이 JSR-303 제약 애노테이션을 추가해주세요:

       @ApiModelProperty(value = "시/도 및 시/군/구", example = "서울특별시 강남구", required = true)
+      @NotBlank
       private String addr1;

@@
       private String addr2;

@@
       @ApiModelProperty(
               value = "거주 유형",
               example = "APARTMENT",
               required = true,
               allowableValues = "APARTMENT, VILLA, ONEROOM, OFFICETEL, HOUSE")
+      @NotNull
       private ResidenceType residenceType;

@@
       @ApiModelProperty(
               value = "임대 유형",
               example = "WOLSE",
               required = true,
               allowableValues = "JEONSE, WOLSE")
+      @NotNull
       private LeaseType leaseType;

@@
       @ApiModelProperty(value = "보증금 (원)", example = "50000000", required = true)
+      @NotNull
+      @Min(0)
       private Integer depositPrice;

       @ApiModelProperty(value = "월세 (원)", example = "1000000", notes = "전세인 경우 0")
+      @Min(0)
       private Integer monthlyRent;

       @ApiModelProperty(value = "관리비 (원)", example = "150000")
+      @Min(0)
       private Integer maintenanceFee;

       @ApiModelProperty(value = "방 개수", example = "3")
+      @NotNull
+      @Min(0)
       private Integer roomCnt;

• 교차 필드 검증(예: JEONSE일 때 monthlyRent=0, WOLSE일 때 monthlyRent>0)이 필요하다면 별도 커스텀 Validator로 확장 가능합니다.
• DTO 전체에 @Validated 애노테이션은 선택 사항이며, 주로 클래스 레벨 검증이 추가로 필요할 때 사용합니다.

📝 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.

Suggested change
@ApiModelProperty(value = "시/도 및 시/군/구", example = "서울특별시 강남구", required = true)
private String addr1;
// … around line 27 in HomeCreateRequestDto.java …
@ApiModelProperty(value = "시/도 및 시/군/구", example = "서울특별시 강남구", required = true)
@NotBlank
private String addr1;
private String addr2;
@ApiModelProperty(
value = "거주 유형",
example = "APARTMENT",
required = true,
allowableValues = "APARTMENT, VILLA, ONEROOM, OFFICETEL, HOUSE")
@NotNull
private ResidenceType residenceType;
@ApiModelProperty(
value = "임대 유형",
example = "WOLSE",
required = true,
allowableValues = "JEONSE, WOLSE")
@NotNull
private LeaseType leaseType;
@ApiModelProperty(value = "보증금 (원)", example = "50000000", required = true)
@NotNull
@Min(0)
private Integer depositPrice;
@ApiModelProperty(value = "월세 (원)", example = "1000000", notes = "전세인 경우 0")
@Min(0)
private Integer monthlyRent;
@ApiModelProperty(value = "관리비 (원)", example = "150000")
@Min(0)
private Integer maintenanceFee;
@ApiModelProperty(value = "방 개수", example = "3")
@NotNull
@Min(0)
private Integer roomCnt;
// … rest of the class …
🤖 Prompt for AI Agents
In src/main/java/org/scoula/domain/home/dto/HomeCreateRequestDto.java around
lines 27 to 29, the DTO field validations are missing; add JSR-303 annotations
to ensure runtime validation (e.g., annotate addr1 with @NotBlank to require a
non-empty address) and similarly mark other fields appropriately
(@NotNull/@NotBlank/@Min/@Positive as applicable for numeric and required fields
such as monthlyRent, deposit, contractType, etc.); for the conditional rule
between contract type and monthlyRent (JEONSE vs WOLSE), implement a class-level
custom ConstraintValidator and companion annotation to enforce the cross-field
logic and annotate the DTO class with that custom constraint (optional: add
@Validated where class-level validation is needed).

Comment on lines 53 to 55
@ApiModelProperty(value = "관리비 (원)", example = "150000")
private Integer maintenanceFee;

Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

필드명 불일치: maintenanceFee vs (다른 계층) maintenaceFee

본 DTO는 maintenanceFee로 올바르게 작성되었으나, HomeVO/HomeCreateDTO 일부에 maintenaceFee 오타가 존재합니다. 자동 매핑 실패/데이터 유실이 발생합니다.

권장 방안(정렬 우선순위):

  1. 도메인 전반을 maintenanceFee로 통일 (VO/DTO/Mapper XML/Service 매핑 코드 일괄 수정)
  2. 일괄 수정이 어려우면 임시로 매핑 계층에 수동 매핑 또는 MapStruct @mapping으로 브릿지

예: MapStruct 매핑(참고용)

@Mapping(source = "maintenanceFee", target = "maintenaceFee")
HomeCreateDTO toCreateDto(HomeCreateRequestDto req);

원하시면 레포 전역 리팩터링 패치 생성해 드릴게요.
[offer_assistance]

오타 필드 사용 위치 스캔:


🏁 Script executed:

#!/bin/bash
rg -n --hidden -S '\bmaintenaceFee\b' -C2

Length of output: 9822


필드명 통일 필요: maintenaceFeemaintenanceFee

VO/DTO/서비스/매퍼 전반에 오타가 있어 자동 매핑·데이터 유실 위험이 있습니다.
아래 위치를 일괄 수정해주세요.

  • src/main/java/org/scoula/domain/home/vo/HomeVO.java (라인 26: private Integer maintenaceFee;)
  • src/main/java/org/scoula/domain/home/dto/HomeCreateDTO.java (라인 35: private Integer maintenaceFee;)
  • src/main/java/org/scoula/domain/home/dto/HomeResponseDTO.java (라인 35: private Integer maintenaceFee;)
  • src/main/java/org/scoula/domain/home/service/HomeServiceImpl.java
    • 라인 54, 233, 278: .maintenaceFee(...) 호출
  • src/main/java/org/scoula/domain/home/controller/HomeControllerImpl.java
    • 라인 63, 175: .maintenaceFee(requestDto.getMaintenanceFee()) 호출
  • src/main/resources/org/scoula/domain/home/mapper/HomeMapper.xml
    • 라인 13, 54, 76, 93, 233, 248, 268: #{maintenaceFee}as maintenaceFee 매핑

권장 방안:

  1. 도메인 전반 maintenaceFeemaintenanceFee 일괄 리팩터링
  2. 불가 시 MapStruct로 임시 브릿지 추가
    @Mapping(source = "maintenanceFee", target = "maintenaceFee")
    HomeCreateDTO toCreateDto(HomeCreateRequestDto req);

필요하시면 레포지토리 전역 리팩터링 패치 제공 가능합니다.

🤖 Prompt for AI Agents
In src/main/java/org/scoula/domain/home/dto/HomeCreateRequestDto.java around
lines 53-55: there's a misspelled field name maintenaceFee that must be renamed
to maintenanceFee; perform an across-repository refactor to rename maintenaceFee
→ maintenanceFee in the listed files (VO, DTOs, service calls, controller calls,
and all occurrences in
src/main/resources/org/scoula/domain/home/mapper/HomeMapper.xml) and update
corresponding getters/setters, constructor usages and mapper property names to
match; if you cannot refactor everywhere at once, add a temporary MapStruct
mapping bridging maintenanceFee → maintenaceFee for DTO/VO conversions per the
suggested @Mapping until the full rename is applied.

private LeaseType leaseType;
private Integer depositPrice;
private Integer monthlyRent;
private Integer maintenaceFee;
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

오타: maintenaceFee → maintenanceFee (매핑/직렬화/쿼리 실패 가능성 큼)

다른 DTO(예: HomeCreateRequestDto)의 필드명은 maintenanceFee로 보입니다. 현재 VO의 오타로 인해 MapStruct/수동 매핑/마이바티스 resultMap에서 필드 매칭이 누락될 수 있습니다.

다음과 같이 필드명을 즉시 정정하는 것을 권장합니다.

-      private Integer maintenaceFee;
+      private Integer maintenanceFee;

참고: 연쇄 영향이 큰 변경입니다. 아래 항목들도 함께 정렬해 주세요.

  • HomeCreateDTO의 maintenaceFeemaintenanceFee
  • Mapper XML의 컬럼 alias 또는 resultMap 필드명
  • 서비스/컨트롤러 매핑 코드

원하시면 전체 레퍼런스 수정 PR 패치를 만들어 드릴게요.
[offer_assistance]

레포 내 오타 사용 위치를 확인하는 스크립트입니다.


🏁 Script executed:

#!/bin/bash
rg -n --hidden -S '\bmaintenaceFee\b' -C2

Length of output: 9822


오타 수정: maintenaceFeemaintenanceFee
VO, DTO, Mapper, Controller, Service 전반에서 일관된 필드명을 사용해야 매핑/직렬화/쿼리 오류를 방지할 수 있습니다.

• 수정 대상 위치

  • src/main/java/org/scoula/domain/home/vo/HomeVO.java (라인 26)
  • src/main/java/org/scoula/domain/home/dto/HomeCreateDTO.java (라인 35)
  • src/main/java/org/scoula/domain/home/dto/HomeResponseDTO.java (라인 35)
  • src/main/resources/org/scoula/domain/home/mapper/HomeMapper.xml (총 7곳: #{maintenaceFee}#{maintenanceFee}, as maintenaceFeeas maintenanceFee, maintenance_fee = #{maintenaceFee}#{maintenanceFee})
  • src/main/java/org/scoula/domain/home/controller/HomeControllerImpl.java (2곳: .maintenaceFee(...).maintenanceFee(...))
  • src/main/java/org/scoula/domain/home/service/HomeServiceImpl.java (3곳: .maintenaceFee(...).maintenanceFee(...))

• 예시 diff (HomeVO.java)

-    private Integer maintenaceFee;
+    private Integer maintenanceFee;

위 변경에 따른 연쇄 수정이 반드시 필요하니, 각 매퍼(resultMap/SQL), 매핑 코드, DTO 필드명까지 함께 정리해 주세요.

📝 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.

Suggested change
private Integer maintenaceFee;
private Integer maintenanceFee;
🤖 Prompt for AI Agents
In src/main/java/org/scoula/domain/home/vo/HomeVO.java around line 26 (and all
related files listed), there is a typo: the field maintenaceFee should be
renamed to maintenanceFee; update the field name in HomeVO and then apply the
same rename across DTOs (HomeCreateDTO.java line ~35, HomeResponseDTO.java line
~35), all usages in HomeControllerImpl.java (2 places) and HomeServiceImpl.java
(3 places), and every occurrence in the MyBatis mapper file
src/main/resources/org/scoula/domain/home/mapper/HomeMapper.xml (change
#{maintenaceFee} → #{maintenanceFee}, SQL aliases "as maintenaceFee" → "as
maintenanceFee", and parameter bindings like maintenance_fee = #{maintenaceFee}
→ #{maintenanceFee}); ensure getters/setters and any builder/constructor calls
are updated, regenerate/adjust mapper resultMap and SQL statements to use the
corrected property name, and run a build/tests to catch any remaining
references.

Comment on lines 12 to 15
#{userId}, #{addr1}, #{addr2}, #{residenceType}, #{leaseType},
#{depositPrice}, #{monthlyRent}, #{maintenaceFee}, #{homeStatus},
#{viewCnt}, #{likeCnt}, #{chatCnt}, #{roomCnt}, #{supplyArea}, #{exclusiveArea}
)
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

프로퍼티명 오타: maintenaceFee → maintenanceFee

VO 필드명이 maintenanceFee일 가능성이 높습니다. 현재 SQL 바인딩/별칭이 maintenaceFee(오타)로 되어 있어 런타임 바인딩 에러 또는 매핑 실패가 발생할 수 있습니다. 모든 위치를 일괄 수정하세요.

먼저 실제 VO 필드명을 확인해 주세요.

수정 예시:

-                     #{depositPrice}, #{monthlyRent}, #{maintenaceFee}, #{homeStatus},
+                     #{depositPrice}, #{monthlyRent}, #{maintenanceFee}, #{homeStatus},

-            h.maintenance_fee as maintenaceFee, h.home_status as homeStatus,
+            h.maintenance_fee as maintenanceFee, h.home_status as homeStatus,

-            h.maintenance_fee as maintenaceFee, h.home_status as homeStatus,
+            h.maintenance_fee as maintenanceFee, h.home_status as homeStatus,

-        h.maintenance_fee as maintenaceFee, h.home_status as homeStatus,
+        h.maintenance_fee as maintenanceFee, h.home_status as homeStatus,

-            h.maintenance_fee as maintenaceFee, h.home_status as homeStatus,
+            h.maintenance_fee as maintenanceFee, h.home_status as homeStatus,

-                        maintenance_fee = #{maintenaceFee},
+                        maintenance_fee = #{maintenanceFee},

Also applies to: 54-58, 76-80, 92-96, 231-236, 268-269


🏁 Script executed:

#!/bin/bash
# VO와 XML에서 maintenaceFee/maintenanceFee 사용 여부 확인
fd -a HomeVO.java | xargs -I{} rg -n -C2 -P 'maintenaceFee|maintenanceFee' {}
rg -n -C2 -P 'maintenaceFee|maintenanceFee' src/main/resources

Length of output: 5314


VO 필드명 및 매퍼 XML 오타 수정 (maintenaceFee → maintenanceFee)

VO(HomeVO.java)에 maintenaceFee 필드명 오타가 있어, 이를 maintenanceFee로 변경하고 관련 getter/setter를 모두 수정해야 합니다. 그 후 매퍼 XML의 바인딩·별칭·업데이트 절에서도 #{maintenaceFee}as maintenaceFeemaintenanceFee로 일괄 교체하세요.

• 수정 대상

  • src/main/java/**/HomeVO.java
  • src/main/resources/org/scoula/domain/home/mapper/HomeMapper.xml

• 예시 diff

--- a/src/main/java/org/scoula/domain/home/vo/HomeVO.java
+++ b/src/main/java/org/scoula/domain/home/vo/HomeVO.java
@@ -23,7 +23,7 @@ public class HomeVO {
-    private Integer maintenaceFee;
+    private Integer maintenanceFee;

-    public Integer getMaintenaceFee() {
-        return maintenaceFee;
-    }
+    public Integer getMaintenanceFee() {
+        return maintenanceFee;
+    }

-    public void setMaintenaceFee(Integer maintenaceFee) {
-        this.maintenaceFee = maintenaceFee;
+    public void setMaintenanceFee(Integer maintenanceFee) {
+        this.maintenanceFee = maintenanceFee;
    }
}
--- a/src/main/resources/org/scoula/domain/home/mapper/HomeMapper.xml
+++ b/src/main/resources/org/scoula/domain/home/mapper/HomeMapper.xml
@@ -12,7 +12,7 @@
-                     #{depositPrice}, #{monthlyRent}, #{maintenaceFee}, #{homeStatus},
+                     #{depositPrice}, #{monthlyRent}, #{maintenanceFee}, #{homeStatus},
@@ -53,7 +53,7 @@
-            h.maintenance_fee as maintenaceFee, h.home_status as homeStatus,
+            h.maintenance_fee as maintenanceFee, h.home_status as homeStatus,
@@ -268,7 +268,7 @@
-                        maintenance_fee = #{maintenaceFee},
+                        maintenance_fee = #{maintenanceFee},
📝 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.

Suggested change
#{userId}, #{addr1}, #{addr2}, #{residenceType}, #{leaseType},
#{depositPrice}, #{monthlyRent}, #{maintenaceFee}, #{homeStatus},
#{viewCnt}, #{likeCnt}, #{chatCnt}, #{roomCnt}, #{supplyArea}, #{exclusiveArea}
)
#{userId}, #{addr1}, #{addr2}, #{residenceType}, #{leaseType},
#{depositPrice}, #{monthlyRent}, #{maintenanceFee}, #{homeStatus},
#{viewCnt}, #{likeCnt}, #{chatCnt}, #{roomCnt}, #{supplyArea}, #{exclusiveArea}
)
🤖 Prompt for AI Agents
In src/main/resources/org/scoula/domain/home/mapper/HomeMapper.xml around lines
12 to 15, the field name maintenaceFee is misspelled; update all occurrences of
#{maintenaceFee} and any "as maintenaceFee" to #{maintenanceFee} / "as
maintenanceFee". Also fix the VO: open src/main/java/**/HomeVO.java and rename
the field maintenaceFee → maintenanceFee, update the getter/setter names and
references, and then update any mapper resultMap, SQL insert/update parameter
bindings, aliases, and unit tests or usages to use the corrected maintenanceFee
name consistently.

Comment on lines 63 to 69
<select id="selectHomeDetailByHomeId" parameterType="int" resultType="org.scoula.domain.home.vo.HomeDetailVO">
SELECT
home_detail_id, home_id, build_date, home_floor, building_total_floors,
home_direction, bathroom_count as bathroomCnt, is_pet as isPet, is_parking_available as isParking, description as description
FROM home_detail
WHERE home_id = #{homeId}
</select>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

home_detail 조회에 area/land_category 필드 누락

insert 시에는 area, land_category, description을 넣지만 selectHomeDetailByHomeId에는 area와 land_category가 누락되어 조회 결과가 불완전합니다. 컬럼을 추가 선택하세요.

-        SELECT
-            home_detail_id, home_id, build_date, home_floor, building_total_floors,
-            home_direction, bathroom_count as bathroomCnt, is_pet as isPet, is_parking_available as isParking, description as description
+        SELECT
+            home_detail_id, home_id, build_date, home_floor, building_total_floors,
+            home_direction, bathroom_count as bathroomCnt, is_pet as isPet, is_parking_available as isParking,
+            area as area, land_category as landCategory, description as description
📝 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.

Suggested change
<select id="selectHomeDetailByHomeId" parameterType="int" resultType="org.scoula.domain.home.vo.HomeDetailVO">
SELECT
home_detail_id, home_id, build_date, home_floor, building_total_floors,
home_direction, bathroom_count as bathroomCnt, is_pet as isPet, is_parking_available as isParking, description as description
FROM home_detail
WHERE home_id = #{homeId}
</select>
<select id="selectHomeDetailByHomeId" parameterType="int" resultType="org.scoula.domain.home.vo.HomeDetailVO">
SELECT
home_detail_id, home_id, build_date, home_floor, building_total_floors,
home_direction, bathroom_count as bathroomCnt, is_pet as isPet, is_parking_available as isParking,
area as area, land_category as landCategory, description as description
FROM home_detail
WHERE home_id = #{homeId}
</select>
🤖 Prompt for AI Agents
In src/main/resources/org/scoula/domain/home/mapper/HomeMapper.xml around lines
63 to 69, the selectHomeDetailByHomeId query omits the area and land_category
columns causing incomplete HomeDetailVO results; modify the SELECT projection to
include area and land_category and alias them to match the HomeDetailVO property
names (e.g., area and landCategory or whatever the VO expects) so the mapper
returns the same fields that insert populates.

Comment on lines 256 to 259
<select id="findHomeById" resultType="org.scoula.domain.home.vo.HomeVO">
SELECT * FROM home WHERE home_id=#{id}
</select>

Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

SELECT * 사용 및 중복 쿼리: findHomeById 정리

  • SELECT *는 컬럼/alias 일관성을 깨고 MyBatis 전역 설정(mapUnderscoreToCamelCase)에 의존하게 만듭니다.
  • 이미 selectHomeById가 존재하므로 중복입니다. 하나로 통일하세요.

옵션 A: XML에서 해당 쿼리 제거하고 자바 매퍼도 정리

-    <select id="findHomeById" resultType="org.scoula.domain.home.vo.HomeVO">
-        SELECT * FROM home WHERE home_id=#{id}
-    </select>

옵션 B: 동일한 컬럼 alias를 사용하는 쿼리로 교체(중복은 남지만 안전)

-    <select id="findHomeById" resultType="org.scoula.domain.home.vo.HomeVO">
-        SELECT * FROM home WHERE home_id=#{id}
-    </select>
+    <select id="findHomeById" parameterType="int" resultType="org.scoula.domain.home.vo.HomeVO">
+        SELECT
+            h.home_id as homeId, h.user_id as userId, h.addr1, h.addr2,
+            h.residence_type as residenceType, h.lease_type as leaseType,
+            h.deposit_price as depositPrice, h.monthly_rent as monthlyRent,
+            h.maintenance_fee as maintenanceFee, h.home_status as homeStatus,
+            h.view_cnt as viewCnt, h.like_cnt as likeCnt, h.chat_cnt as chatCnt,
+            h.room_cnt as roomCnt, h.supply_area as supplyArea, h.exclusive_area as exclusiveArea,
+            h.created_at as createdAt, h.updated_at as updatedAt
+        FROM home h
+        WHERE h.home_id = #{id}
+    </select>

중복된 selectHomeById 쿼리의 존재 여부를 확인하기 위해 다음 스크립트를 실행해주세요:


🏁 Script executed:

#!/bin/bash
rg -nP --type=xml '<select\s+id="selectHomeById"' -C2 src/main/resources/org/scoula/domain/home/mapper/HomeMapper.xml

Length of output: 335


중복된 쿼리 제거 및 명시적 컬럼 매핑 통일

이미 selectHomeById(lines 49–57)에서 컬럼을 명시적으로 alias 처리한 쿼리가 존재하므로, 아래 중 하나를 선택하세요:

• 옵션 A: findHomeById 매퍼 및 사용부 제거

  • 파일: src/main/resources/org/scoula/domain/home/mapper/HomeMapper.xml (256–259줄)
  • 연관 자바 인터페이스 메소드(findHomeById)도 삭제
  • 호출부(service/DAO)에서 findHomeByIdselectHomeById 로 변경

• 옵션 B: findHomeById 쿼리를 selectHomeById와 동일한 컬럼·alias 구조로 교체

-    <select id="findHomeById" resultType="org.scoula.domain.home.vo.HomeVO">
-        SELECT * FROM home WHERE home_id=#{id}
-    </select>
+    <select id="findHomeById" parameterType="int" resultType="org.scoula.domain.home.vo.HomeVO">
+        SELECT
+            h.home_id   AS homeId,   h.user_id       AS userId,
+            h.addr1,    h.addr2,
+            h.residence_type AS residenceType,
+            h.lease_type     AS leaseType,
+            h.deposit_price  AS depositPrice,
+            h.monthly_rent   AS monthlyRent,
+            h.maintenance_fee AS maintenanceFee,
+            h.home_status     AS homeStatus,
+            h.view_cnt        AS viewCnt,
+            h.like_cnt        AS likeCnt,
+            h.chat_cnt        AS chatCnt,
+            h.room_cnt        AS roomCnt,
+            h.supply_area     AS supplyArea,
+            h.exclusive_area  AS exclusiveArea,
+            h.created_at      AS createdAt,
+            h.updated_at      AS updatedAt
+        FROM home h
+        WHERE h.home_id = #{id}
+    </select>

위 변경을 통해

  • SELECT * 의 불명확성 해소
  • MyBatis 전역 설정 의존성 축소
  • 중복 매퍼 정리 가 동시에 이루어집니다.
📝 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.

Suggested change
<select id="findHomeById" resultType="org.scoula.domain.home.vo.HomeVO">
SELECT * FROM home WHERE home_id=#{id}
</select>
<select id="findHomeById" parameterType="int" resultType="org.scoula.domain.home.vo.HomeVO">
SELECT
h.home_id AS homeId,
h.user_id AS userId,
h.addr1,
h.addr2,
h.residence_type AS residenceType,
h.lease_type AS leaseType,
h.deposit_price AS depositPrice,
h.monthly_rent AS monthlyRent,
h.maintenance_fee AS maintenanceFee,
h.home_status AS homeStatus,
h.view_cnt AS viewCnt,
h.like_cnt AS likeCnt,
h.chat_cnt AS chatCnt,
h.room_cnt AS roomCnt,
h.supply_area AS supplyArea,
h.exclusive_area AS exclusiveArea,
h.created_at AS createdAt,
h.updated_at AS updatedAt
FROM home h
WHERE h.home_id = #{id}
</select>
🤖 Prompt for AI Agents
In src/main/resources/org/scoula/domain/home/mapper/HomeMapper.xml around lines
256–259 there is a duplicate SELECT * mapper (findHomeById) that conflicts with
the existing selectHomeById (lines 49–57) which uses explicit column aliases;
either remove findHomeById entirely (delete this mapper, remove the
corresponding method from the Java mapper interface, and update all callers to
use selectHomeById) or replace the findHomeById SQL so it lists the same
explicit columns and aliases as selectHomeById (keep signature same) to ensure
consistent column mapping and remove SELECT * usage.

Comment on lines 276 to 286
<update id="updateHomeDetail" parameterType="org.scoula.domain.home.vo.HomeDetailVO">
UPDATE home_detail SET
build_date = #{buildDate},
home_floor = #{homeFloor},
building_total_floors = #{buildingTotalFloors},
home_direction = #{homeDirection},
bathroom_count = #{bathroomCnt},
is_pet = #{isPet},
is_parking_available = #{isParking}
WHERE home_detail_id = #{homeDetailId}
</update>
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

home_detail 갱신 시 area/land_category/description 누락

updateHomeDetail에서 insert된 필드(area, land_category, description)가 갱신되지 않습니다. 필드 추가가 필요합니다.

     <update id="updateHomeDetail" parameterType="org.scoula.domain.home.vo.HomeDetailVO">
         UPDATE home_detail SET
                                build_date = #{buildDate},
                                home_floor = #{homeFloor},
                                building_total_floors = #{buildingTotalFloors},
                                home_direction = #{homeDirection},
                                bathroom_count = #{bathroomCnt},
                                is_pet = #{isPet},
-                               is_parking_available = #{isParking}
+                               is_parking_available = #{isParking},
+                               area = #{area},
+                               land_category = #{landCategory},
+                               description = #{description}
         WHERE home_detail_id = #{homeDetailId}
     </update>
📝 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.

Suggested change
<update id="updateHomeDetail" parameterType="org.scoula.domain.home.vo.HomeDetailVO">
UPDATE home_detail SET
build_date = #{buildDate},
home_floor = #{homeFloor},
building_total_floors = #{buildingTotalFloors},
home_direction = #{homeDirection},
bathroom_count = #{bathroomCnt},
is_pet = #{isPet},
is_parking_available = #{isParking}
WHERE home_detail_id = #{homeDetailId}
</update>
<update id="updateHomeDetail" parameterType="org.scoula.domain.home.vo.HomeDetailVO">
UPDATE home_detail SET
build_date = #{buildDate},
home_floor = #{homeFloor},
building_total_floors = #{buildingTotalFloors},
home_direction = #{homeDirection},
bathroom_count = #{bathroomCnt},
is_pet = #{isPet},
is_parking_available = #{isParking},
area = #{area},
land_category = #{landCategory},
description = #{description}
WHERE home_detail_id = #{homeDetailId}
</update>
🤖 Prompt for AI Agents
In src/main/resources/org/scoula/domain/home/mapper/HomeMapper.xml around lines
276 to 286, the UPDATE statement for updateHomeDetail is missing the area,
land_category and description columns that were inserted earlier; add these
three columns to the SET clause mapping to the corresponding HomeDetailVO
properties (map DB columns area, land_category, description to the VO
properties, e.g., area, landCategory, description), ensure proper comma
separation and that the parameter names exactly match the VO getters so MyBatis
can bind them.

@Valid @RequestPart HomeCreateRequestDto requestDto, Authentication authentication) {

// ✨ 매물 등록 요청 데이터와 description 값을 로그로 확인
log.info("매물 등록 요청 데이터: {}", requestDto);

Check failure

Code scanning / CodeQL

Log Injection High

This log entry depends on a
user-provided value
.

Copilot Autofix

AI 6 months ago

To fix this log injection vulnerability, we should sanitize all user-provided fields before logging them. The best approach is to avoid logging the entire requestDto object directly. Instead, log only the fields that are necessary for debugging, and sanitize each field to remove newline characters and other potentially dangerous content. For string fields, replace any newline (\n, \r) characters with spaces or remove them entirely. For collections or nested objects, sanitize each string element. This can be done by creating a helper method to sanitize strings and applying it to each field before logging. The fix should be applied to line 46 in src/main/java/org/scoula/domain/home/controller/HomeControllerImpl.java. We may need to add a private helper method in the controller to perform the sanitization.


Suggested changeset 1
src/main/java/org/scoula/domain/home/controller/HomeControllerImpl.java

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/main/java/org/scoula/domain/home/controller/HomeControllerImpl.java b/src/main/java/org/scoula/domain/home/controller/HomeControllerImpl.java
--- a/src/main/java/org/scoula/domain/home/controller/HomeControllerImpl.java
+++ b/src/main/java/org/scoula/domain/home/controller/HomeControllerImpl.java
@@ -34,6 +34,14 @@
 @RequiredArgsConstructor
 public class HomeControllerImpl implements HomeController {
 
+      /**
+       * Sanitizes a string for safe logging by removing newlines and carriage returns.
+       */
+      private String sanitize(String input) {
+          if (input == null) return null;
+          return input.replaceAll("[\\r\\n]", " ");
+      }
+
       private final HomeService homeService;
       private final UserServiceInterface userService;
 
@@ -43,8 +51,30 @@
               @Valid @RequestPart HomeCreateRequestDto requestDto, Authentication authentication) {
 
           // ✨ 매물 등록 요청 데이터와 description 값을 로그로 확인
-          log.info("매물 등록 요청 데이터: {}", requestDto);
-          log.info("컨트롤러에서 확인한 description 값: {}", requestDto.getDescription());
+          log.info("매물 등록 요청 데이터: addr1={}, addr2={}, residenceType={}, leaseType={}, depositPrice={}, monthlyRent={}, maintenanceFee={}, roomCnt={}, supplyArea={}, exclusiveArea={}, buildDate={}, homeFloor={}, buildingTotalFloors={}, homeDirection={}, area={}, landCategory={}, bathroomCnt={}, isPet={}, isParking={}, facilityItemIds={}, description={}",
+              sanitize(requestDto.getAddr1()),
+              sanitize(requestDto.getAddr2()),
+              sanitize(String.valueOf(requestDto.getResidenceType())),
+              sanitize(String.valueOf(requestDto.getLeaseType())),
+              sanitize(String.valueOf(requestDto.getDepositPrice())),
+              sanitize(String.valueOf(requestDto.getMonthlyRent())),
+              sanitize(String.valueOf(requestDto.getMaintenanceFee())),
+              sanitize(String.valueOf(requestDto.getRoomCnt())),
+              sanitize(String.valueOf(requestDto.getSupplyArea())),
+              sanitize(String.valueOf(requestDto.getExclusiveArea())),
+              sanitize(String.valueOf(requestDto.getBuildDate())),
+              sanitize(String.valueOf(requestDto.getHomeFloor())),
+              sanitize(String.valueOf(requestDto.getBuildingTotalFloors())),
+              sanitize(String.valueOf(requestDto.getHomeDirection())),
+              sanitize(String.valueOf(requestDto.getArea())),
+              sanitize(String.valueOf(requestDto.getLandCategory())),
+              sanitize(String.valueOf(requestDto.getBathroomCnt())),
+              sanitize(String.valueOf(requestDto.getIsPet())),
+              sanitize(String.valueOf(requestDto.getIsParking())),
+              sanitize(String.valueOf(requestDto.getFacilityItemIds())),
+              sanitize(requestDto.getDescription())
+          );
+          log.info("컨트롤러에서 확인한 description 값: {}", sanitize(requestDto.getDescription()));
 
           Integer userId = getCurrentUserId(authentication);
 
EOF
@@ -34,6 +34,14 @@
@RequiredArgsConstructor
public class HomeControllerImpl implements HomeController {

/**
* Sanitizes a string for safe logging by removing newlines and carriage returns.
*/
private String sanitize(String input) {
if (input == null) return null;
return input.replaceAll("[\\r\\n]", " ");
}

private final HomeService homeService;
private final UserServiceInterface userService;

@@ -43,8 +51,30 @@
@Valid @RequestPart HomeCreateRequestDto requestDto, Authentication authentication) {

// ✨ 매물 등록 요청 데이터와 description 값을 로그로 확인
log.info("매물 등록 요청 데이터: {}", requestDto);
log.info("컨트롤러에서 확인한 description 값: {}", requestDto.getDescription());
log.info("매물 등록 요청 데이터: addr1={}, addr2={}, residenceType={}, leaseType={}, depositPrice={}, monthlyRent={}, maintenanceFee={}, roomCnt={}, supplyArea={}, exclusiveArea={}, buildDate={}, homeFloor={}, buildingTotalFloors={}, homeDirection={}, area={}, landCategory={}, bathroomCnt={}, isPet={}, isParking={}, facilityItemIds={}, description={}",
sanitize(requestDto.getAddr1()),
sanitize(requestDto.getAddr2()),
sanitize(String.valueOf(requestDto.getResidenceType())),
sanitize(String.valueOf(requestDto.getLeaseType())),
sanitize(String.valueOf(requestDto.getDepositPrice())),
sanitize(String.valueOf(requestDto.getMonthlyRent())),
sanitize(String.valueOf(requestDto.getMaintenanceFee())),
sanitize(String.valueOf(requestDto.getRoomCnt())),
sanitize(String.valueOf(requestDto.getSupplyArea())),
sanitize(String.valueOf(requestDto.getExclusiveArea())),
sanitize(String.valueOf(requestDto.getBuildDate())),
sanitize(String.valueOf(requestDto.getHomeFloor())),
sanitize(String.valueOf(requestDto.getBuildingTotalFloors())),
sanitize(String.valueOf(requestDto.getHomeDirection())),
sanitize(String.valueOf(requestDto.getArea())),
sanitize(String.valueOf(requestDto.getLandCategory())),
sanitize(String.valueOf(requestDto.getBathroomCnt())),
sanitize(String.valueOf(requestDto.getIsPet())),
sanitize(String.valueOf(requestDto.getIsParking())),
sanitize(String.valueOf(requestDto.getFacilityItemIds())),
sanitize(requestDto.getDescription())
);
log.info("컨트롤러에서 확인한 description 값: {}", sanitize(requestDto.getDescription()));

Integer userId = getCurrentUserId(authentication);

Copilot is powered by AI and may make mistakes. Always verify output.

// ✨ 매물 등록 요청 데이터와 description 값을 로그로 확인
log.info("매물 등록 요청 데이터: {}", requestDto);
log.info("컨트롤러에서 확인한 description 값: {}", requestDto.getDescription());

Check failure

Code scanning / CodeQL

Log Injection High

This log entry depends on a
user-provided value
.

Copilot Autofix

AI 6 months ago

To fix the log injection vulnerability, we should sanitize the user-provided description before logging it. The most straightforward and effective way is to remove or replace newline (\n, \r) and other control characters from the string before logging. This can be done using String.replaceAll() with a regular expression that matches all line breaks and control characters. The fix should be applied directly in the logging statement in HomeControllerImpl.java on line 47, ensuring that only sanitized data is logged. No changes to the DTO or other files are required. If the project does not already have a utility method for sanitizing log input, we can implement the sanitization inline.


Suggested changeset 1
src/main/java/org/scoula/domain/home/controller/HomeControllerImpl.java

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/main/java/org/scoula/domain/home/controller/HomeControllerImpl.java b/src/main/java/org/scoula/domain/home/controller/HomeControllerImpl.java
--- a/src/main/java/org/scoula/domain/home/controller/HomeControllerImpl.java
+++ b/src/main/java/org/scoula/domain/home/controller/HomeControllerImpl.java
@@ -44,7 +44,8 @@
 
           // ✨ 매물 등록 요청 데이터와 description 값을 로그로 확인
           log.info("매물 등록 요청 데이터: {}", requestDto);
-          log.info("컨트롤러에서 확인한 description 값: {}", requestDto.getDescription());
+          String sanitizedDescription = requestDto.getDescription() == null ? "" : requestDto.getDescription().replaceAll("[\\r\\n]", "");
+          log.info("컨트롤러에서 확인한 description 값: {}", sanitizedDescription);
 
           Integer userId = getCurrentUserId(authentication);
 
EOF
@@ -44,7 +44,8 @@

// ✨ 매물 등록 요청 데이터와 description 값을 로그로 확인
log.info("매물 등록 요청 데이터: {}", requestDto);
log.info("컨트롤러에서 확인한 description 값: {}", requestDto.getDescription());
String sanitizedDescription = requestDto.getDescription() == null ? "" : requestDto.getDescription().replaceAll("[\\r\\n]", "");
log.info("컨트롤러에서 확인한 description 값: {}", sanitizedDescription);

Integer userId = getCurrentUserId(authentication);

Copilot is powered by AI and may make mistakes. Always verify output.

// ✨ 서비스에서 받은 DTO와 description 값 확인
log.info("서비스에서 받은 DTO: {}", createDTO);
log.info("서비스에서 확인한 description 값: {}", createDTO.getDescription());

Check failure

Code scanning / CodeQL

Log Injection High

This log entry depends on a
user-provided value
.

Copilot Autofix

AI 6 months ago

To fix this log injection vulnerability, we need to sanitize the user-provided description field before logging it. The best approach is to remove or escape newline (\n, \r) and other control characters from the string before passing it to the logger. This can be done by creating a utility method (e.g., sanitizeForLog(String input)) that replaces or removes these characters. The fix should be applied in HomeServiceImpl.java on line 42, where the log entry is made. We should also add the utility method within the same file (since we cannot edit other files), and use it to sanitize the description before logging.


Suggested changeset 1
src/main/java/org/scoula/domain/home/service/HomeServiceImpl.java

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/main/java/org/scoula/domain/home/service/HomeServiceImpl.java b/src/main/java/org/scoula/domain/home/service/HomeServiceImpl.java
--- a/src/main/java/org/scoula/domain/home/service/HomeServiceImpl.java
+++ b/src/main/java/org/scoula/domain/home/service/HomeServiceImpl.java
@@ -29,6 +29,15 @@
       private final HomeMapper homeMapper;
       private final S3ServiceInterface s3Service;
 
+      /**
+       * Sanitizes user input for safe logging by removing newlines and carriage returns.
+       */
+      private static String sanitizeForLog(String input) {
+          if (input == null) return null;
+          // Remove newlines, carriage returns, and other control characters
+          return input.replaceAll("[\\r\\n\\t\\f\\b]", "");
+      }
+
       @Override
       public Integer createHome(HomeCreateDTO createDTO, List<MultipartFile> images, Integer userId) {
           log.info(
@@ -39,7 +48,7 @@
 
           // ✨ 서비스에서 받은 DTO와 description 값 확인
           log.info("서비스에서 받은 DTO: {}", createDTO);
-          log.info("서비스에서 확인한 description 값: {}", createDTO.getDescription());
+          log.info("서비스에서 확인한 description 값: {}", sanitizeForLog(createDTO.getDescription()));
 
           try {
               HomeVO home =
EOF
@@ -29,6 +29,15 @@
private final HomeMapper homeMapper;
private final S3ServiceInterface s3Service;

/**
* Sanitizes user input for safe logging by removing newlines and carriage returns.
*/
private static String sanitizeForLog(String input) {
if (input == null) return null;
// Remove newlines, carriage returns, and other control characters
return input.replaceAll("[\\r\\n\\t\\f\\b]", "");
}

@Override
public Integer createHome(HomeCreateDTO createDTO, List<MultipartFile> images, Integer userId) {
log.info(
@@ -39,7 +48,7 @@

// ✨ 서비스에서 받은 DTO와 description 값 확인
log.info("서비스에서 받은 DTO: {}", createDTO);
log.info("서비스에서 확인한 description 값: {}", createDTO.getDescription());
log.info("서비스에서 확인한 description 값: {}", sanitizeForLog(createDTO.getDescription()));

try {
HomeVO home =
Copilot is powered by AI and may make mistakes. Always verify output.

// ✨ DB에 저장할 객체의 description 값 최종 확인
log.info("DB에 저장할 HomeDetailVO 객체: {}", homeDetail);
log.info("최종 DB 저장 직전의 description 값: {}", homeDetail.getDescription());

Check failure

Code scanning / CodeQL

Log Injection High

This log entry depends on a
user-provided value
.

Copilot Autofix

AI 6 months ago

To fix this log injection vulnerability, we need to sanitize the user-provided description before logging it. The best approach is to remove or replace newline (\n, \r) and other control characters from the string before it is logged. This can be done by creating a helper method (e.g., sanitizeForLog(String input)) that replaces all newline and carriage return characters with spaces or removes them entirely. We should apply this sanitization in all log statements that output the description, specifically in HomeServiceImpl.java on lines 42 and 91. The helper method can be private and static within the service class, or placed in a utility class if available. Only the log output needs to be sanitized; the value stored in the database can remain unchanged.


Suggested changeset 1
src/main/java/org/scoula/domain/home/service/HomeServiceImpl.java

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/main/java/org/scoula/domain/home/service/HomeServiceImpl.java b/src/main/java/org/scoula/domain/home/service/HomeServiceImpl.java
--- a/src/main/java/org/scoula/domain/home/service/HomeServiceImpl.java
+++ b/src/main/java/org/scoula/domain/home/service/HomeServiceImpl.java
@@ -26,6 +26,15 @@
 @Transactional
 public class HomeServiceImpl implements HomeService {
 
+      /**
+       * Sanitizes a string for safe logging by removing newlines and carriage returns.
+       */
+      private static String sanitizeForLog(String input) {
+          if (input == null) return null;
+          // Remove newlines and carriage returns
+          return input.replaceAll("[\\r\\n]", " ");
+      }
+
       private final HomeMapper homeMapper;
       private final S3ServiceInterface s3Service;
 
@@ -39,7 +48,7 @@
 
           // ✨ 서비스에서 받은 DTO와 description 값 확인
           log.info("서비스에서 받은 DTO: {}", createDTO);
-          log.info("서비스에서 확인한 description 값: {}", createDTO.getDescription());
+          log.info("서비스에서 확인한 description 값: {}", sanitizeForLog(createDTO.getDescription()));
 
           try {
               HomeVO home =
@@ -88,7 +97,7 @@
 
               // ✨ DB에 저장할 객체의 description 값 최종 확인
               log.info("DB에 저장할 HomeDetailVO 객체: {}", homeDetail);
-              log.info("최종 DB 저장 직전의 description 값: {}", homeDetail.getDescription());
+              log.info("최종 DB 저장 직전의 description 값: {}", sanitizeForLog(homeDetail.getDescription()));
 
               int detailResult = homeMapper.insertHomeDetail(homeDetail);
               if (detailResult != 1) {
EOF
@@ -26,6 +26,15 @@
@Transactional
public class HomeServiceImpl implements HomeService {

/**
* Sanitizes a string for safe logging by removing newlines and carriage returns.
*/
private static String sanitizeForLog(String input) {
if (input == null) return null;
// Remove newlines and carriage returns
return input.replaceAll("[\\r\\n]", " ");
}

private final HomeMapper homeMapper;
private final S3ServiceInterface s3Service;

@@ -39,7 +48,7 @@

// ✨ 서비스에서 받은 DTO와 description 값 확인
log.info("서비스에서 받은 DTO: {}", createDTO);
log.info("서비스에서 확인한 description 값: {}", createDTO.getDescription());
log.info("서비스에서 확인한 description 값: {}", sanitizeForLog(createDTO.getDescription()));

try {
HomeVO home =
@@ -88,7 +97,7 @@

// ✨ DB에 저장할 객체의 description 값 최종 확인
log.info("DB에 저장할 HomeDetailVO 객체: {}", homeDetail);
log.info("최종 DB 저장 직전의 description 값: {}", homeDetail.getDescription());
log.info("최종 DB 저장 직전의 description 값: {}", sanitizeForLog(homeDetail.getDescription()));

int detailResult = homeMapper.insertHomeDetail(homeDetail);
if (detailResult != 1) {
Copilot is powered by AI and may make mistakes. Always verify output.
@MeongW MeongW merged commit e205f6c into develop Aug 17, 2025
4 of 7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

♻️ refactor 리팩토링 작업

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feat] 이슈 제목

3 participants