Skip to content

fix: 핀 조회 파라미터 복구 및 필터 파싱 재적용#107

Merged
mike7643 merged 2 commits into
mainfrom
feat/restore-pin-query-refactors
Jun 29, 2026
Merged

fix: 핀 조회 파라미터 복구 및 필터 파싱 재적용#107
mike7643 merged 2 commits into
mainfrom
feat/restore-pin-query-refactors

Conversation

@mike7643

@mike7643 mike7643 commented Jun 29, 2026

Copy link
Copy Markdown
Collaborator

✨ 작업 내용 한 줄 요약

  • 되돌린 핀 조회 관련 리팩터링을 다시 적용하고 /lockers/pins 요청은 클라이언트 계약에 맞게 검증 없이 유지

🛠️ 작업 내용

  • 내부 핀 조회 모델에서 사용자 위치 파라미터를 userLat, userLng로 분리하고 공통 필터 생성 로직 복구
  • 검색, 장소 조회, 핀 조회 요청의 필터 파싱을 웹 계층 converter로 이동하고 enum 기반 요청 모델로 재적용
  • /lockers/pins 요청 DTO의 사용자 위치 검증을 제거해 idle map 호출과 keyword pin 호출이 같은 엔드포인트를 계속 사용하도록 정리

🧠 기술적 의사결정

  • sizeTypes, indoorOutdoorTypes, lockerTypes 문자열 파싱 책임을 request DTO와 도메인 필터에서 빼고 web converter로 이동해 서비스 계층이 이미 해석된 값만 받도록 변경

Summary by CodeRabbit

  • New Features

    • 검색/핀/장소 요청에서 보관함 크기, 실내외, 시설 유형을 더 정확한 선택 항목으로 받을 수 있게 되었습니다.
    • 지도 검색 입력이 사용자 좌표 기준으로 처리되도록 개선되었습니다.
    • 요청 값이 자동 정규화되어 대소문자나 일부 형식 차이를 더 유연하게 처리합니다.
  • Bug Fixes

    • 검색 필터가 비어 있거나 잘못된 값일 때의 처리 안정성이 향상되었습니다.
    • 필터 값이 변경된 뒤에도 조회 결과가 일관되게 유지되도록 개선되었습니다.

@mike7643 mike7643 requested a review from buddle031 as a code owner June 29, 2026 10:26
@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

필터 파라미터(sizeTypes, indoorOutdoorTypes, lockerTypes)를 Set<String>에서 typed enum(LockerSizeFilterType, IndoorOutdoorFilterType, LockerFacilityFilterType)으로 전환했다. HTTP 요청 단에서 enum 변환을 처리하는 Spring MVC 컨버터 3종과 LockerSearchFilterFactory를 추가하고, LockerSearchFilter.from(...) 파싱 로직을 제거했다. LockerPinQuery의 좌표 필드명도 userLat/userLng로 변경됐다.

Changes

필터 enum 타입화 및 컨버터 도입

