Skip to content

Conversation

@doup2001
Copy link
Member

@doup2001 doup2001 commented Dec 27, 2025

📌 작업한 내용

  • SegmentResponse 리팩토링 및 응답 구조 정리 (네이밍/필드 구성 개선, 중복 제거 등).
  • 전체 코드 1차~5차 리팩토링으로 도메인/서비스/DTO 전반 구조 정리 및 가독성 향상.
  • 방 그룹 관련 기능 구현 (방 그룹 생성/조회 등 도메인 로직 및 API 계층 추가).
  • 방 비교용 DTO 구현으로, 다수의 방 정보를 한 번에 비교할 수 있는 응답 스펙 정의.
  • 청약 진단 관련 DTO 수정으로 필드명/타입 정리 및 도메인 요구사항 반영.
    ​- Swagger 스펙 정보 보완 및 예시/설명 추가로 API 문서 가독성 및 활용성 개선.

🔍 참고 사항

  • 여러 차수에 걸쳐 리팩토링이 이루어져, 동일 모듈 내 변경이 많은 만큼 충돌 가능성을 고려해 머지 순서 조율이 필요함.
  • 방 그룹/비교/청약 진단 DTO 변경으로 프론트엔드에서 사용하는 응답 스키마가 일부 달라졌을 수 있으니, 연동 테스트를 반드시 함께 진행해 달라 부탁드립니다.

🖼️ 스크린샷

🔗 관련 이슈

✅ 체크리스트

  • 로컬에서 빌드 및 테스트 완료
  • 코드 리뷰 반영 완료
  • 문서화 필요 여부 확인

Summary by CodeRabbit

  • 새로운 기능

    • 진단 결과의 상세 조회(상세 DTO) 추가
    • 세그먼트 단위 대중교통 경로 조회 API 추가
    • 거리·시간 계산 및 색상 결정 유틸리티 추가
  • 개선 사항

    • 페이징 문서화(0부터 시작 등) 및 기본값 명시 개선
    • 대중교통 응답의 시간/라벨 표기 및 색상 규칙 정비
    • 여러 DTO 및 API 스펙에 Swagger 주석 보강, 유닛타입에 공급 그룹 정보 추가
  • 제거/호환성 변경

    • 기존 진단 이력/기존 거리 API 일부 제거 및 응답 형태 변경

✏️ Tip: You can customize this high-level summary in your review settings.

@doup2001 doup2001 self-assigned this Dec 27, 2025
@doup2001 doup2001 added the 🔨 Refactor 코드 리팩토링 label Dec 27, 2025
@coderabbitai
Copy link

coderabbitai bot commented Dec 27, 2025

Warning

Rate limit exceeded

@doup2001 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 8 minutes and 5 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 1970573 and 8e850f7.

📒 Files selected for processing (4)
  • src/main/java/com/pinHouse/server/platform/pinPoint/application/dto/UpdatePinPointRequest.java
  • src/main/java/com/pinHouse/server/platform/pinPoint/application/service/PinPointService.java
  • src/main/java/com/pinHouse/server/platform/pinPoint/domain/entity/PinPoint.java
  • src/main/java/com/pinHouse/server/platform/pinPoint/domain/repository/PinPointMongoRepository.java

Walkthrough

경로·거리 계산을 템플릿화하고 거리/시간/교통색상 유틸을 추가했으며, 진단 DTO를 상세/간략으로 재구성하고 여러 DTO에 OpenAPI 주석 및 필드(예: group) 변경을 적용했습니다. 여러 API 반환 타입과 관련 메서드가 변경되었습니다.

Changes

코호트 / 파일(s) 변경 요약
페이징 DTO 주석 변경
src/main/java/com/pinHouse/server/core/response/response/pageable/SliceRequest.java
클래스 레벨 @Tag 제거, @Schema 추가; page/offSet 설명 및 defaultValue 조정(0 기반 페이지 명시).
유틸 추가: 거리·시간·색상
src/main/java/com/pinHouse/server/core/util/DistanceCalculator.java, src/main/java/com/pinHouse/server/core/util/TimeFormatter.java, src/main/java/com/pinHouse/server/platform/housing/complex/application/util/TransportColorResolver.java
Haversine 기반 거리 계산기, 분→시간 포맷터, 교통 유형별 배경색 추출 유틸 추가(모두 non‑instantiable, public static).
진단 DTO 및 API 변경
src/main/java/com/pinHouse/server/platform/diagnostic/diagnosis/application/dto/DiagnosisDetailResponse.java, .../DiagnosisResponse.java, .../DiagnosisService.java, .../DiagnosisUseCase.java, .../DiagnosisApi.java, .../DiagnosisApiSpec.java
상세 DTO DiagnosisDetailResponse 추가, DiagnosisResponse 간소화(다수 필드 제거), 서비스·유스케이스·컨트롤러: getDiagnose()getDiagnoseDetail() 및 반환 타입 변경, 진단 이력 엔드포인트 제거.
복합 주택 경로·거리 로직 리팩토링
src/main/java/com/pinHouse/server/platform/housing/complex/application/service/ComplexService.java, .../ComplexUseCase.java, .../OdsayUtil.java
경로 계산을 calculateTransitRoute() 템플릿으로 통합, 기존 getDistance() 삭제, getSegments() 추가, 로컬 거리 계산 제거하고 DistanceCalculator 사용, 디버그 로그 제거.
Transit/Distance 응답 변경 및 매퍼 공개화
src/main/java/com/pinHouse/server/platform/housing/complex/application/dto/response/DistanceResponse.java, .../TransitResponseMapper.java, .../TransitRoutesResponse.java
DistanceResponse에서 stops 제거하고 routes만 유지, 시간 포맷을 TimeFormatter로 통일, TransitResponseMapper.toSegmentResponses() 공개화, minutesTextlabelText로 필드명 변경, step.secondaryText 노출 조정.
ComplexDetail/Deposit/Location/UnitType DTO 업데이트
src/main/java/com/pinHouse/server/platform/housing/complex/application/dto/response/ComplexDetailResponse.java, .../DepositResponse.java, .../LocationResponse.java, .../UnitTypeResponse.java
ComplexDetail의 distance 필드를 SegmentResponse 리스트로 변경, Deposit/Location에 @Schema 주석 추가, UnitTypeResponse에 group: List<String> 필드 및 주석 추가(팩토리에서 채움).
도메인: UnitType 확장
src/main/java/com/pinHouse/server/platform/housing/complex/domain/entity/UnitType.java
group: List<String> 필드 추가, 생성자/빌더 시그니처에 group 인자 추가.
공고·핀포인트·좋아요 DTO 주석·예시 업데이트
src/main/java/com/pinHouse/server/platform/housing/facility/application/dto/NoticeFacilityListResponse.java, .../NoticeDetailFilterRequest.java, .../LikeRequest.java, .../LikeApiSpec.java, .../UpdatePinPointRequest.java
다수 DTO에 @Schema 주석 추가/갱신, 시설 최대 갯수 제약(@Size(max=3)) 추가, 좋아요 예시 문자열 및 핀포인트 주석/예시 수정.
Notice 비교 DTO에 group 추가
src/main/java/com/pinHouse/server/platform/housing/notice/application/dto/UnitTypeCompareResponse.java
UnitTypeComparisonItem에 group: List<String> 추가 및 팩토리에서 채움.
기타 정리
src/main/java/com/pinHouse/server/platform/housing/complex/presentation/ComplexApi.java
사용되지 않는 import 제거(컴파일 영향 주의).

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant Client
    participant ComplexService
    participant ODsayAPI as ODsay (외부)
    participant TransitMapper as TransitResponseMapper
    participant DistanceCalc as DistanceCalculator

    Client->>ComplexService: getSegments(complexId, pinPointId)
    ComplexService->>ODsayAPI: request path (pinPoint)
    ODsayAPI-->>ComplexService: PathResult (root)
    ComplexService->>TransitMapper: toTransitRoutesResponse(PathResult) / toSegmentResponses
    TransitMapper-->>ComplexService: SegmentResponse list (labelText, steps, durations)
    ComplexService->>DistanceCalc: calculateDistanceKm(locationA, locationB) [필요시]
    DistanceCalc-->>ComplexService: distanceKm
    ComplexService-->>Client: List<SegmentResponse> (segments + distances)
    note right of ComplexService `#E6F4EA`: calculateTransitRoute 템플릿 흐름\n(ODsay 호출 → 매핑 → 거리 계산 → 반환)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 홉, 새로운 유틸이 와서 반짝,