Layer / File(s) Summary
필터 enum 및 LockerSearchFilterFactory 정의
src/main/java/com/zimdugo/locker/application/filter/LockerSizeFilterType.java, src/.../IndoorOutdoorFilterType.java, src/.../LockerFacilityFilterType.java, src/.../LockerSearchFilterFactory.java, src/main/java/com/zimdugo/locker/domain/search/LockerSearchFilter.java
toDomain() 메서드를 가진 필터 enum 3종을 추가하고, null-safe하게 도메인 타입으로 변환하는 LockerSearchFilterFactory.create()를 구현했다. LockerSearchFilter의 문자열 파싱 from() 메서드와 관련 import가 제거됐다.
HTTP 요청 문자열 → enum 컨버터 및 MVC 등록
src/main/java/com/zimdugo/locker/entrypoint/converter/LockerFilterRequestValueNormalizer.java, src/.../LockerSizeTypeRequestConverter.java, src/.../IndoorOutdoorTypeRequestConverter.java, src/.../LockerTypeRequestConverter.java, src/main/java/com/zimdugo/locker/entrypoint/config/LockerRequestWebMvcConfig.java
JSON 배열 토큰·공백을 정규화하는 LockerFilterRequestValueNormalizer와 Spring Converter 구현체 3종을 추가하고, LockerRequestWebMvcConfig에서 FormatterRegistry에 등록했다.
DTO·Command·Query 필터 필드 타입 변경
src/main/java/com/zimdugo/locker/entrypoint/dto/request/search/LockerSearchRequest.java, src/.../place/PlaceLockerRequest.java, src/.../pin/LockerPinRequest.java, src/main/java/com/zimdugo/locker/application/search/LockerSearchCommand.java, src/.../place/PlaceLockerQueryCommand.java, src/.../pin/LockerPinQuery.java
요청 DTO 3종과 Command/Query 3종의 필터 필드를 Set<String>에서 typed enum Set으로 변경했다. LockerPinQuery의 좌표 필드명이 latitude/longitude에서 userLat/userLng로 변경됐다.
서비스 계층 필터 생성 LockerSearchFilterFactory로 교체
src/main/java/com/zimdugo/locker/application/pin/LockerPinQueryService.java, src/.../place/PlaceLockerQueryService.java, src/.../search/LockerSearchResultQueryService.java
서비스 3곳에서 LockerSearchFilter.from(...)LockerSearchFilterFactory.create(...)로 교체했다. LockerPinQueryServiceuserLat/userLng 필드 참조로도 변경됐다.
테스트 업데이트 및 신규 컨버터 테스트 추가
src/test/java/com/zimdugo/locker/domain/search/LockerSearchFilterTest.java, src/test/.../pin/LockerPinQueryServiceTest.java, src/test/.../place/PlaceLockerQueryServiceTest.java, src/test/.../search/LockerSearchResultQueryServiceTest.java, src/test/.../converter/LockerFilterRequestConverterTest.java, src/test/.../search/LockerSearchRequestTest.java
기존 테스트에서 String 기반 필터 인자를 enum으로 교체하고, LockerSearchFilterTest에 null 정규화·불변성 검증을 추가했다. 컨버터 동작을 검증하는 신규 테스트 2종이 추가됐다.

추정 코드 리뷰 노력

🎯 3 (Moderate) | ⏱️ ~20 minutes

관련 가능성 있는 PR

  • JECT-Study/Zimdugo-4th-Server#50: 키워드 검색에 LockerSearchFilter를 도입하고 후보/PLACE 조회 흐름에 전달하도록 변경한 PR로, 본 PR의 LockerSearchFilter.from(...) 제거 및 LockerSearchFilterFactory.create(...)로의 전환과 직접적으로 연관된다.
  • JECT-Study/Zimdugo-4th-Server#52: PlaceLockerQueryService 및 장소 락커 엔드포인트를 도입한 PR로, 본 PR의 PlaceLockerQueryCommand/DTO 필터 필드 타입 변경과 연관된다.
  • JECT-Study/Zimdugo-4th-Server#67: LockerSearchFilter.from(...)에 실내외/보관함 타입 Set을 전달하도록 수정한 PR로, 본 PR에서 해당 메서드가 제거되는 동일한 필터 생성 경로와 맞물린다.

제안 리뷰어

  • buddle031

🐰 문자열 "SMALL" 시절은 이제 안녕~
enum이 찾아와 타입을 지켜주네.
컨버터가 열심히 JSON 괄호를 지우고,
Factory가 null도 빈 Set으로 바꿔주죠.
쑥쑥 자라는 코드, 토끼는 기뻐 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed 제목이 핀 조회 파라미터 복구와 필터 파싱 재적용이라는 주요 변경점을 간결하게 잘 요약합니다.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed 템플릿의 필수 섹션(한 줄 요약, 작업 내용, 기술적 의사결정)을 모두 포함하고 있어 설명이 충분합니다.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/restore-pin-query-refactors

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.