길과 시간이 쓱쓱 정리되고,
진단은 깊고 얕게 나뉘었네,
DTO들엔 주석이 반짝반짝,
당근 들고 코드 정원에 폴짝!

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Title check ❓ Inconclusive PR 제목이 너무 광범위하고 모호하며, 실제 변경사항의 핵심을 구체적으로 나타내지 못함. 제목을 '♻️ refactor : 진단 DTO 리팩토링 및 방 그룹 기능 추가'와 같이 구체적인 주요 변경사항을 명시하는 것을 권장합니다.
✅ Passed checks (2 passed)
Check name Status Explanation
Description check ✅ Passed PR 설명이 주요 내용을 어느 정도 포함하고 있으나 스크린샷, 관련 이슈, 일부 체크리스트가 미완료 상태입니다.
Docstring Coverage ✅ Passed Docstring coverage is 93.33% which is sufficient. The required threshold is 80.00%.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link

github-actions bot commented Dec 27, 2025

Test Results

22 tests  ±0   22 ✅ ±0   0s ⏱️ ±0s
 3 suites ±0    0 💤 ±0 
 3 files   ±0    0 ❌ ±0 

Results for commit 8e850f7. ± Comparison against base commit d5672b5.

♻️ This comment has been updated with latest results.

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/main/java/com/pinHouse/server/platform/diagnostic/diagnosis/application/service/DiagnosisService.java (1)

74-80: 진단 기록이 없을 때 null 반환은 NPE 위험이 있습니다.

null 반환 대신 Optional<DiagnosisDetailResponse>를 반환하거나, 적절한 예외를 발생시키는 것이 권장됩니다. 현재 구현에서는 API 레이어에서 ApiResponse.ok(null)이 반환되어 클라이언트에서 예상치 못한 응답을 받을 수 있습니다.