@mike7643 mike7643 merged commit bf69662 into main Jun 29, 2026
3 of 4 checks passed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 (3)
src/test/java/com/zimdugo/locker/application/pin/LockerPinQueryServiceTest.java (1)

201-207: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

never() 검증이 너무 구체적합니다.

여기는 SUBWAY_INDOOR_SMALL_FILTER로 호출된 경우만 막습니다. 키워드 핀 경로가 잘못되어 findWithinBounds(...)를 다른 필터로 호출해도 테스트가 통과할 수 있으니, 아예 reader 무호출을 검증하는 편이 안전합니다.

변경 예시
-        verify(nearbyLockerPlaceReader, never()).findWithinBounds(
-            37.54,
-            126.92,
-            37.56,
-            126.94,
-            SUBWAY_INDOOR_SMALL_FILTER
-        );
+        then(nearbyLockerPlaceReader).shouldHaveNoInteractions();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/test/java/com/zimdugo/locker/application/pin/LockerPinQueryServiceTest.java`
around lines 201 - 207, The current `never()` verification on
`nearbyLockerPlaceReader.findWithinBounds(...)` is too specific because it only
blocks calls using `SUBWAY_INDOOR_SMALL_FILTER`. Update
`LockerPinQueryServiceTest` to assert that `nearbyLockerPlaceReader` is not
called at all in this keyword-pin path, using the reader mock itself rather than
matching a particular filter. Keep the verification aligned with the relevant
service flow in `LockerPinQueryServiceTest` so accidental calls with other
filters are also caught.
src/main/java/com/zimdugo/locker/application/filter/LockerFacilityFilterType.java (1)

15-17: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

여기도 문자열 기반 enum 브리징은 피하는 편이 안전합니다.

지금 구현은 LockerFacilityFilterTypeLockerType의 상수명이 완전히 같다는 가정에 묶여 있습니다. 한쪽 enum만 수정돼도 배포 전에는 안 보이고, 실제 요청 처리 중에만 실패하니 명시 매핑으로 바꿔 두는 편이 낫습니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/com/zimdugo/locker/application/filter/LockerFacilityFilterType.java`
around lines 15 - 17, The LockerFacilityFilterType.toDomain() bridge currently
depends on matching enum constant names via valueOf(name()), which is fragile if
LockerType or LockerFacilityFilterType changes. Replace this string-based
conversion with an explicit mapping inside LockerFacilityFilterType.toDomain()
(or equivalent dedicated mapper) so each enum constant maps intentionally to the
correct LockerType value without relying on name equality.
src/main/java/com/zimdugo/locker/application/filter/LockerSizeFilterType.java (1)

10-12: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

valueOf(name()) 대신 명시 매핑으로 고정해 주세요.

LockerSearchFilterFactory.create()가 이 메서드를 바로 호출하므로, application/domain enum 이름이 한쪽만 바뀌어도 컴파일은 통과하고 여기서 런타임 예외가 납니다. switch로 매핑하면 enum 변경 누락을 컴파일 단계에서 잡을 수 있습니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/com/zimdugo/locker/application/filter/LockerSizeFilterType.java`
around lines 10 - 12, `LockerSizeFilterType.toDomain()` currently relies on
`LockerSizeType.valueOf(name())`, which makes the mapping depend on matching
enum names at runtime. Replace this with an explicit `switch`-based mapping
inside `toDomain()` so each `LockerSizeFilterType` value maps directly to the
corresponding `LockerSizeType`, and review `LockerSearchFilterFactory.create()`
callers to ensure they still use this conversion path.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@src/main/java/com/zimdugo/locker/application/filter/LockerSearchFilterFactory.java`:
- Around line 18-32: The filter conversion in LockerSearchFilterFactory is
mapping request enums directly to domain values without removing null entries
first, which can cause a failure when LockerSearchRequest receives empty filter
tokens from the request converters. Update the set-building logic in the factory
to filter out null elements before calling LockerSizeFilterType.toDomain,
IndoorOutdoorFilterType.toDomain, and LockerFacilityFilterType.toDomain, so
empty inputs are treated as empty sets rather than causing an error.

In
`@src/test/java/com/zimdugo/locker/entrypoint/converter/LockerFilterRequestConverterTest.java`:
- Around line 37-42: The invalid locker type test only asserts
BusinessException, so it can pass even if the converter throws the wrong error
code. Update invalidLockerTypeThrowsException in
LockerFilterRequestConverterTest to also verify the BusinessException errorCode
is INVALID_PARAMETER_FORMAT, using the same
lockerTypeRequestConverter.convert("unknown") path so the API contract is pinned
down.

---

Nitpick comments:
In
`@src/main/java/com/zimdugo/locker/application/filter/LockerFacilityFilterType.java`:
- Around line 15-17: The LockerFacilityFilterType.toDomain() bridge currently
depends on matching enum constant names via valueOf(name()), which is fragile if
LockerType or LockerFacilityFilterType changes. Replace this string-based
conversion with an explicit mapping inside LockerFacilityFilterType.toDomain()
(or equivalent dedicated mapper) so each enum constant maps intentionally to the
correct LockerType value without relying on name equality.

In
`@src/main/java/com/zimdugo/locker/application/filter/LockerSizeFilterType.java`:
- Around line 10-12: `LockerSizeFilterType.toDomain()` currently relies on
`LockerSizeType.valueOf(name())`, which makes the mapping depend on matching
enum names at runtime. Replace this with an explicit `switch`-based mapping
inside `toDomain()` so each `LockerSizeFilterType` value maps directly to the
corresponding `LockerSizeType`, and review `LockerSearchFilterFactory.create()`
callers to ensure they still use this conversion path.

In
`@src/test/java/com/zimdugo/locker/application/pin/LockerPinQueryServiceTest.java`:
- Around line 201-207: The current `never()` verification on
`nearbyLockerPlaceReader.findWithinBounds(...)` is too specific because it only
blocks calls using `SUBWAY_INDOOR_SMALL_FILTER`. Update
`LockerPinQueryServiceTest` to assert that `nearbyLockerPlaceReader` is not
called at all in this keyword-pin path, using the reader mock itself rather than
matching a particular filter. Keep the verification aligned with the relevant
service flow in `LockerPinQueryServiceTest` so accidental calls with other
filters are also caught.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 9f91c175-aef5-416b-82c2-31cd9304855a

📥 Commits

Reviewing files that changed from the base of the PR and between ac7b9c1 and 07397c2.

📒 Files selected for processing (25)
  • src/main/java/com/zimdugo/locker/application/filter/IndoorOutdoorFilterType.java
  • src/main/java/com/zimdugo/locker/application/filter/LockerFacilityFilterType.java
  • src/main/java/com/zimdugo/locker/application/filter/LockerSearchFilterFactory.java
  • src/main/java/com/zimdugo/locker/application/filter/LockerSizeFilterType.java
  • src/main/java/com/zimdugo/locker/application/pin/LockerPinQuery.java
  • src/main/java/com/zimdugo/locker/application/pin/LockerPinQueryService.java
  • src/main/java/com/zimdugo/locker/application/place/PlaceLockerQueryCommand.java
  • src/main/java/com/zimdugo/locker/application/place/PlaceLockerQueryService.java
  • src/main/java/com/zimdugo/locker/application/search/LockerSearchCommand.java
  • src/main/java/com/zimdugo/locker/application/search/LockerSearchResultQueryService.java
  • src/main/java/com/zimdugo/locker/domain/search/LockerSearchFilter.java
  • src/main/java/com/zimdugo/locker/entrypoint/config/LockerRequestWebMvcConfig.java
  • src/main/java/com/zimdugo/locker/entrypoint/converter/IndoorOutdoorTypeRequestConverter.java
  • src/main/java/com/zimdugo/locker/entrypoint/converter/LockerFilterRequestValueNormalizer.java
  • src/main/java/com/zimdugo/locker/entrypoint/converter/LockerSizeTypeRequestConverter.java
  • src/main/java/com/zimdugo/locker/entrypoint/converter/LockerTypeRequestConverter.java
  • src/main/java/com/zimdugo/locker/entrypoint/dto/request/pin/LockerPinRequest.java
  • src/main/java/com/zimdugo/locker/entrypoint/dto/request/place/PlaceLockerRequest.java
  • src/main/java/com/zimdugo/locker/entrypoint/dto/request/search/LockerSearchRequest.java
  • src/test/java/com/zimdugo/locker/application/pin/LockerPinQueryServiceTest.java
  • src/test/java/com/zimdugo/locker/application/place/PlaceLockerQueryServiceTest.java
  • src/test/java/com/zimdugo/locker/application/search/LockerSearchResultQueryServiceTest.java
  • src/test/java/com/zimdugo/locker/domain/search/LockerSearchFilterTest.java
  • src/test/java/com/zimdugo/locker/entrypoint/converter/LockerFilterRequestConverterTest.java
  • src/test/java/com/zimdugo/locker/entrypoint/dto/request/search/LockerSearchRequestTest.java