🔎 Optional 사용 예시
-    public DiagnosisDetailResponse getDiagnoseDetail(UUID userId) {
+    public Optional<DiagnosisDetailResponse> getDiagnoseDetail(UUID userId) {
         User user = userService.loadUser(userId);
         Diagnosis diagnosis = repository.findTopByUserOrderByCreatedAtDesc(user)
                 .orElse(null);
         if (diagnosis == null) {
-            return null;
+            return Optional.empty();
         }
         EvaluationContext context = ruleChain.evaluateAll(diagnosis);
-        return DiagnosisDetailResponse.from(context);
+        return Optional.of(DiagnosisDetailResponse.from(context));
     }
src/main/java/com/pinHouse/server/platform/housing/complex/application/dto/response/ComplexDetailResponse.java (1)

61-65: NumberFormatException 발생 가능성을 고려하세요.

document.getTotalHouseholds()가 숫자가 아닌 문자열일 경우 Integer.parseInt()에서 예외가 발생합니다. 방어적 파싱을 고려해보세요.

🔎 방어적 파싱 제안
 .totalHouseholds(
-        document.getTotalHouseholds() == null || document.getTotalHouseholds().equals("")
-                ? 0
-                : Integer.parseInt(document.getTotalHouseholds())
+        parseIntOrDefault(document.getTotalHouseholds(), 0)
 )

별도 헬퍼 메서드:

private static int parseIntOrDefault(String value, int defaultValue) {
    if (value == null || value.isBlank()) {
        return defaultValue;
    }
    try {
        return Integer.parseInt(value);
    } catch (NumberFormatException e) {
        return defaultValue;
    }
}
🧹 Nitpick comments (9)
src/main/java/com/pinHouse/server/core/response/response/pageable/SliceRequest.java (1)

11-12: 필드명 표기법 개선 고려

offSet 필드명이 일반적인 Java 네이밍 컨벤션(offset)과 다릅니다. 일관성을 위해 camelCase 표기법(offset)으로 변경하는 것을 고려해보세요.

참고: 이미 사용 중인 필드명이라면 하위 호환성을 위해 현재 상태를 유지하되, 향후 API 버전 업데이트 시 개선을 고려할 수 있습니다.

src/main/java/com/pinHouse/server/platform/like/presentation/swagger/LikeApiSpec.java (1)

57-63: Swagger 예시 값의 일관성이 필요합니다.

NOTICE_EXAMPLE의 targetId "19417"은 Swagger 문서의 API 예시값입니다. 다른 API 문서인 NoticeSearchResultResponse에서는 동일한 공고 ID 예시로 "18442"를 사용하고 있어, API 소비자에게 혼란을 줄 수 있습니다. Like 관련 API와 다른 API 문서에서 동일한 엔티티 타입의 예시 ID를 통일하는 것이 권장됩니다.

src/main/java/com/pinHouse/server/platform/housing/notice/application/dto/NoticeDetailFilterRequest.java (1)

14-38: Swagger 문서화가 명확하게 추가되었고 예제값도 정확합니다.

API 사용성 개선이 잘 이루어졌으며, 예제값 ["청년", "신혼부부"]는 실제 NoticeListRequest.TargetType enum의 label 값과 정확히 일치합니다.

다만 다음 사항을 고려해보시기 바랍니다:

숫자 필드의 음수 입력 방지: transitTime, maxDeposit, maxMonthPay 필드는 음수가 허용되지 않을 것으로 보이는데, @PositiveOrZero 제약조건 추가를 권장합니다.

+import jakarta.validation.constraints.PositiveOrZero;

         @Schema(description = "대중교통 최대 소요 시간 (분)", example = "100")
+        @PositiveOrZero(message = "소요 시간은 0 이상이어야 합니다")
         int transitTime,

         @Schema(description = "보증금 최대값 (원)", example = "50000000")
+        @PositiveOrZero(message = "보증금은 0 이상이어야 합니다")
         int maxDeposit,

         @Schema(description = "월 임대료 최대값 (원)", example = "300000")
+        @PositiveOrZero(message = "월 임대료는 0 이상이어야 합니다")
         int maxMonthPay,
src/main/java/com/pinHouse/server/platform/diagnostic/diagnosis/application/dto/DiagnosisDetailResponse.java (2)

132-136: 추천 후보 리스트 생성 로직이 DiagnosisResponse와 중복됩니다.

DiagnosisResponse.from() 메서드에도 동일한 로직이 존재합니다. 유지보수성과 일관성을 위해 공통 유틸리티 메서드로 추출하는 것을 권장합니다.

🔎 공통 메서드 추출 예시
// EvaluationContext 또는 별도 유틸리티 클래스에 추가
public static List<String> toRecommendedList(List<Candidate> candidates) {
    return candidates.isEmpty() ?
            List.of("해당 없음") :
            candidates.stream()
                    .map(c -> c.noticeType().getValue() + " : " + c.supplyType().getValue())
                    .toList();
}

184-186: 문자열 기반 자격 여부 판단이 취약합니다.

recommended.contains("해당 없음") 문자열 매칭은 메시지 변경 시 버그가 발생할 수 있습니다. context.getCurrentCandidates().isEmpty()를 직접 사용하는 것이 더 안전합니다.

🔎 개선 제안
+        boolean hasRecommendation = !context.getCurrentCandidates().isEmpty();
+
         return DiagnosisDetailResponse.builder()
                 // ... 기존 빌더 코드 ...
-                .eligible(!recommended.contains("해당 없음"))
-                .diagnosisResult(!recommended.contains("해당 없음") ?
+                .eligible(hasRecommendation)
+                .diagnosisResult(hasRecommendation ?
                         "추천 임대주택이 있습니다" : "모든 조건 미충족")
                 .recommended(recommended)
                 .build();
src/main/java/com/pinHouse/server/platform/diagnostic/diagnosis/application/dto/DiagnosisResponse.java (1)

40-45: DiagnosisDetailResponse와 동일한 문자열 기반 자격 판단 문제가 있습니다.

DiagnosisDetailResponse.from()에서 지적한 것과 동일하게, recommended.contains("해당 없음") 대신 context.getCurrentCandidates().isEmpty()를 직접 사용하는 것이 더 안전합니다.

🔎 개선 제안
     public static DiagnosisResponse from(EvaluationContext context) {
+        boolean hasRecommendation = !context.getCurrentCandidates().isEmpty();
+
         List<String> recommended = context.getCurrentCandidates().isEmpty() ?
                 List.of("해당 없음") :
                 context.getCurrentCandidates().stream()
                         .map((c -> c.noticeType().getValue() + " : " + c.supplyType().getValue()))
                         .toList();

         return DiagnosisResponse.builder()
-                .eligible(!recommended.contains("해당 없음"))
-                .decisionMessage(!recommended.contains("해당 없음") ?
+                .eligible(hasRecommendation)
+                .decisionMessage(hasRecommendation ?
                         "추천 임대주택이 있습니다" : "모든 조건 미충족")
                 .recommended(recommended)
                 .build();
     }
src/main/java/com/pinHouse/server/platform/housing/complex/application/util/TransportColorResolver.java (1)

25-64: switch 표현식 사용을 고려해보세요.

현재 if-else 체인이 ChipType 값에 따라 분기하고 있어, switch 표현식으로 리팩토링하면 가독성과 유지보수성이 향상될 수 있습니다.

🔎 switch 표현식 리팩토링 제안
 public static String extractBgColorHex(RootResult.DistanceStep step, ChipType type) {
     if (step == null || type == null) {
         return DEFAULT_COLOR;
     }

-    // WALK와 AIR는 ChipType의 defaultBg 사용
-    if (type == ChipType.WALK || type == ChipType.AIR) {
-        return type.defaultBg;
-    }
-
-    // SUBWAY: subwayLine enum의 색상 사용
-    if (type == ChipType.SUBWAY) {
-        if (step.subwayLine() != null) {
-            return step.subwayLine().getColorHex();
-        }
-        return DEFAULT_COLOR;
-    }
-
-    // BUS: busRouteType 또는 expressBusType enum의 색상 사용
-    if (type == ChipType.BUS) {
-        if (step.busRouteType() != null) {
-            return step.busRouteType().getColorHex();
-        }
-        if (step.expressBusType() != null) {
-            return step.expressBusType().getColorHex();
-        }
-        return DEFAULT_COLOR;
-    }
-
-    // TRAIN: trainType enum의 색상 사용
-    if (type == ChipType.TRAIN) {
-        if (step.trainType() != null) {
-            return step.trainType().getColorHex();
-        }
-        return DEFAULT_COLOR;
-    }
-
-    // 그 외의 경우 기본 회색 반환
-    return DEFAULT_COLOR;
+    return switch (type) {
+        case WALK, AIR -> type.defaultBg != null ? type.defaultBg : DEFAULT_COLOR;
+        case SUBWAY -> step.subwayLine() != null ? step.subwayLine().getColorHex() : DEFAULT_COLOR;
+        case BUS -> {
+            if (step.busRouteType() != null) yield step.busRouteType().getColorHex();
+            if (step.expressBusType() != null) yield step.expressBusType().getColorHex();
+            yield DEFAULT_COLOR;
+        }
+        case TRAIN -> step.trainType() != null ? step.trainType().getColorHex() : DEFAULT_COLOR;
+        default -> DEFAULT_COLOR;
+    };
 }
src/main/java/com/pinHouse/server/platform/housing/complex/domain/entity/UnitType.java (1)

36-37: 리스트 불변성 적용을 고려해보세요.

group 필드가 외부에서 수정 가능한 List<String>으로 저장됩니다. 도메인 객체의 불변성을 위해 생성자에서 방어적 복사를 고려해볼 수 있습니다.

🔎 불변 리스트 적용 제안
 @Builder
 public UnitType(String typeId, String typeCode, String complexId, double exclusiveAreaM2, int monthlyRent, Deposit deposit, Quota quota, List<String> group) {
     this.typeId = typeId;
     this.typeCode = typeCode;
     this.complexId = complexId;
     this.exclusiveAreaM2 = exclusiveAreaM2;
     this.monthlyRent = monthlyRent;
     this.deposit = deposit;
     this.quota = quota;
-    this.group = group;
+    this.group = group != null ? List.copyOf(group) : null;
 }
src/main/java/com/pinHouse/server/platform/housing/complex/application/util/TransitResponseMapper.java (1)

455-472: assignStepIndexes 메서드 - 불변 객체 재생성 비용

StepResponse가 record(불변 객체)이므로 인덱스 부여 시 전체 필드를 복사하여 새 객체를 생성합니다. 현재 최대 3개 경로의 제한된 step 수에서는 성능 영향이 미미하지만, 향후 확장 시 stepIndex를 builder 생성 시점에 직접 설정하는 방식을 고려해볼 수 있습니다.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d5672b5 and e1a8224.

📒 Files selected for processing (27)
  • src/main/java/com/pinHouse/server/core/response/response/pageable/SliceRequest.java
  • src/main/java/com/pinHouse/server/core/util/DistanceCalculator.java
  • src/main/java/com/pinHouse/server/core/util/TimeFormatter.java
  • src/main/java/com/pinHouse/server/platform/diagnostic/diagnosis/application/dto/DiagnosisDetailResponse.java
  • src/main/java/com/pinHouse/server/platform/diagnostic/diagnosis/application/dto/DiagnosisResponse.java
  • src/main/java/com/pinHouse/server/platform/diagnostic/diagnosis/application/service/DiagnosisService.java
  • src/main/java/com/pinHouse/server/platform/diagnostic/diagnosis/application/usecase/DiagnosisUseCase.java
  • src/main/java/com/pinHouse/server/platform/diagnostic/diagnosis/presentation/DiagnosisApi.java
  • src/main/java/com/pinHouse/server/platform/diagnostic/diagnosis/presentation/swagger/DiagnosisApiSpec.java
  • src/main/java/com/pinHouse/server/platform/housing/complex/application/dto/response/ComplexDetailResponse.java
  • src/main/java/com/pinHouse/server/platform/housing/complex/application/dto/response/DepositResponse.java
  • src/main/java/com/pinHouse/server/platform/housing/complex/application/dto/response/DistanceResponse.java
  • src/main/java/com/pinHouse/server/platform/housing/complex/application/dto/response/LocationResponse.java
  • src/main/java/com/pinHouse/server/platform/housing/complex/application/dto/response/UnitTypeResponse.java
  • src/main/java/com/pinHouse/server/platform/housing/complex/application/service/ComplexService.java
  • src/main/java/com/pinHouse/server/platform/housing/complex/application/usecase/ComplexUseCase.java
  • src/main/java/com/pinHouse/server/platform/housing/complex/application/util/TransitResponseMapper.java
  • src/main/java/com/pinHouse/server/platform/housing/complex/application/util/TransportColorResolver.java
  • src/main/java/com/pinHouse/server/platform/housing/complex/domain/entity/UnitType.java
  • src/main/java/com/pinHouse/server/platform/housing/complex/external/OdsayUtil.java
  • src/main/java/com/pinHouse/server/platform/housing/complex/presentation/ComplexApi.java
  • src/main/java/com/pinHouse/server/platform/housing/facility/application/dto/NoticeFacilityListResponse.java
  • src/main/java/com/pinHouse/server/platform/housing/notice/application/dto/NoticeDetailFilterRequest.java
  • src/main/java/com/pinHouse/server/platform/housing/notice/application/dto/UnitTypeCompareResponse.java
  • src/main/java/com/pinHouse/server/platform/like/application/dto/LikeRequest.java
  • src/main/java/com/pinHouse/server/platform/like/presentation/swagger/LikeApiSpec.java
  • src/main/java/com/pinHouse/server/platform/pinPoint/application/dto/UpdatePinPointRequest.java
💤 Files with no reviewable changes (3)
  • src/main/java/com/pinHouse/server/platform/housing/complex/presentation/ComplexApi.java
  • src/main/java/com/pinHouse/server/platform/housing/complex/external/OdsayUtil.java
  • src/main/java/com/pinHouse/server/platform/housing/complex/application/usecase/ComplexUseCase.java
🧰 Additional context used
🧬 Code graph analysis (1)
src/main/java/com/pinHouse/server/core/util/TimeFormatter.java (2)
src/main/java/com/pinHouse/server/core/util/DistanceCalculator.java (1)
  • NoArgsConstructor (11-57)
src/main/java/com/pinHouse/server/platform/housing/complex/application/util/TransportColorResolver.java (1)
  • NoArgsConstructor (12-65)
🔇 Additional comments (27)
src/main/java/com/pinHouse/server/platform/housing/facility/application/dto/NoticeFacilityListResponse.java (2)

13-13: API 문서화 개선이 적절합니다.

OpenAPI 스키마 어노테이션 추가로 API 문서의 가독성이 향상되었습니다.


15-16: 필드 문서화가 잘 작성되었습니다.

스키마 어노테이션이 필터링 로직(3개 이상)과 일치하며, 예시에 사용된 PARK, LIBRARY, HOSPITAL은 모두 FacilityType enum에 정의되어 있는 유효한 상수입니다.

src/main/java/com/pinHouse/server/platform/like/application/dto/LikeRequest.java (2)

6-6: 문서화 개선이 잘 적용되었습니다.

클래스 레벨의 @Schema 어노테이션을 추가하여 API 문서의 가독성을 향상시켰습니다. 한글 이름과 설명이 명확하게 작성되었습니다.


11-12: 타입 필드 문서화가 잘 작성되었습니다.

allowableValues를 명시하여 API 사용자가 허용되는 값을 명확히 알 수 있도록 했습니다. 설명도 명확합니다.

src/main/java/com/pinHouse/server/platform/like/presentation/swagger/LikeApiSpec.java (1)

65-71: Swagger 문서 예제 ID는 유효성 검증이 필요 없습니다.

"4b30ca7d718d4ea9a9f6966f"는 COMPLEX_EXAMPLE 정의에만 사용되는 Swagger 문서 예제입니다. 실제 코드 동작에 사용되지 않으므로 데이터베이스에 존재하는 유효한 ID일 필요가 없습니다. MongoDB ObjectId 형식(24자 16진수)은 이미 올바르며, 문서 예제로서 적절합니다.

src/main/java/com/pinHouse/server/platform/housing/notice/application/dto/NoticeDetailFilterRequest.java (2)

11-11: LGTM! 클래스 레벨 문서화가 잘 추가되었습니다.

API 문서의 가독성을 높이는 명확한 설명이 추가되었습니다.


39-41: LGTM! 크기 제약조건이 설명과 일관되게 추가되었습니다.

facilities 필드의 "최대 3개까지 가능"이라는 설명이 @Size(max = 3) 검증 로직으로 정확히 구현되었습니다. 설명과 검증이 일치하는 좋은 예시입니다.

src/main/java/com/pinHouse/server/platform/diagnostic/diagnosis/application/dto/DiagnosisDetailResponse.java (1)

153-154: isCollegeStudent 판단 로직 검증이 필요합니다.

diagnosis.getEducationStatus() != null은 교육 상태가 존재하는지만 확인하며, 실제로 대학생인지 여부를 정확히 판단하지 못할 수 있습니다. 예를 들어, 졸업생이나 대학원생도 educationStatus가 존재할 수 있습니다.

도메인 로직상 educationStatus가 오직 대학생인 경우에만 설정되는지 확인해 주세요. 그렇지 않다면 특정 값 비교가 필요할 수 있습니다.

src/main/java/com/pinHouse/server/platform/diagnostic/diagnosis/application/usecase/DiagnosisUseCase.java (1)

14-15: LGTM!

인터페이스 시그니처가 서비스 레이어의 변경사항과 일관되게 업데이트되었습니다.

src/main/java/com/pinHouse/server/platform/diagnostic/diagnosis/presentation/swagger/DiagnosisApiSpec.java (1)

23-27: LGTM!

Swagger 명세가 새로운 DiagnosisDetailResponse DTO와 일관되게 업데이트되었으며, API 설명이 명확합니다.

src/main/java/com/pinHouse/server/platform/housing/complex/application/dto/response/LocationResponse.java (1)

7-13: LGTM! Swagger 문서화가 잘 되어있습니다.

위도/경도에 대한 설명과 예시가 명확하게 추가되었습니다.

src/main/java/com/pinHouse/server/platform/housing/complex/application/dto/response/DepositResponse.java (1)

11-18: LGTM! 필드별 Swagger 문서화가 적절합니다.

최소/보통/최대 보증금 정보에 대한 설명이 명확하게 추가되었습니다.

src/main/java/com/pinHouse/server/core/util/TimeFormatter.java (1)

1-56: LGTM! 유틸리티 클래스가 잘 구현되어 있습니다.

시간 포맷팅 로직이 중앙화되어 코드 중복이 줄어들 것입니다. 엣지 케이스(0, 음수, 정각 시간, 시간+분)가 적절히 처리되었습니다.

src/main/java/com/pinHouse/server/core/util/DistanceCalculator.java (1)

1-57: LGTM! Haversine 공식이 올바르게 구현되었습니다.

거리 계산 로직이 중앙화되어 일관성이 향상됩니다. IllegalArgumentException을 통한 null 검증도 적절합니다.

src/main/java/com/pinHouse/server/platform/housing/complex/application/dto/response/ComplexDetailResponse.java (2)

50-54: 응답 스키마 변경에 따른 프론트엔드 호환성을 확인하세요.

distance 필드 타입이 DistanceResponse에서 List<SegmentResponse>로 변경되었습니다. PR 노트에 명시된 대로 프론트엔드 통합 테스트가 필요합니다.


127-127: LGTM! TimeFormatter 사용으로 시간 포맷팅이 중앙화되었습니다.

로컬 formatTime 메서드 대신 공통 유틸리티 클래스를 사용하여 코드 일관성이 향상되었습니다.

src/main/java/com/pinHouse/server/platform/housing/notice/application/dto/UnitTypeCompareResponse.java (1)

59-63: LGTM! group 필드가 일관된 패턴으로 추가되었습니다.

null-safe 처리(unitType.getGroup() != null ? ... : List.of())가 nearbyFacilities 필드와 동일한 패턴으로 적용되어 일관성이 유지됩니다.

Also applies to: 83-83

src/main/java/com/pinHouse/server/platform/housing/complex/domain/entity/UnitType.java (1)

41-50: LGTM! 도메인 엔티티에 group 필드가 적절하게 추가되었습니다.

MongoDB 필드 매핑과 빌더 생성자가 올바르게 업데이트되었습니다.

src/main/java/com/pinHouse/server/platform/housing/complex/application/util/TransportColorResolver.java (1)

30-33: 이 concern은 근거가 없습니다.

ChipType 열거형을 확인한 결과, WALKAIR 모두 생성자에서 명시적으로 non-null 문자열 값으로 초기화됩니다 (WALK("#BBBAC5"), AIR("#2C7A7B")). defaultBg 필드는 final String이며 항상 null이 아닌 값으로 설정되므로, 이 코드는 안전합니다.

Likely an incorrect or invalid review comment.

src/main/java/com/pinHouse/server/platform/housing/complex/application/util/TransitResponseMapper.java (2)

17-36: 문서화 개선 승인

클래스의 책임과 지원하는 스키마를 명확하게 문서화하여 유지보수성이 향상되었습니다. 신규 스키마(TransitRoutesResponse)와 구 스키마(DistanceResponse)의 구분이 명확합니다.


243-277: toSegmentResponses 메서드의 public 접근 제어자 변경 및 로직 개선 승인

외부에서 Segment 리스트를 직접 조회할 수 있도록 public으로 변경된 것은 ComplexService.getSegments()에서 사용되는 설계 의도와 일치합니다. minutesText 로직이 교통수단 타입별로 적절하게 분기 처리되었습니다.

다만, normalizeLine 반환값이 null일 수 있으므로 Line 262에서 null 할당이 의도된 것인지 확인이 필요합니다.

src/main/java/com/pinHouse/server/platform/housing/complex/application/dto/response/DistanceResponse.java (1)

30-42: 응답 구조 단순화 및 TimeFormatter 통합 승인

stops 필드 제거와 TimeFormatter.formatTimeOrNull() 사용으로 코드가 간결해졌습니다. AI 요약에서 언급된 대로 TransferPointResponse 중첩 타입도 함께 제거되어 응답 스키마가 정리되었습니다.

PR 목표에서 프론트엔드 통합 테스트 요청이 있었으므로, stops 필드를 사용하던 클라이언트가 있는지 확인이 필요합니다.

src/main/java/com/pinHouse/server/platform/housing/complex/application/dto/response/UnitTypeResponse.java (1)

11-36: Swagger 문서화 개선 승인

DTO 필드에 상세한 OpenAPI 메타데이터가 추가되어 API 문서의 가독성과 활용성이 향상되었습니다.

src/main/java/com/pinHouse/server/platform/housing/complex/application/service/ComplexService.java (4)

403-443: 템플릿 메서드 패턴 도입 승인

calculateTransitRoute 메서드로 공통 로직(complex/pinpoint 조회, 경로 계산)을 추출하여 코드 중복이 제거되었습니다. Function<PathResult, T> 매퍼를 통한 결과 변환 위임은 유연한 설계입니다.


72-76: getComplex 메서드 Segment 기반 응답 변경 승인

DistanceResponse 대신 List<SegmentResponse>를 사용하도록 변경되어 새로운 스키마 구조와 일치합니다. ComplexDetailResponse.from() 시그니처 변경과 연동됩니다.


204-206: DistanceCalculator 유틸리티 사용 승인

거리 계산 로직이 DistanceCalculator.calculateDistanceKm()으로 중앙화되어 일관성이 향상되었습니다.


466-471: getEasyDistance 템플릿 메서드 활용 승인

기존 로직을 calculateTransitRoute 템플릿으로 위임하여 중복 코드가 제거되었습니다. 캐싱 로직은 그대로 유지되어 기존 동작과 호환됩니다.

Comment on lines +8 to 9
@Schema(description = "페이지 번호 (0부터 시작)", example = "0", defaultValue = "1")
int page,
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

페이지 번호 기본값 불일치 수정 필요

설명과 예시는 0부터 시작한다고 명시되어 있지만, defaultValue는 "1"로 설정되어 있습니다. 이는 API 문서를 혼란스럽게 만들 수 있습니다.

🔎 제안하는 수정
-        @Schema(description = "페이지 번호 (0부터 시작)", example = "0", defaultValue = "1")
+        @Schema(description = "페이지 번호 (0부터 시작)", example = "0", defaultValue = "0")
         int page,
📝 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
@Schema(description = "페이지 번호 (0부터 시작)", example = "0", defaultValue = "1")
int page,
@Schema(description = "페이지 번호 (0부터 시작)", example = "0", defaultValue = "0")
int page,
🤖 Prompt for AI Agents
In
src/main/java/com/pinHouse/server/core/response/response/pageable/SliceRequest.java
around lines 8-9, the @Schema for the page field documents "페이지 번호 (0부터 시작)" and
example "0" but sets defaultValue = "1"; update the annotation so the
defaultValue matches the documented zero-based indexing (e.g., change
defaultValue to "0") or adjust the description/example to reflect a 1-based
default—pick the correct convention for the API and make the annotation
consistent.

Comment on lines +50 to 53
DiagnosisDetailResponse response = service.getDiagnoseDetail(principalDetails.getId());

/// 리턴
return ApiResponse.ok(response);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

서비스에서 null이 반환될 경우 처리가 필요합니다.

getDiagnoseDetail()이 진단 기록이 없을 때 null을 반환하면 ApiResponse.ok(null)이 됩니다. 클라이언트에게 명확한 응답(예: 404 또는 빈 상태 메시지)을 제공하는 것이 사용자 경험에 더 좋습니다.

🔎 개선 예시
     public ApiResponse<DiagnosisDetailResponse> getLatestDiagnosis(@AuthenticationPrincipal PrincipalDetails principalDetails) {
         DiagnosisDetailResponse response = service.getDiagnoseDetail(principalDetails.getId());
+        if (response == null) {
+            return ApiResponse.noContent(); // 또는 적절한 빈 응답 처리
+        }
         return ApiResponse.ok(response);
     }
📝 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
DiagnosisDetailResponse response = service.getDiagnoseDetail(principalDetails.getId());
/// 리턴
return ApiResponse.ok(response);
DiagnosisDetailResponse response = service.getDiagnoseDetail(principalDetails.getId());
if (response == null) {
return ApiResponse.noContent(); // 또는 적절한 빈 응답 처리
}
/// 리턴
return ApiResponse.ok(response);
🤖 Prompt for AI Agents
In
src/main/java/com/pinHouse/server/platform/diagnostic/diagnosis/presentation/DiagnosisApi
around lines 50-53, the controller currently passes whatever
service.getDiagnoseDetail(...) returns directly to ApiResponse.ok, which results
in ApiResponse.ok(null) when no diagnosis exists; modify the controller to check
the returned value for null and, if null, return an appropriate non-200 response
(for example an ApiResponse.notFound(...) or an ApiResponse.error(...) with a
clear "diagnosis not found" message) otherwise return ApiResponse.ok(response);
ensure the null-check uses the principalDetails.getId() call you already have
and that the response shape matches existing API conventions.

Comment on lines +51 to 52
.group(unitType.getGroup())
.build();
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

find . -name "UnitType.java" -o -name "UnitTypeResponse.java" | head -20

Repository: PinHouse/PinHouse_BE

Length of output: 260


🏁 Script executed:

find . -type f -name "*.java" | xargs grep -l "class UnitType\|class UnitTypeResponse" | head -20

Repository: PinHouse/PinHouse_BE

Length of output: 152


🏁 Script executed:

cat -n ./src/main/java/com/pinHouse/server/platform/housing/complex/domain/entity/UnitType.java

Repository: PinHouse/PinHouse_BE

Length of output: 1669


🏁 Script executed:

cat -n ./src/main/java/com/pinHouse/server/platform/housing/complex/application/dto/response/UnitTypeResponse.java

Repository: PinHouse/PinHouse_BE

Length of output: 2516


🏁 Script executed:

rg -n "\.getGroup\(\)|\.group" ./src/main/java/com/pinHouse/server/platform/housing/complex/ -A2 -B2

Repository: PinHouse/PinHouse_BE

Length of output: 1323


group 필드 null 처리 확인 필요

unitType.getGroup()null을 반환할 경우 응답에 null이 포함됩니다. 응답 스키마에 nullable = true 표시가 없으므로 클라이언트는 리스트를 기대합니다. null-safe 처리가 필요합니다.

                .liked(liked)
-               .group(unitType.getGroup())
+               .group(unitType.getGroup() != null ? unitType.getGroup() : List.of())
                .build();
🤖 Prompt for AI Agents
In
src/main/java/com/pinHouse/server/platform/housing/complex/application/dto/response/UnitTypeResponse.java
around lines 51-52, the builder sets .group(unitType.getGroup()) which may be
null and the response schema does not mark the field nullable; guard against
null by converting null to an empty list before passing to the builder (e.g. use
Optional.ofNullable(unitType.getGroup()).orElseGet(Collections::emptyList) or
List.of()), ensuring the API always returns an empty list rather than null.

Comment on lines +445 to +452
/// Segment 리스트 조회 (임대주택 상세조회용)
@Transactional(readOnly = true)
public List<TransitRoutesResponse.SegmentResponse> getSegments(String id, String pinPointId) throws UnsupportedEncodingException {
return calculateTransitRoute(id, pinPointId, pathResult -> {
RootResult rootResult = mapper.selectBest(pathResult);
return mapper.toSegmentResponses(rootResult);
});
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if getSegments is defined in ComplexUseCase interface
rg -n "getSegments" --type=java -g '**/ComplexUseCase.java'

Repository: PinHouse/PinHouse_BE

Length of output: 46


🏁 Script executed:

#!/bin/bash
# Check external calls to getSegments outside ComplexService
rg -n "getSegments\s*\(" --type=java -g '!**/ComplexService.java' -A 2

Repository: PinHouse/PinHouse_BE

Length of output: 46


🏁 Script executed:

#!/bin/bash
# Check ComplexService class declaration and interface implementation
rg -n "class ComplexService" --type=java -A 3

Repository: PinHouse/PinHouse_BE

Length of output: 596


🏁 Script executed:

#!/bin/bash
# Search for all getSegments calls across the entire codebase
rg -n "getSegments" --type=java

Repository: PinHouse/PinHouse_BE

Length of output: 495


🏁 Script executed:

#!/bin/bash
# Check ComplexUseCase interface definition
fd -t f "ComplexUseCase.java" --type f

Repository: PinHouse/PinHouse_BE

Length of output: 162


🏁 Script executed:

#!/bin/bash
# Look for ComplexUseCase interface file path
find . -name "ComplexUseCase.java" -type f

Repository: PinHouse/PinHouse_BE

Length of output: 164


🏁 Script executed:

#!/bin/bash
# Read ComplexUseCase interface to check method definitions
cat -n ./src/main/java/com/pinHouse/server/platform/housing/complex/application/usecase/ComplexUseCase.java

Repository: PinHouse/PinHouse_BE

Length of output: 2760


getSegments 메서드를 private으로 변경하세요

getSegments는 ComplexUseCase 인터페이스에 정의되어 있지 않으며, 오직 ComplexService 내부(line 73)에서만 호출됩니다. 외부 호출이 없는 내부 헬퍼 메서드이므로 public이 아닌 private으로 변경해야 합니다.

🤖 Prompt for AI Agents
In
src/main/java/com/pinHouse/server/platform/housing/complex/application/service/ComplexService.java
around lines 445-452, the getSegments method is declared public but is only used
internally (called at line 73) and is not part of the ComplexUseCase interface;
change its visibility to private (i.e., replace public with private) so it
becomes an internal helper, then recompile/run tests and update any callers if
there are unexpected external references (there should be none).

Comment on lines +8 to 9
@Schema(description = "좋아요 대상 ID (공고 ID 또는 유닛타입 ID)", example = "19417 또는 type456", required = true)
String targetId,
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

예시 값이 실제 사용 패턴과 불일치합니다.

targetId의 example 값으로 "19417 또는 type456"이 지정되어 있지만, LikeApiSpec.java의 실제 예시를 보면:

  • NOTICE 타입: "19417" (숫자 형식)
  • ROOM 타입: "4b30ca7d718d4ea9a9f6966f" (MongoDB ObjectId 형식)

"type456"은 실제로 사용되는 ID 형식과 맞지 않습니다.

🔎 더 정확한 예시로 수정 제안
-        @Schema(description = "좋아요 대상 ID (공고 ID 또는 유닛타입 ID)", example = "19417 또는 type456", required = true)
+        @Schema(description = "좋아요 대상 ID (공고 ID 또는 유닛타입 ID)", example = "19417", required = true)

또는 두 형식을 모두 명시하려면:

-        @Schema(description = "좋아요 대상 ID (공고 ID 또는 유닛타입 ID)", example = "19417 또는 type456", required = true)
+        @Schema(description = "좋아요 대상 ID (공고 ID는 숫자, 유닛타입 ID는 ObjectId 형식)", example = "19417", required = true)
📝 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
@Schema(description = "좋아요 대상 ID (공고 ID 또는 유닛타입 ID)", example = "19417 또는 type456", required = true)
String targetId,
@Schema(description = "좋아요 대상 ID는 숫자, 유닛타입 ID는 ObjectId 형식", example = "19417", required = true)
String targetId,
🤖 Prompt for AI Agents
In
src/main/java/com/pinHouse/server/platform/like/application/dto/LikeRequest.java
around lines 8-9, the @Schema example value "19417 또는 type456" is inaccurate;
replace it with realistic examples that match LikeApiSpec (e.g., NOTICE numeric
id "19417" and ROOM MongoDB ObjectId "4b30ca7d718d4ea9a9f6966f") or present both
formats clearly (e.g., "예: 19417 또는 4b30ca7d718d4ea9a9f6966f"); update the
example string in the annotation to one of these corrected representations.

Comment on lines 5 to 9
@Schema(name = "[요청][핀포인트] 핀포인트 이름 수정", description = "사용자가 등록한 핀포인트의 이름을 수정하는 요청 DTO")
public record UpdatePinPointRequest(
@Schema(description = "핀 포인트 이름", example = "서울역")
@Schema(description = "변경할 핀포인트 이름 (최대 20자)", example = "서울역 근처 집")
String name
) {
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's examine the UpdatePinPointRequest file
cd /tmp && find . -name "UpdatePinPointRequest.java" -type f 2>/dev/null | head -5

Repository: PinHouse/PinHouse_BE

Length of output: 46


🏁 Script executed:

# Search for the file in the repository
git ls-files | grep -i "updatepinpointrequest.java"

Repository: PinHouse/PinHouse_BE

Length of output: 158


🏁 Script executed:

# Let's search for Java files in the pinPoint application directory
git ls-files | grep -i "pinpoint" | grep -i "application\|service\|controller" | head -20

Repository: PinHouse/PinHouse_BE

Length of output: 523


🏁 Script executed:

cat -n src/main/java/com/pinHouse/server/platform/pinPoint/application/dto/UpdatePinPointRequest.java

Repository: PinHouse/PinHouse_BE

Length of output: 476


🏁 Script executed:

cat -n src/main/java/com/pinHouse/server/platform/pinPoint/application/service/PinPointService.java

Repository: PinHouse/PinHouse_BE

Length of output: 5025


🏁 Script executed:

cat -n src/main/java/com/pinHouse/server/platform/pinPoint/application/usecase/PinPointUseCase.java

Repository: PinHouse/PinHouse_BE

Length of output: 1380


🏁 Script executed:

# Find controller that uses UpdatePinPointRequest
rg -n "UpdatePinPointRequest" --type java -B 5 -A 5 | head -50

Repository: PinHouse/PinHouse_BE

Length of output: 6603


🏁 Script executed:

# Find the PinPoint entity and check updateName method
find . -name "PinPoint.java" -type f | grep -i "domain"

Repository: PinHouse/PinHouse_BE

Length of output: 145


🏁 Script executed:

# Search for validation-related imports in the entire pinPoint directory
rg -n "jakarta.validation|javax.validation|@Valid|@Size|@Length|@NotBlank" src/main/java/com/pinHouse/server/platform/pinPoint/ --type java

Repository: PinHouse/PinHouse_BE

Length of output: 921


🏁 Script executed:

cat -n src/main/java/com/pinHouse/server/platform/pinPoint/presentation/PinPointApi.java

Repository: PinHouse/PinHouse_BE

Length of output: 3182


🏁 Script executed:

cat -n src/main/java/com/pinHouse/server/platform/pinPoint/domain/entity/PinPoint.java

Repository: PinHouse/PinHouse_BE

Length of output: 2292


필수 유효성 검증 어노테이션 추가 필요

필드 설명에 "최대 20자" 제약이 명시되어 있으나, 해당 필드에 검증 어노테이션이 없습니다. 컨트롤러에서 이미 @Valid 어노테이션을 사용하고 있으므로, DTO에 검증 제약을 추가해야 합니다.

다음과 같이 수정하세요:

+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.Size;
+
 @Schema(name = "[요청][핀포인트] 핀포인트 이름 수정", description = "사용자가 등록한 핀포인트의 이름을 수정하는 요청 DTO")
 public record UpdatePinPointRequest(
+        @NotBlank(message = "핀포인트 이름은 필수입니다")
+        @Size(max = 20, message = "핀포인트 이름은 최대 20자까지 입력 가능합니다")
         @Schema(description = "변경할 핀포인트 이름 (최대 20자)", example = "서울역 근처 집")
         String name
 ) {

API 문서와 실제 동작 간의 일관성을 유지하기 위해 필수적입니다.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In
src/main/java/com/pinHouse/server/platform/pinPoint/application/dto/UpdatePinPointRequest.java
around lines 5 to 9, the record field documents a "max 20 chars" constraint but
has no validation annotations; add appropriate validation annotations to the
record component (e.g., @NotBlank and @Size(max = 20)) so the controller's
@Valid will enforce the rule, and add the corresponding import(s)
(jakarta.validation.constraints.NotBlank and jakarta.validation.constraints.Size
or your project's validation package) at the top of the file.

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

🧹 Nitpick comments (1)
src/main/java/com/pinHouse/server/platform/housing/complex/application/util/TransitResponseMapper.java (1)

254-268: 라벨 텍스트 생성 로직이 명확합니다.

교통수단별로 적절한 라벨 텍스트를 생성하는 로직이 잘 구현되었습니다. 향후 유지보수성을 위해 별도 메서드로 추출하는 것을 고려할 수 있으나, 현재 코드도 충분히 이해 가능합니다.

🔎 가독성 향상을 위한 선택적 리팩토링 제안
+    /**
+     * Segment의 라벨 텍스트 생성
+     */
+    private String createLabelText(RootResult.DistanceStep step, ChipType type) {
+        if (type == ChipType.WALK) {
+            return null;
+        } else if (step.type() == RootResult.TransportType.BUS && step.lineInfo() != null && !step.lineInfo().isBlank()) {
+            return step.lineInfo();
+        } else if (step.type() == RootResult.TransportType.SUBWAY && step.lineInfo() != null && !step.lineInfo().isBlank()) {
+            return normalizeLine(step, type);
+        } else {
+            return TimeFormatter.formatTime(step.time());
+        }
+    }
+
     public List<TransitRoutesResponse.SegmentResponse> toSegmentResponses(RootResult route) {
         if (route == null || route.steps() == null) {
             return List.of();
         }
 
         return route.steps().stream()
                 .filter(step -> step.time() > 0)
                 .map(step -> {
                     ChipType type = mapType(step.type());
                     String bgColorHex = TransportColorResolver.extractBgColorHex(step, type);
-
-                    // 막대 위 표시 텍스트 (WALK는 null)
-                    String labelText;
-                    if (type == ChipType.WALK) {
-                        // WALK는 null
-                        labelText = null;
-                    } else if (step.type() == RootResult.TransportType.BUS && step.lineInfo() != null && !step.lineInfo().isBlank()) {
-                        // 버스 노선 정보 포함
-                        labelText = step.lineInfo();
-                    } else if (step.type() == RootResult.TransportType.SUBWAY && step.lineInfo() != null && !step.lineInfo().isBlank()) {
-                        // 지하철 노선 정보 포함
-                        labelText = normalizeLine(step, type);
-                    } else {
-                        // 기타 교통수단은 시간 표시
-                        labelText = TimeFormatter.formatTime(step.time());
-                    }
+                    String labelText = createLabelText(step, type);
 
                     return TransitRoutesResponse.SegmentResponse.builder()
                             .type(step.type().name())
                             .minutes(step.time())
                             .labelText(labelText)
                             .colorHex(bgColorHex)
                             .line(step.line())
                             .build();
                 })
                 .toList();
     }
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e1a8224 and 05e598b.

📒 Files selected for processing (3)
  • src/main/java/com/pinHouse/server/platform/housing/complex/application/dto/response/DistanceResponse.java
  • src/main/java/com/pinHouse/server/platform/housing/complex/application/dto/response/TransitRoutesResponse.java
  • src/main/java/com/pinHouse/server/platform/housing/complex/application/util/TransitResponseMapper.java
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: test
🔇 Additional comments (11)
src/main/java/com/pinHouse/server/platform/housing/complex/application/dto/response/DistanceResponse.java (1)

5-5: 시간 포맷팅 로직 중앙화 - 좋습니다!

TimeFormatter 유틸리티 클래스로 시간 포맷팅 로직을 중앙화한 것은 코드 중복을 줄이고 유지보수성을 향상시킵니다.

src/main/java/com/pinHouse/server/platform/housing/complex/application/util/TransitResponseMapper.java (8)

3-3: 유틸리티 통합 및 문서화 개선이 우수합니다.

TimeFormatter 유틸리티 도입으로 시간 포맷팅 로직이 중앙화되었으며, 상세한 JavaDoc 추가로 코드 가독성과 유지보수성이 크게 향상되었습니다.

Also applies to: 17-36


95-96: 필드명 변경이 일관되게 적용되었습니다.

labelText 사용과 조건부 null 처리가 DTO 정의와 일치합니다.

Also applies to: 106-106


221-221: 시간 포맷팅 로직 중앙화가 우수합니다.

TimeFormatter.formatTime 사용으로 시간 표시 형식이 일관되게 유지됩니다.


243-243: 메서드 가시성 변경이 의도적인지 확인하세요.

toSegmentResponses 메서드가 private에서 public으로 변경되어 public API 표면이 확장됩니다. AI 요약에 따르면 ComplexService.java에서 사용되는 것으로 보이며, 이것이 의도된 변경인지 확인이 필요합니다.


380-380: 도보 이동 단계의 부가 텍스트 null 처리가 적절합니다.

도보 이동은 노선 정보가 없으므로 secondaryTextnull로 설정하는 것이 올바른 처리입니다.


390-390: 메서드 시그니처 개선이 일관되게 적용되었습니다.

ChipType 파라미터 추가로 색상 추출 로직이 명확해졌으며, 모든 호출 지점(Lines 320, 325)이 올바르게 업데이트되었습니다.

Also applies to: 418-418


420-425: 승차/하차 단계 간 일관성이 우수합니다.

ALIGHT step에 BOARD step과 동일한 버스 노선 축약 로직을 적용하여 일관된 사용자 경험을 제공합니다.


102-102: 색상 추출 로직 중앙화가 적절합니다.

TransportColorResolver를 통한 색상 추출로 코드 재사용성이 향상되었습니다. 구현이 null 안전성을 포함하여 각 교통수단 타입(WALK, AIR, SUBWAY, BUS, TRAIN)을 올바르게 처리하고 있습니다.

src/main/java/com/pinHouse/server/platform/housing/complex/application/dto/response/TransitRoutesResponse.java (2)

84-85: 필드명 변경이 API 의미를 더 명확하게 표현합니다.

minutesText에서 labelText로의 변경은 이 필드가 단순 시간 정보뿐만 아니라 호선명, 버스번호 등 다양한 정보를 담을 수 있다는 점을 잘 반영합니다. 검증 결과 관련 매퍼와 DTO 클래스 전체에서 올바르게 업데이트되었으며, 로직도 정확합니다:

  • WALK 유형: null
  • 버스/지하철: 호선 정보
  • 기타: 소요 시간

스키마 설명도 정확하게 업데이트되어 있습니다.


116-117: 이 파일은 새로 생성된 파일이며 기존 필드의 수정이 아닙니다. secondaryText 필드는 처음부터 @JsonIgnore 어노테이션을 가지지 않았고, 이번 커밋은 버스 번호가 나오지 않는 문제를 해결하기 위한 새로운 응답 DTO 도입입니다. 따라서 기존 API에 대한 하위 호환성 문제는 없습니다.

Likely an incorrect or invalid review comment.

Comment on lines 34 to 42
public static DistanceResponse from(RootResult rootResult, List<TransitResponse> routes) {
int minutes = rootResult.totalTime();
return DistanceResponse.builder()
.totalTime(formatTime(minutes))
.totalTime(TimeFormatter.formatTimeOrNull(minutes))
.totalTimeMinutes(minutes)
.totalDistance(Math.round(rootResult.totalDistance() / 100.0) / 10.0)
.routes(routes)
.stops(null)
.build();
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

find . -type f -name "TimeFormatter.java" | head -20

Repository: PinHouse/PinHouse_BE

Length of output: 128


🏁 Script executed:

# Search for TimeFormatter class in the codebase
fd -t f "TimeFormatter" --type java

Repository: PinHouse/PinHouse_BE

Length of output: 235


🏁 Script executed:

# Also search for formatTimeOrNull method mentions
rg "formatTimeOrNull" -t java --max-count 10 -B 2 -A 2

Repository: PinHouse/PinHouse_BE

Length of output: 1363


🏁 Script executed:

cat -n ./src/main/java/com/pinHouse/server/core/util/TimeFormatter.java

Repository: PinHouse/PinHouse_BE

Length of output: 1775


🏁 Script executed:

# Also check DistanceResponse.java for field type of totalTime
rg "totalTime" src/main/java/com/pinHouse/server/platform/housing/complex/application/dto/response/DistanceResponse.java -A 1 -B 1

Repository: PinHouse/PinHouse_BE

Length of output: 657


🏁 Script executed:

# Check if there are any tests for TimeFormatter
find . -type f -name "*TimeFormatterTest*" -o -name "*TimeFormatterTests*"

Repository: PinHouse/PinHouse_BE

Length of output: 46


TimeFormatter.formatTimeOrNull의 엣지 케이스는 적절히 처리되지만 필드 타입 선언을 명확히 하세요.

TimeFormatter 구현을 확인했습니다:

  • 0분 이하: null 반환 ✓
  • 음수 값: null 반환 ✓
  • 큰 값: 정수 연산으로 안전하게 처리 ✓

다만 다음 사항을 확인이 필요합니다:

  • DistanceResponsetotalTime 필드가 String 타입으로 선언되어 있으나, formatTimeOrNull은 null을 반환할 수 있습니다.
  • 필드에 @Nullable 또는 Optional<String> 타입으로 선언하여 null을 명시적으로 표시하거나, null 처리에 대한 주석을 추가하세요.
  • 현재 설계(0분 이하일 때 null)는 의도적이지만, 다운스트림 컨슈머에서 null 가능성을 인식하도록 명확히 해야 합니다.
🤖 Prompt for AI Agents
In
src/main/java/com/pinHouse/server/platform/housing/complex/application/dto/response/DistanceResponse.java
around lines 34 to 42, the from(...) method can return null for totalTime
because TimeFormatter.formatTimeOrNull may return null; update the DTO to make
that nullability explicit by either (a) annotating the totalTime field and its
getter/setter/builder parameter with @Nullable (importing
javax.annotation.Nullable or org.jetbrains.annotations.Nullable consistently)
and adding a brief Javadoc that totalTime may be null when minutes <= 0, or (b)
change the field type to Optional<String> and adapt builders and callers to use
Optional.ofNullable(TimeFormatter.formatTimeOrNull(minutes)); choose one
approach and apply it consistently across the DTO and any consumers to ensure
downstream code is aware of and handles the nullable/optional totalTime.

Comment on lines +55 to +56
@Schema(description = "막대 위 표시 텍스트 (호선명, 버스번호, 또는 소요시간), WALK인 경우 null", example = "수도권 7호선")
String labelText,
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's examine the DistanceResponse.java file to verify the field rename
cat -n src/main/java/com/pinHouse/server/platform/housing/complex/application/dto/response/DistanceResponse.java | sed -n '50,65p'

Repository: PinHouse/PinHouse_BE

Length of output: 184


🏁 Script executed:

# Search for old field name minutesText to see if it still exists
rg "minutesText" --type java -n

Repository: PinHouse/PinHouse_BE

Length of output: 46


🏁 Script executed:

# Search for labelText usage and mapper implementations
rg "labelText" --type java -n -C3

Repository: PinHouse/PinHouse_BE

Length of output: 8199


🏁 Script executed:

# Search for WALK type handling in the codebase
rg "ChipType\.WALK|TransitType\.WALK" --type java -n -C3

Repository: PinHouse/PinHouse_BE

Length of output: 8341


🏁 Script executed:

# Find mapper implementations related to TransitResponse or DistanceResponse
rg "TransitResponse|DistanceResponse" --type java -n | head -30

Repository: PinHouse/PinHouse_BE

Length of output: 5579


프론트엔드 API 계약 변경 - Breaking Change

DistanceResponse.TransitResponselabelText 필드는 원래 minutesText에서 변경된 필드로, API를 사용하는 프론트엔드의 코드 수정이 필수입니다.

또한 TransitRoutesResponse.SegmentResponse에도 동일한 필드명 변경이 적용되었습니다.

확인 사항:

  • 매퍼 구현에서 WALK 타입의 경우 labelText가 null로 올바르게 설정됨 (TransitResponseMapper.java 라인 96, 256-258 확인됨)
  • 필드 의미가 변경됨: minutesText (시간 표시) → labelText (호선/버스번호/소요시간 등 다양한 값을 표시)
  • 프론트엔드 통합 테스트를 통한 호환성 검증 필수

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

♻️ Duplicate comments (1)
src/main/java/com/pinHouse/server/platform/housing/complex/application/service/ComplexService.java (1)

469-476: getSegments 메서드를 private으로 변경하세요.

getSegments는 ComplexUseCase 인터페이스에 정의되어 있지 않으며, 오직 ComplexService 내부(line 73)에서만 호출됩니다. 외부 호출이 없는 내부 헬퍼 메서드이므로 public이 아닌 private으로 변경해야 합니다.

🔎 제안된 수정
-    @Transactional(readOnly = true)
-    public List<TransitRoutesResponse.SegmentResponse> getSegments(String id, String pinPointId) throws UnsupportedEncodingException {
+    @Transactional(readOnly = true)
+    private List<TransitRoutesResponse.SegmentResponse> getSegments(String id, String pinPointId) throws UnsupportedEncodingException {
         return calculateTransitRoute(id, pinPointId, pathResult -> {
             RootResult rootResult = mapper.selectBest(pathResult);
             return mapper.toSegmentResponses(rootResult);
         });
     }
🧹 Nitpick comments (2)
src/main/java/com/pinHouse/server/platform/housing/complex/application/service/ComplexService.java (1)

281-297: 모집대상 필터링 로직이 비즈니스 요구사항을 잘 반영했습니다.

"기본"/"일반" 그룹을 항상 포함시키고, 그 외의 경우 rentalType 매칭을 확인하는 로직이 정확합니다. 다만, 중첩된 조건문이 다소 복잡하므로 가독성 향상을 위해 별도 메서드로 추출하는 것을 고려해볼 수 있습니다.

🔎 가독성 향상을 위한 선택적 리팩토링 제안
+    /** 모집대상(group)이 필터 조건을 만족하는지 확인 */
+    private boolean matchesRentalTypeFilter(List<String> group, List<String> rentalTypeValues) {
+        if (group == null || group.isEmpty() || rentalTypeValues == null || rentalTypeValues.isEmpty()) {
+            return true;
+        }
+        
+        // "기본" 또는 "일반"이 포함되어 있으면 무조건 포함
+        boolean hasDefaultGroup = group.stream()
+                .anyMatch(g -> "기본".equals(g) || "일반".equals(g));
+        
+        if (hasDefaultGroup) {
+            return true;
+        }
+        
+        // "기본"/"일반"이 없으면, rentalTypes 중 하나라도 group에 포함되어야 함
+        return rentalTypeValues.stream().anyMatch(group::contains);
+    }

     private boolean matchesUnitType(UnitType u,
                                     double minM2,
                                     double maxM2,
                                     long maxDeposit,
                                     long maxMonthlyPay,
                                     List<String> rentalTypeValues) {
         // ... 기존 체크 로직 ...
         
-        // 모집대상(group) 체크
-        List<String> group = u.getGroup();
-        if (group != null && !group.isEmpty() && rentalTypeValues != null && !rentalTypeValues.isEmpty()) {
-            // "기본" 또는 "일반"이 포함되어 있으면 무조건 포함
-            boolean hasDefaultGroup = group.stream()
-                    .anyMatch(g -> "기본".equals(g) || "일반".equals(g));
-
-            if (!hasDefaultGroup) {
-                // "기본"/"일반"이 없으면, rentalTypes 중 하나라도 group에 포함되어야 함
-                boolean hasMatchingRentalType = rentalTypeValues.stream()
-                        .anyMatch(group::contains);
-
-                if (!hasMatchingRentalType) {
-                    return false;
-                }
-            }
-        }
+        // 모집대상(group) 체크
+        if (!matchesRentalTypeFilter(u.getGroup(), rentalTypeValues)) {
+            return false;
+        }
         
         return true;
     }
src/main/java/com/pinHouse/server/platform/search/application/dto/FastUnitTypeResponse.java (1)

35-36: 모집 대상 그룹 필드의 null 안전성 확인 필요합니다.

group 필드가 UnitTypeResponse와 동일하게 잘 구현되어 있습니다. 다만, UnitType.getGroup()은 null을 반환할 수 있으므로 다음 중 하나를 고려해주세요:

  • 필드에 @Nullable 또는 @Schema(nullable = true) 어노테이션을 추가하여 API 명세에서 명시적으로 표시하기
  • 또는 null이 의도된 설계라면, 현재 상태 유지하되 프론트엔드 팀에 null 가능성을 명확히 전달하기
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 05e598b and 1970573.

📒 Files selected for processing (2)
  • src/main/java/com/pinHouse/server/platform/housing/complex/application/service/ComplexService.java
  • src/main/java/com/pinHouse/server/platform/search/application/dto/FastUnitTypeResponse.java
🔇 Additional comments (6)
src/main/java/com/pinHouse/server/platform/housing/complex/application/service/ComplexService.java (6)

72-76: 세그먼트 기반 거리 계산으로의 리팩토링이 적절합니다.

기존의 거리 계산 로직을 getSegments를 사용하여 세그먼트 리스트 기반으로 변경한 것은 코드 구조를 개선하고 재사용성을 높입니다.


115-117: 템플릿 메서드 패턴 적용으로 코드 중복 제거가 잘 되었습니다.

공통 로직을 calculateTransitRoute로 추출하고 결과 변환만 mapper에 위임하는 구조는 깔끔하고 유지보수하기 좋습니다.


204-204: 거리 계산 로직을 유틸리티로 중앙화한 것이 좋습니다.

DistanceCalculator 유틸리티 클래스를 사용하여 거리 계산 로직의 중복을 제거하고 일관성을 높였습니다.


222-226: 임대 유형 값 추출 로직이 안전하게 구현되었습니다.

null 체크와 함께 RentalType enum을 String 값으로 변환하는 로직이 명확하고 안전합니다.


427-467: 템플릿 메서드 패턴을 활용한 우수한 리팩토링입니다.

공통 경로 계산 로직을 calculateTransitRoute로 추출하고 결과 변환을 함수형 인터페이스로 위임하는 설계가 훌륭합니다. 코드 중복을 효과적으로 제거하고 유지보수성을 크게 향상시켰습니다. private 가시성도 적절합니다.


490-495: 템플릿 메서드를 활용한 일관된 리팩토링입니다.

getEasyDistancecalculateTransitRoute 템플릿 메서드를 사용하도록 변경하여 코드 일관성과 유지보수성이 향상되었습니다. 캐싱 로직은 그대로 유지되어 성능도 보장됩니다.

.map(FacilityType::getValue)
.toList())
.liked(liked)
.group(unitType.getGroup())
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

find . -name "FastUnitTypeResponse.java" -type f

Repository: PinHouse/PinHouse_BE

Length of output: 157


🏁 Script executed:

find . -name "UnitType.java" -type f | head -5

Repository: PinHouse/PinHouse_BE

Length of output: 152


🏁 Script executed:

git ls-files | grep -E "(UnitType|Response)" | head -20

Repository: PinHouse/PinHouse_BE

Length of output: 2070


🏁 Script executed:

cat -n ./src/main/java/com/pinHouse/server/platform/search/application/dto/FastUnitTypeResponse.java

Repository: PinHouse/PinHouse_BE

Length of output: 3447


🏁 Script executed:

cat -n ./src/main/java/com/pinHouse/server/platform/housing/complex/domain/entity/UnitType.java

Repository: PinHouse/PinHouse_BE

Length of output: 1669


🏁 Script executed:

cat -n ./src/main/java/com/pinHouse/server/platform/housing/complex/application/dto/response/UnitTypeResponse.java

Repository: PinHouse/PinHouse_BE

Length of output: 2516


🏁 Script executed:

# Search for null handling patterns with getGroup() across the codebase
rg -n "getGroup\(\)" --type java -B 2 -A 2

Repository: PinHouse/PinHouse_BE

Length of output: 2862


🏁 Script executed:

# Check if there are any @Nullable or @NotNull annotations on group field in UnitType or related classes
rg -n "@Nullable|@NotNull" ./src/main/java/com/pinHouse/server/platform/housing/complex/domain/entity/UnitType.java

Repository: PinHouse/PinHouse_BE

Length of output: 46


🏁 Script executed:

# Check how other List fields are handled in similar DTO factory methods
rg -n "\.(\w+)\(.*\.get(\w+)\(\)\)" ./src/main/java/com/pinHouse/server/platform/search/application/dto/FastUnitTypeResponse.java -A 1 -B 1

Repository: PinHouse/PinHouse_BE

Length of output: 824


🏁 Script executed:

# Check if infra field (also a List) in FastUnitTypeResponse handles null differently
grep -n "infra" ./src/main/java/com/pinHouse/server/platform/search/application/dto/FastUnitTypeResponse.java

Repository: PinHouse/PinHouse_BE

Length of output: 164


getGroup() 메서드의 null 안전성 처리 필요

다른 유사한 DTO 매퍼인 UnitTypeCompareResponse(83줄)에서는 명시적으로 null 체크를 수행하고 있습니다:

.group(unitType.getGroup() != null ? unitType.getGroup() : List.of())

일관성 유지와 NullPointerException 방지를 위해 FastUnitTypeResponse에서도 동일하게 처리해주세요.

🤖 Prompt for AI Agents
In
src/main/java/com/pinHouse/server/platform/search/application/dto/FastUnitTypeResponse.java
around line 64, the mapper currently calls unitType.getGroup() without
null-safety; change it to perform a null check and pass an empty list when null
(same pattern used in UnitTypeCompareResponse: .group(unitType.getGroup() !=
null ? unitType.getGroup() : List.of())), ensuring consistency and preventing
NullPointerException.

@doup2001 doup2001 merged commit f7e1abd into develop Dec 28, 2025
3 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.

2 participants