💤 Files with no reviewable changes (1)
  • src/main/java/com/zimdugo/locker/domain/search/LockerSearchFilter.java

Comment on lines +37 to +42
@Test
@DisplayName("보관함 유형 컨버터는 유효하지 않은 입력을 예외로 처리한다")
void invalidLockerTypeThrowsException() {
assertThatThrownBy(() -> lockerTypeRequestConverter.convert("unknown"))
.isInstanceOf(BusinessException.class);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

오류 코드까지 검증해 주세요.

지금은 BusinessException 타입만 확인해서, 컨버터가 잘못된 errorCode를 던져도 테스트가 통과합니다. 이 경로는 API 계약이라 INVALID_PARAMETER_FORMAT까지 고정해 두는 편이 좋습니다.

변경 예시
+import com.zimdugo.core.exception.ErrorCode;
+
     `@Test`
     `@DisplayName`("보관함 유형 컨버터는 유효하지 않은 입력을 예외로 처리한다")
     void invalidLockerTypeThrowsException() {
         assertThatThrownBy(() -> lockerTypeRequestConverter.convert("unknown"))
-            .isInstanceOf(BusinessException.class);
+            .isInstanceOf(BusinessException.class)
+            .extracting("errorCode")
+            .isEqualTo(ErrorCode.INVALID_PARAMETER_FORMAT);
     }
📝 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
@Test
@DisplayName("보관함 유형 컨버터는 유효하지 않은 입력을 예외로 처리한다")
void invalidLockerTypeThrowsException() {
assertThatThrownBy(() -> lockerTypeRequestConverter.convert("unknown"))
.isInstanceOf(BusinessException.class);
}
import com.zimdugo.core.exception.ErrorCode;
`@Test`
`@DisplayName`("보관함 유형 컨버터는 유효하지 않은 입력을 예외로 처리한다")
void invalidLockerTypeThrowsException() {
assertThatThrownBy(() -> lockerTypeRequestConverter.convert("unknown"))
.isInstanceOf(BusinessException.class)
.extracting("errorCode")
.isEqualTo(ErrorCode.INVALID_PARAMETER_FORMAT);
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/test/java/com/zimdugo/locker/entrypoint/converter/LockerFilterRequestConverterTest.java`
around lines 37 - 42, The invalid locker type test only asserts
BusinessException, so it can pass even if the converter throws the wrong error
code. Update invalidLockerTypeThrowsException in
LockerFilterRequestConverterTest to also verify the BusinessException errorCode
is INVALID_PARAMETER_FORMAT, using the same
lockerTypeRequestConverter.convert("unknown") path so the API contract is pinned
down.

@mike7643 mike7643 self-assigned this Jun 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant