Skip to content

Conversation

@leeseokchan00
Copy link
Contributor

@leeseokchan00 leeseokchan00 commented Nov 17, 2025

๐Ÿ“Œ PR ์š”์•ฝ

๐ŸŒฑ ์ž‘์—…ํ•œ ๋‚ด์šฉ

  • ์›๊ธฐ์˜ฅ

๐ŸŒฑ PR ํฌ์ธํŠธ

๐Ÿ“ธ ์Šคํฌ๋ฆฐ์ƒท

์Šคํฌ๋ฆฐ์ƒท
ํŒŒ์ผ์ฒจ๋ถ€๋ฐ”๋žŒ

๐Ÿ“ฎ ๊ด€๋ จ ์ด์Šˆ

Summary by CodeRabbit

๋ฆด๋ฆฌ์Šค ๋…ธํŠธ

  • ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ

    • ์ƒˆ๋กœ์šด ์žฅ์†Œ ๋“ฑ๋ก ๊ธฐ๋Šฅ ์ถ”๊ฐ€๋กœ ์‚ฌ์šฉ์ž๊ฐ€ ์ง์ ‘ ์žฅ์†Œ๋ฅผ ๋“ฑ๋กํ•˜๊ณ  ์‚ฌ์ง„ ์—…๋กœ๋“œ ๊ฐ€๋Šฅ
    • ์ฃผ์†Œ ๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ ๊ฐ•ํ™”๋กœ ๋” ์ •ํ™•ํ•œ ์žฅ์†Œ ์ฐพ๊ธฐ ๊ฐ€๋Šฅ
    • ๋™๋„ค ์„ ํƒ ๊ธฐ๋Šฅ ๊ฐœ์„ 
  • ๊ฐœ์„ ์‚ฌํ•ญ

    • ๊ฒ€์ƒ‰ ํ™”๋ฉด์„ ์ƒˆ๋กœ์šด ์ „์ฒด ํ™”๋ฉด ์ธํ„ฐํŽ˜์ด์Šค๋กœ ๊ฐœ์„ 
    • ์ด๋ฏธ์ง€ ์„ ํƒ ๋ฐ ์—…๋กœ๋“œ ํ๋ฆ„ ์ตœ์ ํ™”
    • UI ์ปดํฌ๋„ŒํŠธ ๋ฐ ๋„ค๋น„๊ฒŒ์ด์…˜ ๊ฐœ์„ 

โ€ฆto refactor/#144-first-qa

# Conflicts:
#	feature/mypage/src/main/java/com/teamsolply/solply/mypage/MypageContract.kt
#	feature/mypage/src/main/java/com/teamsolply/solply/mypage/MypageScreen.kt
#	feature/mypage/src/main/java/com/teamsolply/solply/mypage/component/SolplyPersonaDropDown.kt
#	feature/mypage/src/main/java/com/teamsolply/solply/mypage/profile/ProfileEditScreen.kt
#	feature/mypage/src/main/java/com/teamsolply/solply/mypage/profile/navigation/ProfileNavigation.kt
โ€ฆto refactor/#144-first-qa

# Conflicts:
#	feature/main/src/main/java/com/teamsolply/solply/main/MainNavigator.kt
@coderabbitai
Copy link

coderabbitai bot commented Nov 17, 2025

๐Ÿš€ Walkthrough

์ด PR์€ Naver ๋กœ์ปฌ ๊ฒ€์ƒ‰ API ํ†ตํ•ฉ, ์žฅ์†Œ ๋“ฑ๋ก ๊ธฐ๋Šฅ ๊ตฌํ˜„, ๊ทธ๋ฆฌ๊ณ  ๊ฒ€์ƒ‰/์ฆ๊ฒจ์ฐพ๊ธฐ ๋™๋„ค ๋„ค๋น„๊ฒŒ์ด์…˜ ํ”Œ๋กœ์šฐ ๋Œ€๊ทœ๋ชจ ๋ฆฌํŒฉํ† ๋ง์„ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค. ๊ธฐ์กด์˜ ๋‹ค์ด์–ผ๋กœ๊ทธ ๊ธฐ๋ฐ˜ ๊ฒ€์ƒ‰์„ ์ „์ฒด ํ™”๋ฉด ๊ฒ€์ƒ‰์œผ๋กœ ๋ณ€๊ฒฝํ•˜๊ณ  ํ”„๋กœํ•„ ์‚ฌ์ง„ ์—…๋กœ๋“œ UI๋ฅผ ํ†ตํ•ฉํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ“‹ Changes

์‘์ง‘๋„ / ํŒŒ์ผ ๋ณ€๊ฒฝ ์š”์•ฝ
Naver API ํ†ตํ•ฉ
core/network/src/main/java/com/teamsolply/solply/network/di/NaverApiModule.kt, core/network/src/main/java/com/teamsolply/solply/network/model/NaverLocalSearchResponseDto.kt, core/network/src/main/java/com/teamsolply/solply/network/service/NaverLocalSearchService.kt
Naver ๋กœ์ปฌ ๊ฒ€์ƒ‰ API ๋ชจ๋“ˆ, ์„œ๋น„์Šค, ์‘๋‹ต DTO ์‹ ๊ทœ ์ถ”๊ฐ€. Dagger Hilt ๋ฐ”์ธ๋”ฉ ๋ฐ Retrofit ํ†ตํ•ฉ ์™„๋ฃŒ.
๋นŒ๋“œ ์„ค์ • ๋ฐ ๊ณตํ†ต ๋ ˆ์ด์–ด
build-logic/convention/src/main/java/com/teamsolply/solply/convention/BuildConfig.kt, core/buildconfig/src/main/java/com/teamsolply/solply/buildconfig/impl/BuildConfigFieldsProviderImpl.kt, core/common/src/main/java/com/teamsolply/solply/common/buildconfig/BuildConfigFields.kt
Naver Developers ํด๋ผ์ด์–ธํŠธ ID/Secret ๋นŒ๋“œ ์„ค์ • ์ถ”๊ฐ€.
๋””์ž์ธ ์‹œ์Šคํ…œ - ์ด๋ฏธ์ง€ ๊ด€๋ จ
core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/card/RegisterPlaceImage.kt, core/designsystem/src/main/res/drawable/ic_arrow_down_lg.xml
์ƒˆ๋กœ์šด RegisterPlaceImage ์ปดํฌ๋„ŒํŠธ ๋ฐ ContentResolver ํ™•์žฅํ•จ์ˆ˜ ์ถ”๊ฐ€. ์•„์ด์ฝ˜ ๋ฆฌ์†Œ์Šค ์—…๋ฐ์ดํŠธ.
๋””์ž์ธ ์‹œ์Šคํ…œ - ํผ ์ปดํฌ๋„ŒํŠธ
core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/dropdown/SolplyBasicDropDown.kt, core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/header/SolplyHomeHeader.kt, core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/textfield/SolplyTextField.kt
๋“œ๋กญ๋‹ค์šด ๋ ˆ์ด๋ธ”์„ Composable ํ•จ์ˆ˜๋กœ ๋ณ€๊ฒฝ, ํ—ค๋” ํŒŒ๋ผ๋ฏธํ„ฐ ํƒ€์ž… ์ˆ˜์ •, ํ…์ŠคํŠธ ํ•„๋“œ์— innerPadding ๋ฐ ํฌ์ปค์Šค ์ฝœ๋ฐฑ ์ถ”๊ฐ€.
๋„๋ฉ”์ธ ๋ฐ DTO ๋ ˆ์ด์–ด - ์žฅ์†Œ ์ •๋ณด
core/model/src/main/java/com/teamsolply/solply/model/PlaceType.kt, data/place/src/main/java/com/teamsolply/solply/place/dto/response/GetPlacesResponseDto.kt, data/place/src/main/java/com/teamsolply/solply/place/dto/response/GetRecommendPlaceDto.kt, data/place/src/main/java/com/teamsolply/solply/place/mapper/PlaceEntityMapper.kt, data/place/src/main/java/com/teamsolply/solply/place/repository/PlaceRepositoryImpl.kt
PlaceType์— toId() ํ™•์žฅํ•จ์ˆ˜ ์ถ”๊ฐ€. primaryTag๋ฅผ mainTag๋กœ ํ•„๋“œ๋ช… ๋ณ€๊ฒฝ ๋ฐ ๋งคํ•‘ ๋กœ์ง ์—…๋ฐ์ดํŠธ.
๋„๋ฉ”์ธ ๋ฐ DTO ๋ ˆ์ด์–ด - ์žฅ์†Œ ๋“ฑ๋ก
data/search/src/main/java/com/teamsolply/solply/search/dto/request/RegisterPlaceRequestDto.kt, data/search/src/main/java/com/teamsolply/solply/search/dto/response/RegisterPlaceResponseDto.kt, domain/search/src/main/java/com/teamsolply/solply/search/model/RegisterPlaceEntity.kt
์žฅ์†Œ ๋“ฑ๋ก ์š”์ฒญ/์‘๋‹ต DTO ๋ฐ ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ ์‹ ๊ทœ ์ถ”๊ฐ€.
๋„๋ฉ”์ธ ๋ฐ DTO ๋ ˆ์ด์–ด - ๊ฒ€์ƒ‰
data/search/src/main/java/com/teamsolply/solply/search/dto/response/SearchResponseDto.kt, domain/search/src/main/java/com/teamsolply/solply/search/model/NaverLocalSearchResponseEntity.kt, domain/search/src/main/java/com/teamsolply/solply/search/model/SearchResultEntity.kt
SearchResultEntity์— townId ํ•„๋“œ ์ถ”๊ฐ€. Naver ๊ฒ€์ƒ‰ ์‘๋‹ต ์—”ํ‹ฐํ‹ฐ ์‹ ๊ทœ ์ถ”๊ฐ€. ํŒจํ‚ค์ง€ ์ด๋™.
์ €์žฅ์†Œ ๋ ˆ์ด์–ด
data/search/src/main/java/com/teamsolply/solply/search/repository/SearchRepositoryImpl.kt, data/search/src/main/java/com/teamsolply/solply/search/source/SearchRemoteDataSource.kt, domain/search/src/main/java/com/teamsolply/solply/search/repository/SearchRepository.kt
searchAddress() ๋ฐ requestsPlaces() ๋ฉ”์„œ๋“œ ์ถ”๊ฐ€. NaverLocalSearchService ์˜์กด์„ฑ ์ฃผ์ž….
๋„คํŠธ์›Œํฌ ์›๊ฒฉ ๋ ˆ์ด์–ด
remote/search/src/main/java/com/teamsolply/solply/search/datasource/SearchRemoteDataSourceImpl.kt, remote/search/src/main/java/com/teamsolply/solply/search/service/SearchService.kt, remote/place/src/main/java/com/teamsolply/solply/place/datasource/PlaceRemoteDataSourceImpl.kt, remote/place/src/main/java/com/teamsolply/solply/place/service/PlaceService.kt
requestsPlaces() POST ์—”๋“œํฌ์ธํŠธ ์ถ”๊ฐ€. ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ๋ช… ๋ณ€๊ฒฝ (subTagAIdList โ†’ subTag1Ids).
๊ธฐ๋Šฅ - ๊ฒ€์ƒ‰
feature/search/src/main/java/com/teamsolply/solply/search/SearchContract.kt, feature/search/src/main/java/com/teamsolply/solply/search/SearchScreen.kt, feature/search/src/main/java/com/teamsolply/solply/search/SearchViewModel.kt, feature/search/src/main/java/com/teamsolply/solply/search/navigation/SearchNavigation.kt, feature/search/src/main/java/com/teamsolply/solply/search/SearchDialog.kt
์ „์ฒด ํ™”๋ฉด ๊ฒ€์ƒ‰ ํ™”๋ฉด ์‹ ๊ทœ ์ถ”๊ฐ€. SearchDialog ์ œ๊ฑฐ. ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ๋ Œ๋”๋ง ๋ฐ ๋„ค๋น„๊ฒŒ์ด์…˜ ๋กœ์ง ์ถ”๊ฐ€.
๊ธฐ๋Šฅ - ์žฅ์†Œ ๋“ฑ๋ก
feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceContract.kt, feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceScreen.kt, feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceViewModel.kt, feature/search/src/main/java/com/teamsolply/solply/registerplace/component/...
์žฅ์†Œ ๋“ฑ๋ก ํ™”๋ฉด, ViewModel, ์ปดํฌ๋„ŒํŠธ (PlaceTypeDropDown, RegisterPlaceItem) ์‹ ๊ทœ ์ถ”๊ฐ€. S3 ํŒŒ์ผ ์—…๋กœ๋“œ ํ†ตํ•ฉ.
๊ธฐ๋Šฅ - ์ฝ”์Šค ๋ฆฌํŒฉํ† ๋ง
feature/course/src/main/java/com/teamsolply/solply/course/CourseContract.kt, feature/course/src/main/java/com/teamsolply/solply/course/CourseScreen.kt, feature/course/src/main/java/com/teamsolply/solply/course/CourseViewModel.kt, feature/course/src/main/java/com/teamsolply/solply/course/component/FavoriteTownTopBar.kt
๊ฒ€์ƒ‰ ๋‹ค์ด์–ผ๋กœ๊ทธ ์ƒํƒœ ์ œ๊ฑฐ. NavigateToFavoriteTown, NavigateToSearch ์˜๋„ ์ถ”๊ฐ€.
๊ธฐ๋Šฅ - ์ฆ๊ฒจ์ฐพ๊ธฐ ๋™๋„ค
feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/FavoriteTownContract.kt, feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/FavoriteTownRoute.kt, feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/FavoriteViewModel.kt, feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/favoriteTownNavigation/FavoriteTownNavigation.kt
selectedTownId ์ „๋‹ฌ ๋ฉ”์ปค๋‹ˆ์ฆ˜ ์ถ”๊ฐ€. FavoriteTownSideEffect๋กœ ํƒ€์ž… ๋ณ€๊ฒฝ. DismissWithResult ๋ถ€๊ฐ€ ๋ฐ์ดํ„ฐ ์ถ”๊ฐ€.
๊ธฐ๋Šฅ - ์ฝ”์Šค ๋„ค๋น„๊ฒŒ์ด์…˜
feature/course/src/main/java/com/teamsolply/solply/course/navigation/CourseNavigation.kt
courseNavGraph ์‹œ๊ทธ๋‹ˆ์ฒ˜ ์—…๋ฐ์ดํŠธ. navigateToFavoriteTown, navigateToSearch ์ฝœ๋ฐฑ ์ถ”๊ฐ€.
๊ธฐ๋Šฅ - ์žฅ์†Œ ๋ฆฌํŒฉํ† ๋ง
feature/place/src/main/java/com/teamsolply/solply/place/PlaceContract.kt, feature/place/src/main/java/com/teamsolply/solply/place/PlaceScreen.kt, feature/place/src/main/java/com/teamsolply/solply/place/PlaceViewModel.kt, feature/place/src/main/java/com/teamsolply/solply/place/component/button/PlaceChipButton.kt, feature/place/src/main/java/com/teamsolply/solply/place/navigation/PlaceNavigation.kt
๊ฒ€์ƒ‰ ๋‹ค์ด์–ผ๋กœ๊ทธ ์ƒํƒœ ์ œ๊ฑฐ. NavigateToFavoriteTown, NavigateToSearch ์˜๋„ ์ถ”๊ฐ€. ์•„์ด์ฝ˜ ๋ณ€๊ฒฝ.
๊ธฐ๋Šฅ - ๋ฉ”์ธ ๋ฐ ์ง€๋„
feature/main/build.gradle.kts, feature/main/src/main/AndroidManifest.xml, feature/main/src/main/java/com/teamsolply/solply/main/MainNavigator.kt, feature/main/src/main/java/com/teamsolply/solply/main/MainScreen.kt, feature/maps/src/main/java/com/teamsolply/solply/maps/MapsViewModel.kt, feature/maps/src/main/java/com/teamsolply/solply/maps/component/...
๊ฒ€์ƒ‰ ๋ฐ ์žฅ์†Œ ๋“ฑ๋ก ์˜์กด์„ฑ ์ถ”๊ฐ€. ๋„ค๋น„๊ฒŒ์ด์…˜ ํ๋ฆ„ ํ†ตํ•ฉ. RegisterPlaceImage ํ†ตํ•ฉ. ์ƒ์„ธ ๊ธฐ๋ก ์ถ”๊ฐ€.
์œ ํ‹ธ ๋ฐ ๊ธฐํƒ€
core/ui/src/main/java/com/teamsolply/solply/ui/util/PresignedUrlUploader.kt, data/maps/src/main/java/com/teamsolply/solply/maps/dto/response/PresignedUrlsResponseDto.kt, feature/search/build.gradle.kts, feature/place/build.gradle.kts
ํŒจํ‚ค์ง€ ์ด๋™. SerialName ์ˆ˜์ • (presignedUrlInfos โ†’ presignedGetUrlInfos). Lottie ์˜์กด์„ฑ ์ถ”๊ฐ€.

๐Ÿ”„ Sequence Diagram

sequenceDiagram
    actor User
    participant SearchScreen as SearchScreen
    participant SearchViewModel as SearchViewModel
    participant SearchRepository as SearchRepository
    participant NaverAPI as NaverLocalSearchService
    participant MainScreen as MainScreen

    User->>SearchScreen: ๊ฒ€์ƒ‰ ํ…์ŠคํŠธ ์ž…๋ ฅ
    SearchScreen->>SearchViewModel: InputSearchQuery(text)
    SearchViewModel->>SearchRepository: searchAddress(query)
    SearchRepository->>NaverAPI: searchLocal(query)
    NaverAPI-->>SearchRepository: NaverLocalSearchResponseDto[]
    SearchRepository-->>SearchViewModel: Result<NaverLocalSearchResponseEntity[]>
    SearchViewModel->>SearchScreen: uiState ์—…๋ฐ์ดํŠธ
    SearchScreen->>User: ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ํ‘œ์‹œ

    User->>SearchScreen: ์žฅ์†Œ ์„ ํƒ
    SearchScreen->>SearchViewModel: PlaceDetailClick(placeId, townId)
    SearchViewModel-->>SearchScreen: NavigateToPlaceDetail SideEffect
    SearchScreen->>MainScreen: navigateToPlaceDetail(...)
    MainScreen->>User: ์ง€๋„ ์ƒ์„ธ ํ™”๋ฉด ํ‘œ์‹œ
Loading
sequenceDiagram
    actor User
    participant RegisterScreen as RegisterPlaceScreen
    participant RegisterViewModel as RegisterPlaceViewModel
    participant SearchRepository as SearchRepository
    participant MapsRepository as MapsRepository
    participant S3 as S3 (PresignedURL)
    participant Backend as Backend API

    User->>RegisterScreen: ์žฅ์†Œ๋ช… ์ž…๋ ฅ
    RegisterScreen->>RegisterViewModel: InputPlaceNameText(text)
    RegisterViewModel->>SearchRepository: searchAddress(query)
    SearchRepository-->>RegisterViewModel: ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ
    RegisterViewModel->>RegisterScreen: uiState ์—…๋ฐ์ดํŠธ
    
    User->>RegisterScreen: ์ด๋ฏธ์ง€ ์„ ํƒ + ์™„๋ฃŒ
    RegisterScreen->>RegisterViewModel: SelectedReportUris(uris)
    RegisterViewModel->>RegisterViewModel: ํ•„์ˆ˜ ํ•„๋“œ ๊ฒ€์ฆ
    
    User->>RegisterScreen: ๋“ฑ๋ก ๋ฒ„ํŠผ
    RegisterScreen->>RegisterViewModel: ClickRegisterPlace
    RegisterViewModel->>MapsRepository: requestPresignedUrls(count)
    MapsRepository-->>RegisterViewModel: PresignedUrl[]
    
    loop ๊ฐ ํŒŒ์ผ๋งˆ๋‹ค
        RegisterViewModel->>S3: uploadToPresignedUrl(file)
        S3-->>RegisterViewModel: 200 OK
    end
    
    RegisterViewModel->>SearchRepository: requestsPlaces(RegisterPlaceEntity)
    SearchRepository->>Backend: POST /register-place
    Backend-->>SearchRepository: RegisterPlaceResponseDto
    SearchRepository-->>RegisterViewModel: Result<RegisterPlaceResponseEntity>
    RegisterViewModel->>RegisterScreen: ์„ฑ๊ณต + Lottie ํ‘œ์‹œ
    RegisterViewModel-->>RegisterScreen: NavigateToBack SideEffect
Loading

๐ŸŽฏ ์ฝ”๋“œ ๋ฆฌ๋ทฐ ๋‚œ์ด๋„ ์ถ”์ •

๐ŸŽฏ 4 (Complex) | โฑ๏ธ ~60 minutes

ํŠน๋ณ„ํžˆ ์ฃผ์˜๊ฐ€ ํ•„์š”ํ•œ ์˜์—ญ:

  • ๋„ค๋น„๊ฒŒ์ด์…˜ ํ”Œ๋กœ์šฐ ๋ฆฌํŒฉํ† ๋ง: Course, Place, Search, FavoriteTown ๊ฐ„์˜ ๋„ค๋น„๊ฒŒ์ด์…˜ ๋ชจ๋ธ์ด ๋Œ€ํญ ๋ณ€๊ฒฝ๋จ. ํŠนํžˆ FavoriteTownNavigation, CourseNavigation, PlaceNavigation, MainNavigator์˜ ์‹œ๊ทธ๋‹ˆ์ฒ˜ ๋ฐ ์ฝœ๋ฐฑ ํ๋ฆ„์„ ๊ฒ€์ฆ ํ•„์š”
  • RegisterPlaceViewModel์˜ ๋ณ‘๋ ฌ ํŒŒ์ผ ์—…๋กœ๋“œ: S3 presigned URL ๊ธฐ๋ฐ˜ ๋‹ค์ค‘ ํŒŒ์ผ ์—…๋กœ๋“œ ๋กœ์ง๊ณผ ์—๋Ÿฌ ์ฒ˜๋ฆฌ๊ฐ€ ๋ณต์žกํ•จ. coroutineScope ๋ฐ parallelism ๊ตฌํ˜„ ๊ฒ€์ฆ ํ•„์š”
  • DTO ํ•„๋“œ๋ช… ๋ณ€๊ฒฝ: primaryTag โ†’ mainTag, subTagAIdList โ†’ subTag1Ids/subTag2Ids ๋ณ€๊ฒฝ์ด ์—ฌ๋Ÿฌ ํŒŒ์ผ์— ๊ฑธ์ณ ์žˆ์Œ. ๋งคํ•‘ ๋กœ์ง์˜ ์ผ๊ด€์„ฑ ํ™•์ธ ํ•„์š”
  • Naver API ๋ชจ๋“ˆ ํ†ตํ•ฉ: NaverApiModule DI ๋ฐ”์ธ๋”ฉ, ํ—ค๋” ์ฃผ์ž…, Retrofit ์„ค์ •์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ตฌ์„ฑ๋˜์—ˆ๋Š”์ง€ ํ™•์ธ ํ•„์š”
  • ์ƒํƒœ ๊ด€๋ฆฌ ๋ณ€๊ฒฝ: isSearchDialogVisible ์ œ๊ฑฐ ๋ฐ ์ƒˆ๋กœ์šด ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ ๊ธฐ๋ฐ˜ ๋„ค๋น„๊ฒŒ์ด์…˜์œผ๋กœ์˜ ์ „ํ™˜. ๊ธฐ์กด ๋Œ€ํ™”ํ˜• ํ๋ฆ„๊ณผ์˜ ํ˜ธํ™˜์„ฑ ํ™•์ธ ํ•„์š”

๐Ÿ”— ๊ด€๋ จ PR ๋ชฉ๋ก

  • [feature#141] search placeย #145: ์ฃผ PR๊ณผ ๊ฐ™์ด ๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๊ณ  PlaceType ์œ ํ‹ธ๋ฆฌํ‹ฐ๋ฅผ ํ™•์žฅํ•˜๋Š” ์ž‘์—…
  • [Feature/#84] town update api connectย #108: ์ฆ๊ฒจ์ฐพ๊ธฐ ๋™๋„ค ์„ ํƒ UI ๋ฐ ๋„ค๋น„๊ฒŒ์ด์…˜ ๊ตฌ์กฐ ๋ณ€๊ฒฝ ๊ด€๋ จ
  • [Feature/#131] ์ œ๋ณดํ•˜๊ธฐย #139: ์ œ๋ณด ๊ธฐ๋Šฅ (ReportPlaceDialog, presigned URL, ํŒŒ์ผ ์—…๋กœ๋“œ) ๊ตฌํ˜„์œผ๋กœ ์œ ์‚ฌํ•œ ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ ๋กœ์ง ํฌํ•จ

๐Ÿท๏ธ ์ œ์•ˆ ๋ผ๋ฒจ

์„์ฐฌ๐Ÿš๐Ÿฆ, ui๐ŸŽƒ

๐Ÿ‘ฅ ์ œ์•ˆ ๊ฒ€ํ† ์ž

  • 88guri

๐Ÿฐ Poem

๐Ÿ” ๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ๊ณผ ์žฅ์†Œ ๋“ฑ๋ก ํ๋ฆ„,
๐Ÿ–ผ๏ธ ๋„ค๋น„๊ฒŒ์ด์…˜ ๊ฐˆ๋ž˜๊ธธ์„ ์ƒˆ๋กœ ๋‚˜๋ˆ„๊ณ ,
๐Ÿ“ธ ์‚ฌ์ง„ ์—…๋กœ๋“œ์™€ Naver API ํ†ตํ•ฉ,
โœจ ๋™๋„ค ์„ ํƒ๋ถ€ํ„ฐ ์ง€๋„๊นŒ์ง€ ์ด์–ด์ง€๋Š” ์—ฌ์ •,
๐Ÿš€ ํ•œ ๊ฑธ์Œ ๋” ๋‚˜์•„๊ฐ€๋Š” ์†”ํ”Œ๋ฆฌ!

Pre-merge checks and finishing touches

โŒ Failed checks (3 warnings, 1 inconclusive)
Check name Status Explanation Resolution
Title check โš ๏ธ Warning PR ์ œ๋ชฉ '[Refactor/#144] first qa'๋Š” ์‹ค์ œ ๋ณ€๊ฒฝ ์‚ฌํ•ญ๊ณผ ๋งž์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋ณ€๊ฒฝ ์‚ฌํ•ญ์€ ์žฅ์†Œ ๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ ์ถ”๊ฐ€, Naver API ํ†ตํ•ฉ, ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ, ์ฆ๊ฒจ์ฐพ๊ธฐ ๋™๋„ค ๋„ค๋น„๊ฒŒ์ด์…˜ ๋“ฑ ๊ด‘๋ฒ”์œ„ํ•œ ๊ธฐ๋Šฅ ๊ฐœ์„ ์ด์ง€๋งŒ, ์ œ๋ชฉ์€ 'first qa'๋ผ๋Š” ๋ชจํ˜ธํ•œ ์šฉ์–ด๋งŒ ํฌํ•จํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ œ๋ชฉ์„ ๋” ๊ตฌ์ฒด์ ์œผ๋กœ ๋ณ€๊ฒฝํ•˜์„ธ์š”. ์˜ˆ: '[Refactor/#144] Add place registration and search features' ๋˜๋Š” '์ฃผ์š” ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ๋ฐ˜์˜ํ•œ ๋ช…ํ™•ํ•œ ์ œ๋ชฉ์œผ๋กœ ์ˆ˜์ •์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.
Out of Scope Changes check โš ๏ธ Warning ๋ณ€๊ฒฝ ์‚ฌํ•ญ ์ค‘ ์—ฌ๋Ÿฌ ํ•ญ๋ชฉ์ด ์ฃผ์š” ๋ฒ”์œ„๋ฅผ ๋ฒ—์–ด๋‚œ ๊ฒƒ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค: (1) Naver API ๋ชจ๋“ˆ ๋ฐ ๋กœ์ปฌ ๊ฒ€์ƒ‰ ํ†ตํ•ฉ, (2) ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ ๋ฐ S3 ๊ด€๋ จ ๋ณ€๊ฒฝ, (3) ๋™๋„ค ์„ ํƒ ๋„ค๋น„๊ฒŒ์ด์…˜ ์žฌ๊ตฌ์กฐํ™”, (4) ๊ฒ€์ƒ‰ ๋Œ€ํ™”์ƒ์ž ์ œ๊ฑฐ ๋ฐ ์ƒˆ ํ™”๋ฉด ๋„์ž… ๋“ฑ์ด ๋ชจ๋‘ 'UI ์ˆ˜์ •'์˜ ๋ฒ”์œ„๋ฅผ ํฌ๊ฒŒ ์ดˆ๊ณผํ•ฉ๋‹ˆ๋‹ค. ์ด์Šˆ #144์— ๊ตฌ์ฒด์ ์ธ ๋ฒ”์œ„ ์ •์˜๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ , ๋ฐฑ์—”๋“œ API ํ†ตํ•ฉ, ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ, ๋„ค๋น„๊ฒŒ์ด์…˜ ๊ตฌ์กฐ ๋ณ€๊ฒฝ ๋“ฑ์ด ํฌํ•จ๋˜๋Š”์ง€ ๋ช…ํ™•ํžˆ ํ•˜์„ธ์š”.
Docstring Coverage โš ๏ธ Warning Docstring coverage is 1.59% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Linked Issues check โ“ Inconclusive ์—ฐ๊ฒฐ๋œ ์ด์Šˆ #144๋Š” '์žฅ์†Œ ui 1์ฐจ ์ˆ˜์ •'์ด๋ผ๋Š” ์ œ๋ชฉ๋งŒ ์žˆ๊ณ , ๊ตฌ์ฒด์ ์ธ ์š”๊ตฌ์‚ฌํ•ญ, ์ˆ˜๋ฝ ๊ธฐ์ค€, ๋˜๋Š” ๊ฒ€์ฆ ๊ฐ€๋Šฅํ•œ ๋ชฉํ‘œ๊ฐ€ ์ œ๊ณต๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ๋ณ€๊ฒฝ ์‚ฌํ•ญ์˜ ๋ฒ”์œ„์™€ ์ด์Šˆ์˜ ์š”๊ตฌ์‚ฌํ•ญ์„ ๋งค์นญํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์—ฐ๊ฒฐ๋œ ์ด์Šˆ #144์—์„œ ๊ตฌ์ฒด์ ์ธ ์š”๊ตฌ์‚ฌํ•ญ๊ณผ ์ˆ˜๋ฝ ๊ธฐ์ค€์„ ๋ช…์‹œํ•˜์—ฌ, PR ๋ณ€๊ฒฝ ์‚ฌํ•ญ๊ณผ์˜ ๋Œ€์‘ ๊ด€๊ณ„๋ฅผ ๋ช…ํ™•ํžˆ ํ•˜์„ธ์š”.
โœ… Passed checks (1 passed)
Check name Status Explanation
Description Check โœ… Passed Check skipped - CodeRabbitโ€™s high-level summary is enabled.
โœจ Finishing touches
  • ๐Ÿ“ Generate docstrings
๐Ÿงช Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor/#144-first-qa

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.

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

Caution

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

โš ๏ธ Outside diff range comments (6)
core/ui/src/main/java/com/teamsolply/solply/ui/util/PresignedUrlUploader.kt (2)

52-52: OkHttpClient ์ธ์Šคํ„ด์Šค ์žฌ์‚ฌ์šฉ ํ•„์š”

๋งค ์—…๋กœ๋“œ๋งˆ๋‹ค ์ƒˆ๋กœ์šด OkHttpClient ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. OkHttpClient๋Š” ์—ฐ๊ฒฐ ํ’€๊ณผ ์Šค๋ ˆ๋“œ ํ’€์„ ๊ด€๋ฆฌํ•˜๋ฏ€๋กœ, ๋งค๋ฒˆ ์ƒ์„ฑํ•˜๋ฉด ๋ฆฌ์†Œ์Šค ๋‚ญ๋น„์™€ ์„ฑ๋Šฅ ์ €ํ•˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ๊ณผ ๊ฐ™์ด OkHttpClient๋ฅผ ์ฃผ์ž…๋ฐ›๊ฑฐ๋‚˜ ์‹ฑ๊ธ€ํ†ค์œผ๋กœ ๊ด€๋ฆฌํ•˜๋„๋ก ์ˆ˜์ •ํ•˜์„ธ์š”:

 fun uploadToPresignedUrl(
     context: Context,
     uri: Uri,
-    presignedUrl: String
+    presignedUrl: String,
+    client: OkHttpClient = OkHttpClient()
 ) {
     val cr = context.contentResolver
     val mime = cr.getType(uri) ?: "application/octet-stream"
     val len = cr.length(uri)
     require(len >= 0) { "Content length unknown; presigned PUT may reject chunked transfer" }

     val body = FixedLenUriBody(context, uri, mime, len)
     val req = Request.Builder()
         .url(presignedUrl)
         .put(body)
         .build()

-    OkHttpClient().newCall(req).execute().use { resp ->
+    client.newCall(req).execute().use { resp ->
         if (!resp.isSuccessful) {
             val err = resp.body?.string()
             throw IllegalStateException("Upload failed: ${resp.code} body=$err")
         }
     }
 }

๋” ๋‚˜์€ ๋ฐฉ๋ฒ•์€ DI๋ฅผ ํ†ตํ•ด ์„ค์ •๋œ OkHttpClient๋ฅผ ์ฃผ์ž…๋ฐ›๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.


36-58: ANR ์œ„ํ—˜: ๋ฉ”์ธ ์Šค๋ ˆ๋“œ์—์„œ ๋ธ”๋กœํ‚น I/O ๋ฐฉ์ง€ ํ•„์š”

์ด ํ•จ์ˆ˜๋Š” ๋™๊ธฐ/๋ธ”๋กœํ‚น ๋ฐฉ์‹์œผ๋กœ ๋„คํŠธ์›Œํฌ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. Android ๋ฉ”์ธ ์Šค๋ ˆ๋“œ์—์„œ ํ˜ธ์ถœ๋  ๊ฒฝ์šฐ ANR(Application Not Responding)์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ ์ค‘ ํ•˜๋‚˜์˜ ๋ฐฉ๋ฒ•์œผ๋กœ ๊ฐœ์„ ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค:

๋ฐฉ๋ฒ• 1: Suspend ํ•จ์ˆ˜๋กœ ๋ณ€๊ฒฝ (๊ถŒ์žฅ)

suspend fun uploadToPresignedUrl(
    context: Context,
    uri: Uri,
    presignedUrl: String,
    client: OkHttpClient = OkHttpClient()
) {
    withContext(Dispatchers.IO) {
        // ๊ธฐ์กด ๊ตฌํ˜„
    }
}

๋ฐฉ๋ฒ• 2: ์ฝœ๋ฐฑ ๊ธฐ๋ฐ˜ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ

fun uploadToPresignedUrl(
    context: Context,
    uri: Uri,
    presignedUrl: String,
    client: OkHttpClient = OkHttpClient(),
    onSuccess: () -> Unit,
    onError: (Exception) -> Unit
) {
    client.newCall(req).enqueue(object : Callback {
        // ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ
    })
}
feature/maps/src/main/java/com/teamsolply/solply/maps/MapsViewModel.kt (2)

346-366: Null ๊ฒ€์‚ฌ ์—†์ด ๊ฐ•์ œ ์–ธ๋ž˜ํ•‘ ์‚ฌ์šฉ

Line 354์—์„œ courseId!!๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ•์ œ ์–ธ๋ž˜ํ•‘ํ•˜๊ณ  ์žˆ์ง€๋งŒ, courseId ํŒŒ๋ผ๋ฏธํ„ฐ๋Š” Long? (nullable) ํƒ€์ž…์ž…๋‹ˆ๋‹ค. courseId๊ฐ€ null์ธ ๊ฒฝ์šฐ NullPointerException์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ diff๋ฅผ ์ ์šฉํ•˜์—ฌ null ๊ฒ€์‚ฌ๋ฅผ ์ถ”๊ฐ€ํ•˜์„ธ์š”:

 private fun savePlaceToCourse(
     townId: Long,
     courseId: Long?,
     placeId: Long,
     selectedCourseName: String
 ) {
+    if (courseId == null) {
+        // TODO: Handle null courseId case
+        return
+    }
     viewModelScope.launch {
         mapsRepository.postPlaceToCourse(
-            courseId = courseId!!,
+            courseId = courseId,
             placeId = placeId
         ).onSuccess {

520-525: ์—๋Ÿฌ ์ฒ˜๋ฆฌ ์‹œ ์‚ฌ์šฉ์ž ํ”ผ๋“œ๋ฐฑ ๋ถ€์žฌ

๋ชจ๋“  ์—๋Ÿฌ ํ•ธ๋“ค๋Ÿฌ(lines 520-525, 570-574, 575-578, 579-583)๊ฐ€ ๋‹จ์ˆœํžˆ ๋‹ค์ด์–ผ๋กœ๊ทธ๋ฅผ ๋‹ซ๊ธฐ๋งŒ ํ•˜๊ณ  ์‚ฌ์šฉ์ž์—๊ฒŒ ์—๋Ÿฌ ๋ฐœ์ƒ์„ ์•Œ๋ฆฌ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž๋Š” ์ž‘์—…์ด ์‹คํŒจํ–ˆ๋Š”์ง€ ์•Œ ์ˆ˜ ์—†์œผ๋ฏ€๋กœ, MapsSideEffect๋ฅผ ํ†ตํ•ด ์—๋Ÿฌ ์Šค๋‚ต๋ฐ”๋‚˜ ํ† ์ŠคํŠธ๋ฅผ ํ‘œ์‹œํ•˜๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•ด์ฃผ์„ธ์š”.

์˜ˆ๋ฅผ ๋“ค์–ด, MapsSideEffect์— ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ด๋ฒคํŠธ๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

// MapsSideEffect.kt์— ์ถ”๊ฐ€
data object ShowReportErrorSnackBar : MapsSideEffect()

๊ทธ๋ฆฌ๊ณ  onFailure ๋ธ”๋ก์„ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ˆ˜์ •:

                 }.onFailure { error ->
                     android.util.Log.e("PresignedUrl", "โŒ ์‹ ๊ณ  ์‹คํŒจ (์ด๋ฏธ์ง€ ์—†์Œ): ${error.message}", error)
-                    // TODO. ์‹ ๊ณ  ์‹คํŒจ ์ฒ˜๋ฆฌ
+                    postSideEffect(MapsSideEffect.ShowReportErrorSnackBar)
                     delay(5000)
                     sendIntent(MapsIntent.ChangeReportPlaceDialogVisibility(visible = false))
                 }

Also applies to: 570-574, 575-578, 579-583

feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/FavoriteViewModel.kt (1)

30-36: ์„ ํƒ๋œ ๋™๋„ค์— ๋งž๋Š” ์ง€์—ญ์ด ๊ฐฑ์‹ ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

FavoriteTownIntent.LoadFavoriteTownList๋กœ ์ „๋‹ฌ๋ฐ›์€ selectedTownId๊ฐ€ ๋‹ค๋ฅธ ์ง€์—ญ์— ์†ํ•ด ์žˆ์–ด๋„ selectedRegionId๋Š” ํ•ญ์ƒ ์ฒซ ์ง€์—ญ์œผ๋กœ ๊ณ ์ •๋ฉ๋‹ˆ๋‹ค. ๊ทธ ๊ฒฐ๊ณผ ์ฆ๊ฒจ์ฐพ๊ธฐ ํ™”๋ฉด ์ง„์ž… ์‹œ ์„ ํƒ๋ผ ์žˆ์–ด์•ผ ํ•  ๋™๋„ค๊ฐ€ ๋น„๋…ธ์ถœ๋˜๊ณ , ์‚ฌ์šฉ์ž๊ฐ€ ์ง€์—ญ์„ ๋‹ค์‹œ ์ฐพ์•„์•ผ ํ•˜๋Š” UX ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ์ „๋‹ฌ๋ฐ›์€ ๋™๋„ค๊ฐ€ ์†ํ•œ ์ง€์—ญ์„ ์šฐ์„  ์ฐพ๊ณ , ์—†์„ ๋•Œ๋งŒ ๊ธฐ๋ณธ๊ฐ’์„ ์‚ฌ์šฉํ•˜๋„๋ก ๋ณด์ •ํ•ด ์ฃผ์„ธ์š”.

                 .onSuccess { (regions, townsByRegion) ->
-                    reduce {
-                        copy(
-                            regions = regions,
-                            townsByRegion = townsByRegion,
-                            selectedRegionId = regions.firstOrNull()?.id,
-                            selectedTownId = selectedTownId
-                        )
-                    }
+                    val resolvedRegionId = selectedTownId?.let { targetId ->
+                        townsByRegion.entries.firstOrNull { (_, towns) ->
+                            towns.any { it.id == targetId }
+                        }?.key
+                    } ?: regions.firstOrNull()?.id
+
+                    val resolvedTownId = selectedTownId ?: resolvedRegionId
+                        ?.let { regionId -> townsByRegion[regionId]?.firstOrNull()?.id }
+
+                    reduce {
+                        copy(
+                            regions = regions,
+                            townsByRegion = townsByRegion,
+                            selectedRegionId = resolvedRegionId,
+                            selectedTownId = resolvedTownId
+                        )
+                    }
                 }
feature/place/src/main/java/com/teamsolply/solply/place/PlaceScreen.kt (1)

77-89: ์ตœ์‹  state ์—†์ด ์ฆ๊ฒจ์ฐพ๋Š” ๋™๋„ค ID๋ฅผ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.

Line 80์—์„œ navigateToFavoriteTown(state.userInfo.selectedTown.townId)๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด, LaunchedEffectWithLifecycle ๋‚ด๋ถ€ ์ฝ”๋ฃจํ‹ด์ด ์ตœ์ดˆ ํ•ฉ์„ฑ ์‹œ์ ์˜ state๋งŒ ์บก์ฒ˜ํ•ฉ๋‹ˆ๋‹ค. ์ดํ›„ uiState์— ์‹ค์ œ ๋™๋„ค ID๊ฐ€ ๋กœ๋“œ๋ผ๋„ ์ตœ์‹  ๊ฐ’์ด ๋ฐ˜์˜๋˜์ง€ ์•Š์•„ ์ž˜๋ชป๋œ ID(์˜ˆ: ์ดˆ๊ธฐ๊ฐ’ 0)๋กœ ๋‚ด๋น„๊ฒŒ์ด์…˜์ด ์‹คํ–‰๋˜๋Š” ์น˜๋ช…์ ์ธ ๋™์ž‘์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. sideEffect๊ฐ€ ์ œ๊ณตํ•˜๋Š” ID๋ฅผ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ rememberUpdatedState ๋“ฑ์„ ํ™œ์šฉํ•ด ์ตœ์‹  ๊ฐ’์„ ์ฐธ์กฐํ•˜๋„๋ก ์ˆ˜์ •ํ•ด์ฃผ์„ธ์š”.(developer.android.com)

-                is PlaceSideEffect.NavigateToFavoriteTown -> navigateToFavoriteTown(
-                    state.userInfo.selectedTown.townId
-                )
+                is PlaceSideEffect.NavigateToFavoriteTown -> sideEffect.selectedTownId?.let { selectedId ->
+                    navigateToFavoriteTown(selectedId)
+                }
๐Ÿงน Nitpick comments (12)
feature/search/src/main/java/com/teamsolply/solply/registerplace/component/RegisterPlaceItem.kt (3)

14-18: ๋งค๊ฐœ๋ณ€์ˆ˜ ์ˆœ์„œ ๊ฐœ์„ ์„ ๊ณ ๋ คํ•ด๋ณด์„ธ์š”.

Jetpack Compose์˜ ์ผ๋ฐ˜์ ์ธ ์ปจ๋ฒค์…˜์— ๋”ฐ๋ฅด๋ฉด, modifier ๋งค๊ฐœ๋ณ€์ˆ˜๋Š” ํ•„์ˆ˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋“ค ๋‹ค์Œ, ๊ทธ๋ฆฌ๊ณ  ํ›„ํ–‰ ๋žŒ๋‹ค(trailing lambda)๊ฐ€ ์žˆ๋‹ค๋ฉด ๊ทธ ์ด์ „์— ์œ„์น˜ํ•˜๋Š” ๊ฒƒ์ด ๊ถŒ์žฅ๋ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•ด๋ณด์„ธ์š”:

 @Composable
 internal fun RegisterPlaceItem(
     placeName: String,
     placeAddress: String,
-    modifier: Modifier = Modifier,
-    onClick: (String, String) -> Unit
+    onClick: (String, String) -> Unit,
+    modifier: Modifier = Modifier
 ) {

๋˜๋Š” onClick์„ ํ›„ํ–‰ ๋žŒ๋‹ค๋กœ ์‚ฌ์šฉํ•˜๋ ค๋ฉด:

@Composable
internal fun RegisterPlaceItem(
    placeName: String,
    placeAddress: String,
    modifier: Modifier = Modifier,
    onClick: (String, String) -> Unit
)

์ด๋ ‡๊ฒŒ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

RegisterPlaceItem(name, address) { name, address ->
    // handle click
}

20-39: ์ ‘๊ทผ์„ฑ ๊ฐœ์„ ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.

์Šคํฌ๋ฆฐ ๋ฆฌ๋” ์‚ฌ์šฉ์ž๋ฅผ ์œ„ํ•œ ์ ‘๊ทผ์„ฑ ์ •๋ณด๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. semantics modifier๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ์ ‘๊ทผ์„ฑ์„ ๊ฐœ์„ ํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ ‘๊ทผ์„ฑ์„ ๊ฐœ์„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

+import androidx.compose.ui.semantics.contentDescription
+import androidx.compose.ui.semantics.semantics
+
 @Composable
 internal fun RegisterPlaceItem(
     placeName: String,
     placeAddress: String,
     modifier: Modifier = Modifier,
     onClick: (String, String) -> Unit
 ) {
     Column(
         modifier = modifier
             .fillMaxWidth()
             .padding(horizontal = 20.dp, vertical = 16.dp)
+            .semantics(mergeDescendants = true) {
+                contentDescription = "$placeName, $placeAddress"
+            }
             .customClickable(rippleEnabled = false) {
                 onClick(placeName, placeAddress)
             }
     ) {

28-38: ๋นˆ ๋ฌธ์ž์—ด ์ฒ˜๋ฆฌ๋ฅผ ๊ณ ๋ คํ•ด๋ณด์„ธ์š”.

placeName์ด๋‚˜ placeAddress๊ฐ€ ๋นˆ ๋ฌธ์ž์—ด์ผ ๊ฒฝ์šฐ์— ๋Œ€ํ•œ ์ฒ˜๋ฆฌ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ์—์„œ ์ด๋ฏธ ์ฒ˜๋ฆฌํ•˜๊ณ  ์žˆ๋‹ค๋ฉด ๋ฌธ์ œ์—†์ง€๋งŒ, ๊ทธ๋ ‡์ง€ ์•Š๋‹ค๋ฉด ๋นˆ ์ƒํƒœ์— ๋Œ€ํ•œ UI ์ฒ˜๋ฆฌ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

์˜ˆ์‹œ:

if (placeName.isNotBlank()) {
    Text(
        text = placeName,
        modifier = Modifier.padding(bottom = 7.dp),
        style = SolplyTheme.typography.title15M,
        color = SolplyTheme.colors.black,
    )
}
if (placeAddress.isNotBlank()) {
    Text(
        text = placeAddress,
        style = SolplyTheme.typography.caption12R,
        color = SolplyTheme.colors.gray700,
    )
}
core/ui/src/main/java/com/teamsolply/solply/ui/util/PresignedUrlUploader.kt (1)

52-52: ํƒ€์ž„์•„์›ƒ ์„ค์ • ์ถ”๊ฐ€ ๊ถŒ์žฅ

OkHttpClient์— ํƒ€์ž„์•„์›ƒ ์„ค์ •์ด ์—†์–ด ์—…๋กœ๋“œ๊ฐ€ ๋ฌดํ•œ์ • ๋Œ€๊ธฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํŠนํžˆ ๋Œ€์šฉ๋Ÿ‰ ํŒŒ์ผ ์—…๋กœ๋“œ๋‚˜ ๋„คํŠธ์›Œํฌ ๋ถˆ์•ˆ์ • ์‹œ ๋ฌธ์ œ๊ฐ€ ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

OkHttpClient ์ƒ์„ฑ ์‹œ ํƒ€์ž„์•„์›ƒ์„ ์„ค์ •ํ•˜์„ธ์š”:

val client = OkHttpClient.Builder()
    .connectTimeout(30, TimeUnit.SECONDS)
    .writeTimeout(60, TimeUnit.SECONDS)
    .readTimeout(30, TimeUnit.SECONDS)
    .build()
feature/maps/src/main/java/com/teamsolply/solply/maps/MapsViewModel.kt (3)

508-527: ์ด๋ฏธ์ง€ ์—†๋Š” ๊ฒฝ์šฐ์˜ ์กฐ๊ธฐ ์ข…๋ฃŒ ๋กœ์ง์ด ์ž˜ ๊ตฌํ˜„๋˜์—ˆ์Šต๋‹ˆ๋‹ค

์ด๋ฏธ์ง€๊ฐ€ ์—†์„ ๋•Œ ๋ถˆํ•„์š”ํ•œ presigned URL ๋ฐœ๊ธ‰ ๋ฐ ์—…๋กœ๋“œ ๊ณผ์ •์„ ๊ฑด๋„ˆ๋›ฐ๋Š” ์ตœ์ ํ™”๊ฐ€ ์ ์ ˆํ•ฉ๋‹ˆ๋‹ค.

๋‹ค๋งŒ, ์‹คํŒจ ์‹œ(line 520-525) ์‚ฌ์šฉ์ž์—๊ฒŒ ์—๋Ÿฌ ๋ฉ”์‹œ์ง€๋ฅผ ํ‘œ์‹œํ•˜์ง€ ์•Š๊ณ  ๋‹ค์ด์–ผ๋กœ๊ทธ๋งŒ ๋‹ซํžˆ๋Š” ๊ฒƒ์€ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์— ์ข‹์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. MapsSideEffect๋ฅผ ํ†ตํ•ด ์—๋Ÿฌ ์Šค๋‚ต๋ฐ”๋‚˜ ํ† ์ŠคํŠธ๋ฅผ ํ‘œ์‹œํ•˜๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•ด์ฃผ์„ธ์š”.


517-517: ๋กœ๊น… ์ถ”์ƒํ™” ์‚ฌ์šฉ ๊ถŒ์žฅ

android.util.Log๋ฅผ ์ง์ ‘ ์‚ฌ์šฉํ•˜๋Š” ๋Œ€์‹  ๋กœ๊น… ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ(์˜ˆ: Timber)๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ํ”„๋กœ๋•์…˜ ๋นŒ๋“œ์—์„œ ๋กœ๊ทธ๋ฅผ ์‰ฝ๊ฒŒ ์ œ์–ดํ•˜๊ณ , ๋” ๋‚˜์€ ๋กœ๊ทธ ๊ด€๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

ํ”„๋กœ์ ํŠธ์— Timber๊ฐ€ ์ด๋ฏธ ํฌํ•จ๋˜์–ด ์žˆ๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”:

#!/bin/bash
# Description: Check if Timber is already used in the project

echo "=== Checking for Timber usage ==="
rg -n "import timber.log.Timber" --type kotlin

echo -e "\n=== Checking build.gradle for Timber dependency ==="
fd -e gradle -e kts | xargs rg "timber"

Also applies to: 521-521, 534-534, 557-558, 567-567, 571-571, 576-577, 580-581


518-518: ๋งค์ง ๋„˜๋ฒ„๋ฅผ ์ƒ์ˆ˜๋กœ ์ถ”์ถœ

delay(2500)๊ณผ delay(5000) ๊ฐ™์€ ๋งค์ง ๋„˜๋ฒ„๋ฅผ ์˜๋ฏธ์žˆ๋Š” ์ด๋ฆ„์„ ๊ฐ€์ง„ ์ƒ์ˆ˜๋กœ ์ถ”์ถœํ•˜์—ฌ ๊ฐ€๋…์„ฑ๊ณผ ์œ ์ง€๋ณด์ˆ˜์„ฑ์„ ํ–ฅ์ƒ์‹œํ‚ค์„ธ์š”.

ํด๋ž˜์Šค ์ƒ๋‹จ์— companion object๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ์ƒ์ˆ˜๋ฅผ ์ •์˜ํ•˜์„ธ์š”:

companion object {
    private const val REPORT_SUCCESS_DIALOG_DELAY_MS = 2500L
    private const val REPORT_ERROR_DIALOG_DELAY_MS = 5000L
}

๊ทธ๋ฆฌ๊ณ  delay ํ˜ธ์ถœ ๋ถ€๋ถ„์„ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ˆ˜์ •ํ•˜์„ธ์š”:

-                    delay(2500)
+                    delay(REPORT_SUCCESS_DIALOG_DELAY_MS)
-                    delay(5000)
+                    delay(REPORT_ERROR_DIALOG_DELAY_MS)

Also applies to: 523-523, 568-568, 572-572

feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceScreen.kt (1)

143-171: ๋ณต์žกํ•œ ํ•จ์ˆ˜ ์‹œ๊ทธ๋‹ˆ์ฒ˜

RegisterPlaceScreen์ด 20๊ฐœ ์ด์ƒ์˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ๋ฐ›๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ํ•จ์ˆ˜๊ฐ€ ๋„ˆ๋ฌด ๋งŽ์€ ์ฑ…์ž„์„ ๊ฐ€์ง€๊ณ  ์žˆ์–ด ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ์–ด๋ ค์šธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ด€๋ จ๋œ ๋งค๊ฐœ๋ณ€์ˆ˜๋“ค์„ ๋ฐ์ดํ„ฐ ํด๋ž˜์Šค๋กœ ๊ทธ๋ฃนํ™”ํ•˜๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•ด๋ณด์„ธ์š”.

์˜ˆ์‹œ:

data class RegisterPlaceScreenParams(
    val uiState: RegisterPlaceState,
    val paddingValues: PaddingValues,
    val callbacks: RegisterPlaceCallbacks
)

data class RegisterPlaceCallbacks(
    val navigateToBack: () -> Unit,
    val inputPlaceNameText: (String) -> Unit,
    // ... other callbacks
)
domain/search/src/main/java/com/teamsolply/solply/search/model/NaverLocalSearchResponseEntity.kt (1)

11-12: ์ขŒํ‘œ ํ•„๋“œ์˜ ํƒ€์ž…์„ ๊ณ ๋ คํ•˜์„ธ์š”.

mapx์™€ mapy๊ฐ€ String ํƒ€์ž…์œผ๋กœ ์„ ์–ธ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. Naver API ์‘๋‹ต ํ˜•์‹์— ๋งž์ถ˜ ๊ฒƒ์œผ๋กœ ๋ณด์ด์ง€๋งŒ, ์ขŒํ‘œ ๊ณ„์‚ฐ์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ Double์ด๋‚˜ Float์œผ๋กœ ๋ณ€ํ™˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

feature/search/src/main/java/com/teamsolply/solply/registerplace/component/PlaceTypeDropDown.kt (1)

97-97: ํ•จ์ˆ˜ ๊ฐ€์‹œ์„ฑ์„ ์ œํ•œํ•˜๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•˜์„ธ์š”.

getPlaceTypeIconResId ํ•จ์ˆ˜๊ฐ€ ์ด ์ปดํฌ๋„ŒํŠธ ์™ธ๋ถ€์—์„œ ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š”๋‹ค๋ฉด internal ๋˜๋Š” private์œผ๋กœ ์„ ์–ธํ•˜์—ฌ API ๋…ธ์ถœ ๋ฒ”์œ„๋ฅผ ์ œํ•œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

-fun getPlaceTypeIconResId(item: PlaceType): Int {
+internal fun getPlaceTypeIconResId(item: PlaceType): Int {
core/network/src/main/java/com/teamsolply/solply/network/model/NaverLocalSearchResponseDto.kt (1)

5-25: ์™ธ๋ถ€ API DTO์— @SerialName ์–ด๋…ธํ…Œ์ด์…˜ ์ถ”๊ฐ€ ๊ถŒ์žฅ

๋„ค์ด๋ฒ„ API ์‘๋‹ต DTO์— ๋ช…์‹œ์ ์ธ @SerialName ์–ด๋…ธํ…Œ์ด์…˜์ด ์—†์Šต๋‹ˆ๋‹ค. ์™ธ๋ถ€ API์™€์˜ ๊ณ„์•ฝ์„ ๋ช…ํ™•ํžˆ ํ•˜๊ณ  ํ–ฅํ›„ ํ•„๋“œ๋ช… ๋ณ€๊ฒฝ์œผ๋กœ ์ธํ•œ ์—ญ์ง๋ ฌํ™” ์˜ค๋ฅ˜๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ๋ชจ๋“  ํ•„๋“œ์— @SerialName์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ˆ˜์ •ํ•˜์„ธ์š”:

 @Serializable
 data class NaverLocalSearchResponseDto(
+    @SerialName("lastBuildDate")
     val lastBuildDate: String,
+    @SerialName("total")
     val total: Int,
+    @SerialName("start")
     val start: Int,
+    @SerialName("display")
     val display: Int,
+    @SerialName("items")
     val items: List<LocalSearchItem>
 )
 
 @Serializable
 data class LocalSearchItem(
+    @SerialName("title")
     val title: String,
+    @SerialName("link")
     val link: String,
+    @SerialName("category")
     val category: String,
+    @SerialName("description")
     val description: String,
+    @SerialName("telephone")
     val telephone: String,
+    @SerialName("address")
     val address: String,
+    @SerialName("roadAddress")
     val roadAddress: String,
+    @SerialName("mapx")
     val mapx: String,
+    @SerialName("mapy")
     val mapy: String
 )
feature/main/src/main/java/com/teamsolply/solply/main/MainScreen.kt (1)

392-413: launchSingleTop ์‚ฌ์šฉ์˜ ์ผ๊ด€์„ฑ์„ ํ™•์ธํ•˜์„ธ์š”.

๊ฒ€์ƒ‰ ๋„ค๋น„๊ฒŒ์ด์…˜์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ตฌํ˜„๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ navigateToPlaceDetail์€ launchSingleTop = true๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐ˜๋ฉด, navigateToRegisterPlace๋Š” ์‚ฌ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ์˜๋„๋œ ๋™์ž‘์ธ์ง€ ํ™•์ธํ•˜์„ธ์š”.

๋˜ํ•œ 408๋ฒˆ ๋ผ์ธ์˜ ํ•œ๊ธ€ ์ฃผ์„์€ ์ฝ”๋“œ ์œ ์ง€๋ณด์ˆ˜์„ฑ์„ ์œ„ํ•ด ์˜๋ฌธ์œผ๋กœ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ฃผ์„์„ ์˜๋ฌธ์œผ๋กœ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•˜์„ธ์š”:

-                                popUpTo(Search) { inclusive = true }  // โญ Search๋ฅผ ์Šคํƒ์—์„œ ์ œ๊ฑฐ
+                                popUpTo(Search) { inclusive = true }  // โญ Remove Search from stack
๐Ÿ“œ Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

๐Ÿ“ฅ Commits

Reviewing files that changed from the base of the PR and between 4cdce4d and a549df7.

๐Ÿ“’ Files selected for processing (66)
  • build-logic/convention/src/main/java/com/teamsolply/solply/convention/BuildConfig.kt (1 hunks)
  • core/buildconfig/src/main/java/com/teamsolply/solply/buildconfig/impl/BuildConfigFieldsProviderImpl.kt (2 hunks)
  • core/common/src/main/java/com/teamsolply/solply/common/buildconfig/BuildConfigFields.kt (1 hunks)
  • core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/card/RegisterPlaceImage.kt (1 hunks)
  • core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/dropdown/SolplyBasicDropDown.kt (4 hunks)
  • core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/header/SolplyHomeHeader.kt (2 hunks)
  • core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/textfield/SolplyTextField.kt (11 hunks)
  • core/designsystem/src/main/res/drawable/ic_arrow_down_lg.xml (1 hunks)
  • core/model/src/main/java/com/teamsolply/solply/model/PlaceType.kt (1 hunks)
  • core/network/src/main/java/com/teamsolply/solply/network/di/NaverApiModule.kt (1 hunks)
  • core/network/src/main/java/com/teamsolply/solply/network/model/NaverLocalSearchResponseDto.kt (1 hunks)
  • core/network/src/main/java/com/teamsolply/solply/network/service/NaverLocalSearchService.kt (1 hunks)
  • core/ui/src/main/java/com/teamsolply/solply/ui/util/PresignedUrlUploader.kt (1 hunks)
  • data/maps/src/main/java/com/teamsolply/solply/maps/dto/response/PresignedUrlsResponseDto.kt (1 hunks)
  • data/place/src/main/java/com/teamsolply/solply/place/dto/response/GetPlacesResponseDto.kt (1 hunks)
  • data/place/src/main/java/com/teamsolply/solply/place/dto/response/GetRecommendPlaceDto.kt (1 hunks)
  • data/place/src/main/java/com/teamsolply/solply/place/mapper/PlaceEntityMapper.kt (1 hunks)
  • data/place/src/main/java/com/teamsolply/solply/place/repository/PlaceRepositoryImpl.kt (2 hunks)
  • data/search/src/main/java/com/teamsolply/solply/search/dto/request/RegisterPlaceRequestDto.kt (1 hunks)
  • data/search/src/main/java/com/teamsolply/solply/search/dto/response/RegisterPlaceResponseDto.kt (1 hunks)
  • data/search/src/main/java/com/teamsolply/solply/search/dto/response/SearchResponseDto.kt (2 hunks)
  • data/search/src/main/java/com/teamsolply/solply/search/repository/SearchRepositoryImpl.kt (2 hunks)
  • data/search/src/main/java/com/teamsolply/solply/search/source/SearchRemoteDataSource.kt (1 hunks)
  • domain/search/src/main/java/com/teamsolply/solply/search/model/NaverLocalSearchResponseEntity.kt (1 hunks)
  • domain/search/src/main/java/com/teamsolply/solply/search/model/RegisterPlaceEntity.kt (1 hunks)
  • domain/search/src/main/java/com/teamsolply/solply/search/model/SearchResultEntity.kt (1 hunks)
  • domain/search/src/main/java/com/teamsolply/solply/search/repository/SearchRepository.kt (1 hunks)
  • feature/course/src/main/java/com/teamsolply/solply/course/CourseContract.kt (1 hunks)
  • feature/course/src/main/java/com/teamsolply/solply/course/CourseScreen.kt (3 hunks)
  • feature/course/src/main/java/com/teamsolply/solply/course/CourseViewModel.kt (1 hunks)
  • feature/course/src/main/java/com/teamsolply/solply/course/component/FavoriteTownTopBar.kt (2 hunks)
  • feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/FavoriteTownContract.kt (1 hunks)
  • feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/FavoriteTownRoute.kt (10 hunks)
  • feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/FavoriteViewModel.kt (3 hunks)
  • feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/favoriteTownNavigation/FavoriteTownNavigation.kt (1 hunks)
  • feature/course/src/main/java/com/teamsolply/solply/course/navigation/CourseNavigation.kt (1 hunks)
  • feature/main/build.gradle.kts (1 hunks)
  • feature/main/src/main/AndroidManifest.xml (1 hunks)
  • feature/main/src/main/java/com/teamsolply/solply/main/MainNavigator.kt (3 hunks)
  • feature/main/src/main/java/com/teamsolply/solply/main/MainScreen.kt (4 hunks)
  • feature/maps/src/main/java/com/teamsolply/solply/maps/MapsViewModel.kt (5 hunks)
  • feature/maps/src/main/java/com/teamsolply/solply/maps/component/bottomsheet/PlaceDetailBottomSheet.kt (4 hunks)
  • feature/maps/src/main/java/com/teamsolply/solply/maps/component/dialog/ReportPlaceDialog.kt (5 hunks)
  • feature/mypage/src/main/java/com/teamsolply/solply/mypage/component/SolplyPersonaDropDown.kt (1 hunks)
  • feature/place/build.gradle.kts (1 hunks)
  • feature/place/src/main/java/com/teamsolply/solply/place/PlaceContract.kt (1 hunks)
  • feature/place/src/main/java/com/teamsolply/solply/place/PlaceScreen.kt (4 hunks)
  • feature/place/src/main/java/com/teamsolply/solply/place/PlaceViewModel.kt (2 hunks)
  • feature/place/src/main/java/com/teamsolply/solply/place/component/button/PlaceChipButton.kt (1 hunks)
  • feature/place/src/main/java/com/teamsolply/solply/place/navigation/PlaceNavigation.kt (1 hunks)
  • feature/search/build.gradle.kts (1 hunks)
  • feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceContract.kt (1 hunks)
  • feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceScreen.kt (1 hunks)
  • feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceViewModel.kt (1 hunks)
  • feature/search/src/main/java/com/teamsolply/solply/registerplace/component/PlaceTypeDropDown.kt (1 hunks)
  • feature/search/src/main/java/com/teamsolply/solply/registerplace/component/RegisterPlaceItem.kt (1 hunks)
  • feature/search/src/main/java/com/teamsolply/solply/registerplace/navigation/RegisterPlaceNavigation.kt (1 hunks)
  • feature/search/src/main/java/com/teamsolply/solply/search/SearchContract.kt (1 hunks)
  • feature/search/src/main/java/com/teamsolply/solply/search/SearchDialog.kt (0 hunks)
  • feature/search/src/main/java/com/teamsolply/solply/search/SearchScreen.kt (1 hunks)
  • feature/search/src/main/java/com/teamsolply/solply/search/SearchViewModel.kt (1 hunks)
  • feature/search/src/main/java/com/teamsolply/solply/search/navigation/SearchNavigation.kt (1 hunks)
  • remote/place/src/main/java/com/teamsolply/solply/place/datasource/PlaceRemoteDataSourceImpl.kt (1 hunks)
  • remote/place/src/main/java/com/teamsolply/solply/place/service/PlaceService.kt (1 hunks)
  • remote/search/src/main/java/com/teamsolply/solply/search/datasource/SearchRemoteDataSourceImpl.kt (2 hunks)
  • remote/search/src/main/java/com/teamsolply/solply/search/service/SearchService.kt (1 hunks)
๐Ÿ’ค Files with no reviewable changes (1)
  • feature/search/src/main/java/com/teamsolply/solply/search/SearchDialog.kt
๐Ÿงฐ Additional context used
๐Ÿงฌ Code graph analysis (20)
feature/search/src/main/java/com/teamsolply/solply/registerplace/component/PlaceTypeDropDown.kt (1)
core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/dropdown/SolplyBasicDropDown.kt (1)
  • SolplyBasicDropDown (32-99)
feature/search/src/main/java/com/teamsolply/solply/search/SearchScreen.kt (4)
core/ui/src/main/java/com/teamsolply/solply/ui/lifecycle/LaunchedEffectWithLifecycle.kt (1)
  • LaunchedEffectWithLifecycle (11-24)
feature/main/src/main/java/com/teamsolply/solply/main/MainNavigator.kt (2)
  • navigateToRegisterPlace (178-180)
  • navigateToBack (116-118)
core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/textfield/SolplyTextField.kt (1)
  • SolplyRenameCourseTextField (304-330)
feature/search/src/main/java/com/teamsolply/solply/search/component/SearchItem.kt (1)
  • SearchItem (28-89)
feature/course/src/main/java/com/teamsolply/solply/course/CourseViewModel.kt (1)
core/ui/src/main/java/com/teamsolply/solply/ui/base/BaseViewModel.kt (1)
  • postSideEffect (48-52)
core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/card/RegisterPlaceImage.kt (1)
core/ui/src/main/java/com/teamsolply/solply/ui/image/AdaptationImage.kt (1)
  • AdaptationImage (15-69)
feature/course/src/main/java/com/teamsolply/solply/course/navigation/CourseNavigation.kt (1)
feature/course/src/main/java/com/teamsolply/solply/course/CourseScreen.kt (1)
  • CourseRoute (31-86)
feature/maps/src/main/java/com/teamsolply/solply/maps/MapsViewModel.kt (1)
core/ui/src/main/java/com/teamsolply/solply/ui/base/BaseViewModel.kt (1)
  • sendIntent (38-42)
feature/search/src/main/java/com/teamsolply/solply/search/SearchViewModel.kt (1)
core/ui/src/main/java/com/teamsolply/solply/ui/base/BaseViewModel.kt (1)
  • postSideEffect (48-52)
feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/favoriteTownNavigation/FavoriteTownNavigation.kt (1)
feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/FavoriteTownRoute.kt (1)
  • FavoriteTownRoute (37-115)
feature/search/src/main/java/com/teamsolply/solply/registerplace/navigation/RegisterPlaceNavigation.kt (2)
feature/main/src/main/java/com/teamsolply/solply/main/MainNavigator.kt (1)
  • navigate (42-82)
feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceScreen.kt (1)
  • RegisterPlaceRoute (66-140)
feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceViewModel.kt (3)
core/ui/src/main/java/com/teamsolply/solply/ui/base/BaseViewModel.kt (3)
  • reduce (44-46)
  • postSideEffect (48-52)
  • sendIntent (38-42)
domain/search/src/main/java/com/teamsolply/solply/search/repository/SearchRepository.kt (1)
  • searchAddress (10-10)
core/ui/src/main/java/com/teamsolply/solply/ui/util/PresignedUrlUploader.kt (1)
  • uploadToPresignedUrl (36-58)
feature/search/src/main/java/com/teamsolply/solply/search/navigation/SearchNavigation.kt (2)
feature/main/src/main/java/com/teamsolply/solply/main/MainNavigator.kt (1)
  • navigate (42-82)
feature/search/src/main/java/com/teamsolply/solply/search/SearchScreen.kt (1)
  • SearchScreen (45-221)
feature/place/src/main/java/com/teamsolply/solply/place/PlaceScreen.kt (1)
feature/main/src/main/java/com/teamsolply/solply/main/MainNavigator.kt (2)
  • navigateToFavoriteTown (167-169)
  • navigateToSearch (171-176)
feature/course/src/main/java/com/teamsolply/solply/course/CourseScreen.kt (1)
feature/main/src/main/java/com/teamsolply/solply/main/MainNavigator.kt (2)
  • navigateToFavoriteTown (167-169)
  • navigateToSearch (171-176)
feature/place/src/main/java/com/teamsolply/solply/place/PlaceViewModel.kt (1)
core/ui/src/main/java/com/teamsolply/solply/ui/base/BaseViewModel.kt (1)
  • postSideEffect (48-52)
feature/maps/src/main/java/com/teamsolply/solply/maps/component/dialog/ReportPlaceDialog.kt (1)
core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/card/RegisterPlaceImage.kt (1)
  • RegisterPlaceImage (33-112)
feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/FavoriteViewModel.kt (6)
core/ui/src/main/java/com/teamsolply/solply/ui/base/BaseViewModel.kt (2)
  • reduce (44-46)
  • postSideEffect (48-52)
data/course/src/main/java/com/teamsolply/solply/course/favoriteTown/repository/FavoriteTownRepositoryImpl.kt (1)
  • patchUserFavoriteTown (37-46)
remote/course/src/main/java/com/teamsolply/solply/course/favoriteTown/service/FavoriteTownService.kt (1)
  • patchUserFavoriteTown (14-17)
data/course/src/main/java/com/teamsolply/solply/course/favoriteTown/source/FavoriteTownRemoteDataSource.kt (1)
  • patchUserFavoriteTown (8-10)
remote/course/src/main/java/com/teamsolply/solply/course/favoriteTown/datasource/FavoriteTownRemoteDataSourceImpl.kt (1)
  • patchUserFavoriteTown (17-21)
domain/course/src/main/java/com/teamsolply/solply/course/favoriteTown/repository/FavoriteTownRepository.kt (1)
  • patchUserFavoriteTown (8-11)
feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/FavoriteTownRoute.kt (2)
feature/main/src/main/java/com/teamsolply/solply/main/MainNavigator.kt (1)
  • navigateToBack (116-118)
feature/course/src/main/java/com/teamsolply/solply/course/component/FavoriteTownTopBar.kt (1)
  • FavoriteTownTopBar (21-58)
feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceScreen.kt (6)
core/ui/src/main/java/com/teamsolply/solply/ui/lifecycle/LaunchedEffectWithLifecycle.kt (1)
  • LaunchedEffectWithLifecycle (11-24)
core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/textfield/SolplyTextField.kt (2)
  • SolplyRenameCourseTextField (304-330)
  • SolplyFixedReportTextField (332-406)
feature/search/src/main/java/com/teamsolply/solply/registerplace/component/RegisterPlaceItem.kt (1)
  • RegisterPlaceItem (13-40)
feature/search/src/main/java/com/teamsolply/solply/registerplace/component/PlaceTypeDropDown.kt (1)
  • PlaceTypeDropDown (22-95)
core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/card/RegisterPlaceImage.kt (1)
  • RegisterPlaceImage (33-112)
core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/button/SolplyButton.kt (1)
  • SolplyBasicButton (57-83)
feature/main/src/main/java/com/teamsolply/solply/main/MainScreen.kt (2)
feature/search/src/main/java/com/teamsolply/solply/search/navigation/SearchNavigation.kt (1)
  • searchNavGraph (16-30)
feature/search/src/main/java/com/teamsolply/solply/registerplace/navigation/RegisterPlaceNavigation.kt (1)
  • registerPlaceNavGraph (16-26)
feature/place/src/main/java/com/teamsolply/solply/place/navigation/PlaceNavigation.kt (1)
feature/place/src/main/java/com/teamsolply/solply/place/PlaceScreen.kt (1)
  • PlaceRoute (64-180)
๐Ÿ”‡ Additional comments (59)
feature/maps/src/main/java/com/teamsolply/solply/maps/component/bottomsheet/PlaceDetailBottomSheet.kt (2)

309-309: ํƒ€์ดํฌ๊ทธ๋ž˜ํ”ผ ํ‘œ์ค€ํ™” ๊ฐœ์„  ํ™•์ธ!

๋ช…์‹œ์ ์ธ lineHeight ์žฌ์ •์˜๋ฅผ ์ œ๊ฑฐํ•˜๊ณ  ๊ธฐ๋ณธ caption14R ์Šคํƒ€์ผ์„ ์‚ฌ์šฉํ•˜๋„๋ก ๋ณ€๊ฒฝํ•œ ๊ฒƒ์€ ์ข‹์€ ๊ฐœ์„ ์ž…๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๋””์ž์ธ ์‹œ์Šคํ…œ์˜ ์ผ๊ด€์„ฑ์ด ํ–ฅ์ƒ๋˜๊ณ  ํ–ฅํ›„ ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ์šฉ์ดํ•ด์ง‘๋‹ˆ๋‹ค.

Also applies to: 334-334, 359-359


439-439: ๊ฐ„๊ฒฉ ์กฐ์ • ํ™•์ธ!

ํ•˜๋‹จ ์—ฌ๋ฐฑ์„ 40.dp์—์„œ 49.dp๋กœ ์กฐ์ •ํ•œ ๊ฒƒ์€ ์‹œ๊ฐ์  ๊ท ํ˜•์„ ๊ฐœ์„ ํ•˜๊ธฐ ์œ„ํ•œ ์ ์ ˆํ•œ ๋ณ€๊ฒฝ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค.

feature/main/build.gradle.kts (1)

18-18: ์ˆœํ™˜ ์˜์กด์„ฑ ๊ฒ€์ฆ ์™„๋ฃŒ - ๋ฌธ์ œ ์—†์Œ

๊ฒ€์ฆ ๊ฒฐ๊ณผ, feature.search ๋ชจ๋“ˆ์ด ์ •์ƒ์ ์œผ๋กœ ์กด์žฌํ•˜๋ฉฐ feature.main๊ณผ์˜ ์ˆœํ™˜ ์˜์กด์„ฑ์ด ์—†๋Š” ๊ฒƒ์œผ๋กœ ํ™•์ธ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. feature.search๋Š” ๋„๋ฉ”์ธ ๋ชจ๋“ˆ(projects.domain.search, projects.domain.maps)์—๋งŒ ์˜์กดํ•˜๊ณ  ์žˆ์–ด ์˜์กด์„ฑ ๊ตฌ์กฐ๊ฐ€ ๋ช…ํ™•ํ•˜๊ณ  ์•ˆ์ „ํ•ฉ๋‹ˆ๋‹ค.

feature/search/build.gradle.kts (1)

11-13: ๋ชจ๋“  ์˜์กด์„ฑ์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ •์˜๋˜๊ณ  ์‚ฌ์šฉ ์ค‘์ž…๋‹ˆ๋‹ค.

๊ฒ€์ฆ ๊ฒฐ๊ณผ:

  • libs.lottie (v6.4.1), libs.lottie.compose: libs.versions.toml์— ์ •์˜๋จ
  • domain.maps: ๋ชจ๋“ˆ ์กด์žฌ ๋ฐ RegisterPlaceViewModel.kt์—์„œ MapsRepository, File, PresignedUrlsRequestEntity ์ž„ํฌํŠธ
  • libs.lottie.compose: RegisterPlaceScreen.kt์—์„œ LottieAnimation, LottieCompositionSpec, LottieConstants ๋“ฑ ์ž„ํฌํŠธ
  • ์ˆœํ™˜ ์˜์กด์„ฑ: ์—†์Œ (domain/maps๋Š” feature.search์— ์˜์กดํ•˜์ง€ ์•Š์Œ)

์ถ”๊ฐ€ ์กฐ์น˜ ํ•„์š” ์—†์Šต๋‹ˆ๋‹ค.

feature/place/src/main/java/com/teamsolply/solply/place/component/button/PlaceChipButton.kt (1)

50-50: ์•„์ด์ฝ˜ ๋ฆฌ์†Œ์Šค ๋ณ€๊ฒฝ์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์™„๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๊ฒ€์ฆ ๊ฒฐ๊ณผ ๋ชจ๋“  ํ•ญ๋ชฉ์ด ์ •์ƒ์ž…๋‹ˆ๋‹ค:

  • โœ… R.drawable.ic_arrow_down ๋ฆฌ์†Œ์Šค๊ฐ€ core/designsystem/src/main/res/drawable/ic_arrow_down.xml์— ์กด์žฌ
  • โœ… ๊ธฐ์กด ic_under_arrow ๋ฆฌ์†Œ์Šค ํŒŒ์ผ์ด ์ œ๊ฑฐ๋จ
  • โœ… ์ฝ”๋“œ๋ฒ ์ด์Šค ์ „์ฒด์—์„œ ic_under_arrow ์ฐธ์กฐ๊ฐ€ ์—†์Œ
  • โœ… PlaceChipButton.kt line 50์—์„œ ์ƒˆ๋กœ์šด ๋ฆฌ์†Œ์Šค๋ฅผ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์‚ฌ์šฉ ์ค‘

๋ณ€๊ฒฝ ์‚ฌํ•ญ์ด ๋ช…ํ™•ํ•˜๊ณ  ์•ˆ์ •์ ์ž…๋‹ˆ๋‹ค.

feature/search/src/main/java/com/teamsolply/solply/registerplace/component/RegisterPlaceItem.kt (1)

1-11: LGTM!

ํ•„์š”ํ•œ import๋“ค์ด ๋ชจ๋‘ ์ ์ ˆํ•˜๊ฒŒ ์„ ์–ธ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

core/ui/src/main/java/com/teamsolply/solply/ui/util/PresignedUrlUploader.kt (3)

13-19: LGTM!

ContentResolver ํ™•์žฅ ํ•จ์ˆ˜๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ตฌํ˜„๋˜์—ˆ์Šต๋‹ˆ๋‹ค. Cursor ๋ฆฌ์†Œ์Šค ๊ด€๋ฆฌ๊ฐ€ ์ ์ ˆํ•˜๊ณ , null safety๋„ ์ž˜ ์ฒ˜๋ฆฌ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.


21-34: LGTM!

FixedLenUriBody ๊ตฌํ˜„์ด ์˜ฌ๋ฐ”๋ฆ…๋‹ˆ๋‹ค. Presigned URL ์—…๋กœ๋“œ์— ํ•„์š”ํ•œ ๊ณ ์ • ๊ธธ์ด Content-Length ํ—ค๋”๋ฅผ ์ œ๊ณตํ•˜๋ฉฐ, InputStream ๋ฆฌ์†Œ์Šค๋„ ์ ์ ˆํžˆ ๊ด€๋ฆฌ๋˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.


1-1: ํŒจํ‚ค์ง€ ์ด๋™ ๋ฐ ์ฐธ์กฐ ์—…๋ฐ์ดํŠธ ์™„๋ฃŒ ํ™•์ธ๋จ

์Šคํฌ๋ฆฝํŠธ ๊ฒฐ๊ณผ ํ™•์ธ ๊ฒฐ๊ณผ, ํŒจํ‚ค์ง€ ๋ณ€๊ฒฝ์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๋ฐ˜์˜๋˜์—ˆ์Šต๋‹ˆ๋‹ค:

  • uploadToPresignedUrl ํ•จ์ˆ˜์˜ ๋ชจ๋“  import๊ฐ€ ์ƒˆ๋กœ์šด ํŒจํ‚ค์ง€ ๊ฒฝ๋กœ(com.teamsolply.solply.ui.util)๋กœ ์ •์ƒ ์—…๋ฐ์ดํŠธ๋จ
  • ๋‘ ํŒŒ์ผ(RegisterPlaceViewModel.kt, MapsViewModel.kt)์˜ import์™€ ํ•จ์ˆ˜ ํ˜ธ์ถœ ๋ชจ๋‘ ์ƒˆ๋กœ์šด ํŒจํ‚ค์ง€ ๊ฒฝ๋กœ ์‚ฌ์šฉ
  • ๊ธฐ์กด ํŒจํ‚ค์ง€ ๊ฒฝ๋กœ(com.teamsolply.solply.maps.util)์— ๋Œ€ํ•œ ์ฐธ์กฐ ์—†์Œ

ํŒจํ‚ค์ง€ ์ด๋™์ด ์™„๋ฒฝํ•˜๊ฒŒ ์™„๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

feature/maps/src/main/java/com/teamsolply/solply/maps/MapsViewModel.kt (1)

5-5: ์ž„ํฌํŠธ ๊ฒฝ๋กœ ๊ฒ€์ฆ ์™„๋ฃŒ - ์ˆ˜์ • ๋ถˆํ•„์š”

๊ฒ€์ฆ ๊ฒฐ๊ณผ, ๋‘ ํ•จ์ˆ˜ ๋ชจ๋‘ ์˜ˆ์ƒ๋œ ๊ฒฝ๋กœ์— ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค:

  • getFileName: core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/card/RegisterPlaceImage.kt (ํ™•์žฅ ํ•จ์ˆ˜)
  • uploadToPresignedUrl: core/ui/src/main/java/com/teamsolply/solply/ui/util/PresignedUrlUploader.kt

MapsViewModel.kt์˜ ์ž„ํฌํŠธ ๋ฌธ์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ž‘๋™ํ•˜๋ฉฐ, ํ•จ์ˆ˜๋“ค๋„ ์ •ํ™•ํ•˜๊ฒŒ ์‚ฌ์šฉ๋˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

feature/course/src/main/java/com/teamsolply/solply/course/component/FavoriteTownTopBar.kt (2)

29-29: ์ƒ๋‹จ ํŒจ๋”ฉ ์ฆ๊ฐ€ ํ™•์ธ

์ƒ๋‹จ ํŒจ๋”ฉ์ด 4.dp์—์„œ 16.dp๋กœ ์ฆ๊ฐ€ํ•˜์—ฌ ์‹œ๊ฐ์  ์—ฌ๋ฐฑ์ด ๊ฐœ์„ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. UI ๊ฐœ์„  ์‚ฌํ•ญ์œผ๋กœ ์ ์ ˆํ•ฉ๋‹ˆ๋‹ค.


42-42: ํƒ€์ดํ‹€ ํ…์ŠคํŠธ ๋ณ€๊ฒฝ ํ™•์ธ

"์ž์ฃผ ๊ฐ€๋Š” ๋™๋„ค"์—์„œ "๋™๋„ค ์„ค์ •"์œผ๋กœ ๋ณ€๊ฒฝ๋˜์–ด ์„ค์ • ํ™”๋ฉด์˜ ์˜๋„๊ฐ€ ๋” ๋ช…ํ™•ํ•ด์กŒ์Šต๋‹ˆ๋‹ค.

feature/main/src/main/AndroidManifest.xml (1)

9-9: ํ‚ค๋ณด๋“œ ์ž…๋ ฅ ๋ชจ๋“œ ์„ค์ • ์ถ”๊ฐ€ ํ™•์ธ

adjustResize ์„ค์ •์œผ๋กœ ํ‚ค๋ณด๋“œ๊ฐ€ ํ‘œ์‹œ๋  ๋•Œ ๋ ˆ์ด์•„์›ƒ์ด ์ ์ ˆํžˆ ์กฐ์ •๋ฉ๋‹ˆ๋‹ค. ์ž…๋ ฅ ํผ์ด ์žˆ๋Š” ํ™”๋ฉด์—์„œ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์„ ๊ฐœ์„ ํ•˜๋Š” ํ‘œ์ค€ ์„ค์ •์ž…๋‹ˆ๋‹ค.

core/model/src/main/java/com/teamsolply/solply/model/PlaceType.kt (1)

16-24: ALL ์ผ€์ด์Šค์˜ ID ๋งคํ•‘ ํ™•์ธ ํ•„์š”

PlaceType.ALL์€ when ํ‘œํ˜„์‹์— ๋ช…์‹œ์ ์œผ๋กœ ํฌํ•จ๋˜์ง€ ์•Š์•„ else ๋ถ„๊ธฐ๋กœ -1์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ALL์ด ๋ฉ”ํƒ€ ์นดํ…Œ๊ณ ๋ฆฌ๋กœ์„œ -1์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์ด ์˜๋„๋œ ๋™์ž‘์ด๋ผ๋ฉด ๋ฌธ์ œ์—†์ง€๋งŒ, ๋ช…์‹œ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋ฉด ์ฝ”๋“œ์˜ ์˜๋„๊ฐ€ ๋” ๋ช…ํ™•ํ•ด์ง‘๋‹ˆ๋‹ค.

๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ช…์‹œ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•ด๋ณด์„ธ์š”:

 fun PlaceType?.toId(): Long = when (this) {
     CAFE -> 1L
     FOOD -> 2L
     BOOKSTORE -> 3L
     WALKING -> 4L
     SHOPPING -> 5L
     UNIQUE_SPACE -> 6L
+    ALL -> -1L
-    else -> -1
+    null -> -1L
 }
core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/header/SolplyHomeHeader.kt (1)

27-27: ๊ฒ€์ƒ‰ ์ฝœ๋ฐฑ ์‹œ๊ทธ๋‹ˆ์ฒ˜ ๋‹จ์ˆœํ™” ํ™•์ธ

์ฝœ๋ฐฑ ํƒ€์ž…์ด (Boolean) -> Unit์—์„œ () -> Unit์œผ๋กœ ๋ณ€๊ฒฝ๋˜์–ด ํ˜ธ์ถœ๋ถ€๊ฐ€ ๋” ๊ฐ„๊ฒฐํ•ด์กŒ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๋‹ค์ด์–ผ๋กœ๊ทธ ๊ฐ€์‹œ์„ฑ ์ƒํƒœ๋ฅผ ๋กœ์ปฌ์—์„œ ๊ด€๋ฆฌํ•˜๋Š” ๋Œ€์‹  ๋„ค๋น„๊ฒŒ์ด์…˜ ๊ธฐ๋ฐ˜ ํ๋ฆ„์œผ๋กœ ์ „ํ™˜ํ•˜๋Š” ์ „์ฒด PR ๋ฐฉํ–ฅ๊ณผ ์ผ์น˜ํ•ฉ๋‹ˆ๋‹ค.

Also applies to: 79-79

feature/course/src/main/java/com/teamsolply/solply/course/CourseContract.kt (1)

53-58: ๋„ค๋น„๊ฒŒ์ด์…˜ ๊ธฐ๋ฐ˜ ์•„ํ‚คํ…์ฒ˜๋กœ์˜ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ํ™•์ธ

isSearchDialogVisible ์ƒํƒœ๋ฅผ ์ œ๊ฑฐํ•˜๊ณ  ๋ช…์‹œ์ ์ธ ๋„ค๋น„๊ฒŒ์ด์…˜ ์ธํ…ํŠธ(NavigateToFavoriteTown, NavigateToSearch)์™€ ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๋กœ ์ „ํ™˜ํ•œ ๊ฒƒ์€ ์ข‹์€ ์•„ํ‚คํ…์ฒ˜ ๊ฐœ์„ ์ž…๋‹ˆ๋‹ค. ์ด๋Š” ๊ด€์‹ฌ์‚ฌ์˜ ๋ถ„๋ฆฌ๋ฅผ ๊ฐœ์„ ํ•˜๊ณ  ๋„ค๋น„๊ฒŒ์ด์…˜ ๋กœ์ง์„ ๋” ๋ช…ํ™•ํ•˜๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

Also applies to: 67-71

data/search/src/main/java/com/teamsolply/solply/search/dto/response/RegisterPlaceResponseDto.kt (1)

1-12: ์ƒˆ๋กœ์šด DTO ์ •์˜ ํ™•์ธ

์žฅ์†Œ ๋“ฑ๋ก ์‘๋‹ต์„ ์œ„ํ•œ DTO๊ฐ€ ์ž˜ ์ •์˜๋˜์—ˆ์Šต๋‹ˆ๋‹ค. kotlinx.serialization ๊ทœ์น™์„ ๋”ฐ๋ฅด๊ณ  ์žˆ์œผ๋ฉฐ ํ”„๋กœ์ ํŠธ ๊ทœ์น™๊ณผ ์ผ์น˜ํ•ฉ๋‹ˆ๋‹ค.

feature/search/src/main/java/com/teamsolply/solply/search/SearchContract.kt (1)

23-27: ๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ ํ™•์žฅ ํ™•์ธ

์žฅ์†Œ ๋“ฑ๋ก(RegisterPlaceClick)๊ณผ ์žฅ์†Œ ์ƒ์„ธ ๋ณด๊ธฐ(PlaceDetailClick) ์ธํ…ํŠธ ๋ฐ ํ•ด๋‹น ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๊ฐ€ ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๊ฐ ์ธํ…ํŠธ-์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ ์Œ์ด ์ผ๊ด€์„ฑ ์žˆ๊ฒŒ ๊ตฌ์„ฑ๋˜์–ด ์žˆ์œผ๋ฉฐ, ํ•„์š”ํ•œ ์ปจํ…์ŠคํŠธ ์ •๋ณด(placeId, townId)๋ฅผ ์ ์ ˆํžˆ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.

Also applies to: 31-35

data/place/src/main/java/com/teamsolply/solply/place/dto/response/GetPlacesResponseDto.kt (1)

23-24: ๋ฐฑ์—”๋“œ API ํ•„๋“œ๋ช… ๋ณ€๊ฒฝ ํ™•์ธ ํ•„์š”

GetPlacesResponseDto์—์„œ @SerialName์ด "mainTag"๋กœ ๋ณ€๊ฒฝ๋˜์—ˆ์œผ๋‚˜, ๋‹ค๋ฅธ ๊ด€๋ จ DTO๋“ค(SearchResponseDto, PlaceListResponseDto, GetCourseDetailResponseDto ๋“ฑ)์€ ์—ฌ์ „ํžˆ "primaryTag"๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฐœ๋ฐœ์ž๊ฐ€ ๋‹ค์Œ์„ ํ™•์ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค:

  • ๋ฐฑ์—”๋“œ API์˜ GetPlaces ์—”๋“œํฌ์ธํŠธ๊ฐ€ ์‹ค์ œ๋กœ "mainTag" ํ•„๋“œ๋ช…์„ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ์—…๋ฐ์ดํŠธ๋˜์—ˆ๋Š”์ง€ ํ™•์ธ
  • ๋ณ€๊ฒฝ์ด ๋ถˆ์™„์ „ํ•˜๊ฑฐ๋‚˜ ๋‹ค๋ฅธ ์—”๋“œํฌ์ธํŠธ์™€ ๋ถˆ์ผ์น˜ํ•˜์ง€ ์•Š์€์ง€ ํ™•์ธ
  • ๋ฐฑ์—”๋“œ๊ฐ€ ์•„์ง "primaryTag"๋ฅผ ์‚ฌ์šฉ ์ค‘์ด๋ฉด ์—ญ์ง๋ ฌํ™” ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Œ
core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/textfield/SolplyTextField.kt (3)

67-67: ํ•„์ˆ˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์ธํ•œ ๋‚ด๋ถ€ API ๋ณ€๊ฒฝ

BaseTextField์— innerPadding: PaddingValues๊ฐ€ ํ•„์ˆ˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” private ํ•จ์ˆ˜์ด๋ฏ€๋กœ ์™ธ๋ถ€ API์—๋Š” ์˜ํ–ฅ์ด ์—†์ง€๋งŒ, ๋ชจ๋“  ํ˜ธ์ถœ ์ง€์ ์—์„œ ์ด ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์ œ๊ณตํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ณต๊ฐœ API์ธ SolplyNicknameTextField, SolplyRenameCourseTextField์—์„œ ์ ์ ˆํ•œ ๊ธฐ๋ณธ๊ฐ’์„ ์ œ๊ณตํ•˜๊ณ  ์žˆ์–ด ์ข‹์Šต๋‹ˆ๋‹ค.


336-337: ํฌ์ปค์Šค ์ฝœ๋ฐฑ ์ถ”๊ฐ€ ํ™•์ธ

SolplyFixedReportTextField์— onFocusChanged ์ฝœ๋ฐฑ์ด ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ํ‚ค๋ณด๋“œ๊ฐ€ ๋‚˜ํƒ€๋‚  ๋•Œ ์Šคํฌ๋กค ์ฒ˜๋ฆฌ ๋“ฑ์— ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. RegisterPlaceScreen.kt์—์„œ ์ด ์ฝœ๋ฐฑ์„ ์‚ฌ์šฉํ•˜์—ฌ bringIntoView๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์„ ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค.


351-353: ์‹œ๊ฐ์  ์ผ๊ด€์„ฑ ๊ฐœ์„ 

ํ…Œ๋‘๋ฆฌ ๋ฐ˜๊ฒฝ์ด 20.dp์—์„œ 16.dp๋กœ ๋ณ€๊ฒฝ๋˜๊ณ  ์ปจํ…Œ์ด๋„ˆ์— ๋ช…์‹œ์ ์ธ ํŒจ๋”ฉ์ด ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๋””์ž์ธ ์‹œ์Šคํ…œ์˜ ์ผ๊ด€์„ฑ์„ ์œ„ํ•œ ๊ฒƒ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค.

feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceScreen.kt (4)

192-205: ์ด๋ฏธ์ง€ ์„ ํƒ ๋กœ์ง ๊ฒ€์ฆ

์ด๋ฏธ์ง€ ํ”ผ์ปค ๋กœ์ง์ด ๋‚จ์€ ์Šฌ๋กฏ์„ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ฒ˜๋ฆฌํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. remainSelectedUris๊ฐ€ 2 ์ด์ƒ์ผ ๋•Œ ๋ฉ€ํ‹ฐ ํ”ผ์ปค๋ฅผ, 1์ผ ๋•Œ ์‹ฑ๊ธ€ ํ”ผ์ปค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ ์ ˆํ•ฉ๋‹ˆ๋‹ค.


463-463: ์ œ์ถœ ๋ฒ„ํŠผ ํ™œ์„ฑํ™” ์กฐ๊ฑด ํ™•์ธ

ํ•„์ˆ˜ ํ•„๋“œ ๊ฒ€์ฆ์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ตฌํ˜„๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค: placeName, selectedPlaceType, selectedPlaceKeyword, selectedPlaceFeature๊ฐ€ ๋ชจ๋‘ ๋น„์–ด์žˆ์ง€ ์•Š์„ ๋•Œ๋งŒ ๋ฒ„ํŠผ์ด ํ™œ์„ฑํ™”๋ฉ๋‹ˆ๋‹ค. registerPlaceReason๊ณผ selectedUris๋Š” ์„ ํƒ ์‚ฌํ•ญ์ด๋ฏ€๋กœ ๊ฒ€์ฆ์—์„œ ์ œ์™ธ๋œ ๊ฒƒ๋„ ์ ์ ˆํ•ฉ๋‹ˆ๋‹ค.


407-421: ํฌ์ปค์Šค ์ฒ˜๋ฆฌ ๊ฐœ์„ 

SolplyFixedReportTextField์—์„œ ํฌ์ปค์Šค ๋ณ€๊ฒฝ ์‹œ bringIntoViewRequester๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ‚ค๋ณด๋“œ๊ฐ€ ์ž…๋ ฅ ํ•„๋“œ๋ฅผ ๊ฐ€๋ฆฌ์ง€ ์•Š๋„๋ก ํ•˜๋Š” ์ฒ˜๋ฆฌ๊ฐ€ ์ž˜ ๊ตฌํ˜„๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. 200ms ์ง€์—ฐ์€ ํ‚ค๋ณด๋“œ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ๊ณ ๋ คํ•œ ๊ฒƒ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค.


177-190: ๋ฐฑ์—”๋“œ ID ์ผ์น˜ ์—ฌ๋ถ€๋Š” ์ฝ”๋“œ ๊ฒ€์ƒ‰์œผ๋กœ ํ™•์ธ ๋ถˆ๊ฐ€

์ฝ”๋“œ๋ฒ ์ด์Šค ์ „์ฒด ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ, ํ•˜๋“œ์ฝ”๋”ฉ๋œ ID(7L~16L)๋Š” RegisterPlaceScreen.kt ํŒŒ์ผ์—์„œ๋งŒ ์‚ฌ์šฉ ์ค‘์ž…๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ํŒŒ์ผ์—์„œ ์ฐธ์กฐ๋˜์ง€ ์•Š์œผ๋ฏ€๋กœ ์ฝ”๋“œ ๋‚ด ์ผ๊ด€์„ฑ ๋ฌธ์ œ๋Š” ์—†์Šต๋‹ˆ๋‹ค.

๋‹ค๋งŒ ์ด ID๋“ค์ด ์‹ค์ œ ๋ฐฑ์—”๋“œ์˜ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋˜๋Š” API์™€ ์ผ์น˜ํ•˜๋Š”์ง€๋Š” ์ฝ”๋“œ ๋ถ„์„๋งŒ์œผ๋กœ ๊ฒ€์ฆํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋ฐฑ์—”๋“œ API ๋ฌธ์„œ ๋˜๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์Šคํ‚ค๋งˆ์™€์˜ ๋™๊ธฐํ™” ์—ฌ๋ถ€๋ฅผ ์ˆ˜๋™์œผ๋กœ ํ™•์ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

data/place/src/main/java/com/teamsolply/solply/place/mapper/PlaceEntityMapper.kt (1)

11-11: ํ•„๋“œ ์ด๋ฆ„ ๋ณ€๊ฒฝ ๋ฐ˜์˜

DTO์˜ ํ•„๋“œ ์ด๋ฆ„ ๋ณ€๊ฒฝ(primaryTag โ†’ mainTag)์ด ๋งคํผ์— ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๋ฐ˜์˜๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” GetPlacesResponseDto.kt์™€ GetRecommendPlaceDto.kt์˜ ๋ณ€๊ฒฝ์‚ฌํ•ญ๊ณผ ์ผ๊ด€์„ฑ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

core/designsystem/src/main/res/drawable/ic_arrow_down_lg.xml (1)

7-11: ๋“œ๋กญ๋‹ค์šด ํ™”์‚ดํ‘œ ์•„์ด์ฝ˜ ์—…๋ฐ์ดํŠธ

์•„์ด์ฝ˜์˜ ๊ฒฝ๋กœ, ์„  ๋‘๊ป˜, ์ƒ‰์ƒ์ด ์—…๋ฐ์ดํŠธ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๋””์ž์ธ ์‹œ์Šคํ…œ ๊ฐœ์„ ์˜ ์ผํ™˜์œผ๋กœ ๋ณด์ด๋ฉฐ, SolplyBasicDropDown ์ปดํฌ๋„ŒํŠธ์—์„œ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

  • ์„  ๋‘๊ป˜: 1 โ†’ 1.5 (๊ฐ€๋…์„ฑ ํ–ฅ์ƒ)
  • ์ƒ‰์ƒ: #242424 โ†’ #4F4B4B (๋” ๋ฐ์€ ํšŒ์ƒ‰)
  • ๊ฒฝ๋กœ ์กฐ์ •์œผ๋กœ ํ™”์‚ดํ‘œ ํฌ๊ธฐ/์œ„์น˜ ๋ณ€๊ฒฝ
domain/search/src/main/java/com/teamsolply/solply/search/model/RegisterPlaceEntity.kt (1)

3-21: ์ž˜ ์„ค๊ณ„๋œ ๋„๋ฉ”์ธ ๋ชจ๋ธ

์žฅ์†Œ ๋“ฑ๋ก์„ ์œ„ํ•œ ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ๋“ค์ด ๋ช…ํ™•ํ•˜๊ฒŒ ์ •์˜๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค:

  • RegisterPlaceEntity: ํ•„์š”ํ•œ ๋ชจ๋“  ํ•„๋“œ ํฌํ•จ (์ด๋ฆ„, ์ฃผ์†Œ, ํƒœ๊ทธ, ์ด์œ , ์ด๋ฏธ์ง€)
  • PlaceImageEntity: ์ด๋ฏธ์ง€ ์ˆœ์„œ์™€ ์ž„์‹œ ํŒŒ์ผ ํ‚ค๋ฅผ ์ ์ ˆํžˆ ์บก์Аํ™”
  • RegisterPlaceResponseEntity: ์‘๋‹ต ๋ฐ์ดํ„ฐ ๊ตฌ์กฐํ™”

ํ•„๋“œ ํƒ€์ž…๊ณผ ์ด๋ฆ„์ด ๋ช…ํ™•ํ•˜๊ณ  ์ ์ ˆํ•ฉ๋‹ˆ๋‹ค.

feature/place/src/main/java/com/teamsolply/solply/place/PlaceViewModel.kt (2)

65-70: ์ฝ”๋“œ ํฌ๋งทํŒ… ๊ฐœ์„ 

PlaceClicked ์ธํ…ํŠธ ์ฒ˜๋ฆฌ๊ฐ€ ์—ฌ๋Ÿฌ ์ค„๋กœ ํฌ๋งท๋˜์–ด ๊ฐ€๋…์„ฑ์ด ํ–ฅ์ƒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋กœ์ง ๋ณ€๊ฒฝ์€ ์—†์Šต๋‹ˆ๋‹ค.


142-148: ๋„ค๋น„๊ฒŒ์ด์…˜ ํŒจํ„ด ๊ฐœ์„ 

๋Œ€ํ™”์ƒ์ž ํ‘œ์‹œ ์ƒํƒœ ํ† ๊ธ€(ChangeSearchDialogVisibility) ๋Œ€์‹  ๋ช…์‹œ์ ์ธ ๋„ค๋น„๊ฒŒ์ด์…˜ ์ธํ…ํŠธ(NavigateToSearch, NavigateToFavoriteTown)๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ๋ณ€๊ฒฝ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๋” ๋ช…ํ™•ํ•œ ๋„ค๋น„๊ฒŒ์ด์…˜ ํŒจํ„ด์ด๋ฉฐ Compose์˜ ๋‹จ๋ฐฉํ–ฅ ๋ฐ์ดํ„ฐ ํ๋ฆ„๊ณผ ์ž˜ ๋งž์Šต๋‹ˆ๋‹ค.

NavigateToFavoriteTown์ด selectedTownId๋ฅผ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ „๋‹ฌํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

data/place/src/main/java/com/teamsolply/solply/place/dto/response/GetRecommendPlaceDto.kt (1)

21-22: DTO ํ•„๋“œ ์ด๋ฆ„ ๋ณ€๊ฒฝ

primaryTag์—์„œ mainTag๋กœ ํ•„๋“œ ์ด๋ฆ„๊ณผ ์ง๋ ฌํ™” ์ด๋ฆ„์ด ๋ณ€๊ฒฝ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๋ฐฑ์—”๋“œ API ๋ณ€๊ฒฝ์‚ฌํ•ญ์„ ๋ฐ˜์˜ํ•˜๋ฉฐ, PR ์ „์ฒด์˜ ๋‹ค๋ฅธ ๋ณ€๊ฒฝ์‚ฌํ•ญ๋“ค(GetPlacesResponseDto, PlaceEntityMapper, PlaceRepositoryImpl)๊ณผ ์ผ๊ด€์„ฑ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

data/place/src/main/java/com/teamsolply/solply/place/repository/PlaceRepositoryImpl.kt (2)

83-83: DTO ํ•„๋“œ ์ฐธ์กฐ ์—…๋ฐ์ดํŠธ

getRecommendedPlace์˜ ๋งคํ•‘ ๋กœ์ง์ด it.primaryTag ๋Œ€์‹  it.mainTag๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ์—…๋ฐ์ดํŠธ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” GetRecommendPlaceDto์˜ ํ•„๋“œ ์ด๋ฆ„ ๋ณ€๊ฒฝ๊ณผ ์ผ์น˜ํ•ฉ๋‹ˆ๋‹ค.


108-108: DTO ํ•„๋“œ ์ฐธ์กฐ ์—…๋ฐ์ดํŠธ

getPlaces์˜ ๋งคํ•‘ ๋กœ์ง์ด dto.primaryTag ๋Œ€์‹  dto.mainTag๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ์—…๋ฐ์ดํŠธ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” GetPlacesResponseDto์˜ PlaceDto ํ•„๋“œ ์ด๋ฆ„ ๋ณ€๊ฒฝ๊ณผ ์ผ์น˜ํ•ฉ๋‹ˆ๋‹ค.

feature/search/src/main/java/com/teamsolply/solply/search/SearchViewModel.kt (1)

38-45: ์ƒˆ๋กœ์šด ๋„ค๋น„๊ฒŒ์ด์…˜ ์ธํ…ํŠธ ํ•ธ๋“ค๋ง์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ตฌํ˜„๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์žฅ์†Œ ๋“ฑ๋ก ๋ฐ ์ƒ์„ธ ํ™”๋ฉด์œผ๋กœ์˜ ๋„ค๋น„๊ฒŒ์ด์…˜์„ ์œ„ํ•œ ์ธํ…ํŠธ ์ฒ˜๋ฆฌ๊ฐ€ ๊ธฐ์กด ํŒจํ„ด์„ ์ž˜ ๋”ฐ๋ฅด๊ณ  ์žˆ์œผ๋ฉฐ, postSideEffect๋ฅผ ์ ์ ˆํžˆ ์‚ฌ์šฉํ•˜์—ฌ ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

feature/course/src/main/java/com/teamsolply/solply/course/CourseViewModel.kt (1)

43-49: ๋„ค๋น„๊ฒŒ์ด์…˜ ์ธํ…ํŠธ ์ฒ˜๋ฆฌ๊ฐ€ ์ž˜ ๊ตฌํ˜„๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์ฆ๊ฒจ์ฐพ๋Š” ๋™๋„ค์™€ ๊ฒ€์ƒ‰ ํ™”๋ฉด์œผ๋กœ์˜ ๋„ค๋น„๊ฒŒ์ด์…˜ ๋กœ์ง์ด ๋ช…ํ™•ํ•˜๊ฒŒ ๊ตฌํ˜„๋˜์–ด ์žˆ์œผ๋ฉฐ, ๊ธฐ์กด ์ฝ”๋“œ ์Šคํƒ€์ผ๊ณผ ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

remote/search/src/main/java/com/teamsolply/solply/search/service/SearchService.kt (1)

18-21: ์ƒˆ๋กœ์šด ์žฅ์†Œ ๋“ฑ๋ก ์š”์ฒญ ์—”๋“œํฌ์ธํŠธ๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ •์˜๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

Retrofit ์–ด๋…ธํ…Œ์ด์…˜์ด ์ ์ ˆํžˆ ์‚ฌ์šฉ๋˜์—ˆ์œผ๋ฉฐ, POST ์š”์ฒญ์˜ body์™€ ์‘๋‹ต ํƒ€์ž…์ด ๋ช…ํ™•ํ•˜๊ฒŒ ์ •์˜๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

core/common/src/main/java/com/teamsolply/solply/common/buildconfig/BuildConfigFields.kt (1)

7-8: Naver Developers API ์ธ์ฆ ์ •๋ณด ํ•„๋“œ๊ฐ€ ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

BuildConfig์— ์ƒˆ๋กœ์šด Naver ๊ฐœ๋ฐœ์ž ์ธ์ฆ ์ •๋ณด๊ฐ€ ์ถ”๊ฐ€๋˜์—ˆ์œผ๋ฉฐ, ๊ตฌํ˜„์ด ๋ช…ํ™•ํ•ฉ๋‹ˆ๋‹ค.

remote/search/src/main/java/com/teamsolply/solply/search/datasource/SearchRemoteDataSourceImpl.kt (1)

15-16: ์žฅ์†Œ ๋“ฑ๋ก ์š”์ฒญ ๋ฉ”์„œ๋“œ๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ตฌํ˜„๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๊ธฐ์กด getPlaceSearch์™€ ๋™์ผํ•œ ํŒจํ„ด์œผ๋กœ ์„œ๋น„์Šค๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ตฌ์กฐ๊ฐ€ ์ผ๊ด€์„ฑ ์žˆ๊ฒŒ ๊ตฌํ˜„๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

data/search/src/main/java/com/teamsolply/solply/search/source/SearchRemoteDataSource.kt (1)

9-9: ์ธํ„ฐํŽ˜์ด์Šค์— ์ƒˆ๋กœ์šด ์žฅ์†Œ ๋“ฑ๋ก ๋ฉ”์„œ๋“œ๊ฐ€ ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๋ฉ”์„œ๋“œ ์‹œ๊ทธ๋‹ˆ์ฒ˜๊ฐ€ ๋ช…ํ™•ํ•˜๋ฉฐ, ๊ตฌํ˜„์ฒด์™€ ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

data/maps/src/main/java/com/teamsolply/solply/maps/dto/response/PresignedUrlsResponseDto.kt (1)

8-8: ๋ฐฑ์—”๋“œ API ์‘๋‹ต ํ•„๋“œ๋ช… ๊ฒ€์ฆ ํ•„์š”

@SerialName ์–ด๋…ธํ…Œ์ด์…˜์ด "presignedUrlInfos"์—์„œ "presignedGetUrlInfos"๋กœ ๋ณ€๊ฒฝ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ณ€๊ฒฝ์‚ฌํ•ญ์ด ์‹ค์ œ ๋ฐฑ์—”๋“œ API ์‘๋‹ต๊ณผ ์ผ์น˜ํ•˜๋Š”์ง€ ํ™•์ธ์ด ํ•„์ˆ˜์ ์ž…๋‹ˆ๋‹ค.

  • ํ•„๋“œ๋ช… ๋ถˆ์ผ์น˜ ์‹œ: ์—ญ์ง๋ ฌํ™” ์‹คํŒจ ๋˜๋Š” presignedUrlInfos ์†์„ฑ์ด null๋กœ ์ฒ˜๋ฆฌ๋จ
  • ํ˜„์žฌ ์ฝ”๋“œ๋ฒ ์ด์Šค์—๋Š” API ์‘๋‹ต ์˜ˆ์ œ๋‚˜ ํ…Œ์ŠคํŠธ ํ”ฝ์Šค์ฒ˜๊ฐ€ ์—†์–ด ์ž๋™ ๊ฒ€์ฆ ๋ถˆ๊ฐ€๋Šฅ

ํ™•์ธ์‚ฌํ•ญ:

  • /files/presigned-urls ์—”๋“œํฌ์ธํŠธ๊ฐ€ ์‹ค์ œ๋กœ presignedGetUrlInfos ํ•„๋“œ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š”์ง€ ๋ฐฑ์—”๋“œ ํŒ€ ํ™•์ธ ๋˜๋Š” API ๋ฌธ์„œ ๊ฒ€์ฆ
  • ์‹ค์ œ API ์‘๋‹ต๊ณผ ์ผ์น˜ํ•˜์ง€ ์•Š์œผ๋ฉด ๋Ÿฐํƒ€์ž„์— ์˜ค๋ฅ˜ ๋ฐœ์ƒ ๊ฐ€๋Šฅ
feature/mypage/src/main/java/com/teamsolply/solply/mypage/component/SolplyPersonaDropDown.kt (1)

39-46: API ๋ณ€๊ฒฝ์— ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ ์‘ํ–ˆ์Šต๋‹ˆ๋‹ค.

defaultLabel์„ composable ๋žŒ๋‹ค๋กœ ๋ณ€๊ฒฝํ•œ ๊ฒƒ์ด SolplyBasicDropDown์˜ ์ƒˆ๋กœ์šด API์™€ ์ผ์น˜ํ•ฉ๋‹ˆ๋‹ค. ํ…์ŠคํŠธ ๋ Œ๋”๋ง๊ณผ ์Šคํƒ€์ผ๋ง์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ตฌํ˜„๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

data/search/src/main/java/com/teamsolply/solply/search/dto/response/SearchResponseDto.kt (1)

25-27: ํ•„๋“œ ์ถ”๊ฐ€๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ตฌํ˜„๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

townId ํ•„๋“œ๊ฐ€ ์ ์ ˆํ•œ ์ง๋ ฌํ™” ์–ด๋…ธํ…Œ์ด์…˜๊ณผ ํ•จ๊ป˜ ์ถ”๊ฐ€๋˜์—ˆ์œผ๋ฉฐ, ๊ธฐ์กด ์ฝ”๋“œ ํŒจํ„ด๊ณผ ์ผ์น˜ํ•ฉ๋‹ˆ๋‹ค.

remote/place/src/main/java/com/teamsolply/solply/place/datasource/PlaceRemoteDataSourceImpl.kt (1)

37-50: ํŒŒ๋ผ๋ฏธํ„ฐ ์ด๋ฆ„ ๋ณ€๊ฒฝ์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ ์šฉ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

subTag1Ids์™€ subTag2Ids๋กœ์˜ ์ด๋ฆ„ ๋ณ€๊ฒฝ์ด PlaceService API์™€ ์ผ์น˜ํ•˜๋ฉฐ, ๊ธฐ์กด ๋กœ์ง(์‰ผํ‘œ๋กœ ๊ตฌ๋ถ„๋œ ๋ฌธ์ž์—ด ์ƒ์„ฑ)์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์œ ์ง€๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/dropdown/SolplyBasicDropDown.kt (2)

34-68: API ๋ณ€๊ฒฝ์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ตฌํ˜„๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

defaultLabel์„ composable ๋žŒ๋‹ค๋กœ ๋ณ€๊ฒฝํ•œ ๊ฒƒ์€ ๋” ์œ ์—ฐํ•œ ๋ผ๋ฒจ ์ปค์Šคํ„ฐ๋งˆ์ด์ง•์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค. PR ๋‚ด์˜ ๋ชจ๋“  ์‚ฌ์šฉ์ฒ˜๊ฐ€ ์ƒˆ๋กœ์šด API์— ๋งž๊ฒŒ ์—…๋ฐ์ดํŠธ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.


89-90: ์• ๋‹ˆ๋ฉ”์ด์…˜ API๊ฐ€ ์ ์ ˆํ•˜๊ฒŒ ์—…๋ฐ์ดํŠธ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

expandVertically/shrinkVertically๋กœ์˜ ๋ณ€๊ฒฝ์ด ๋“œ๋กญ๋‹ค์šด์˜ ํ™•์žฅ/์ถ•์†Œ ๋™์ž‘์— ๋” ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค.

feature/maps/src/main/java/com/teamsolply/solply/maps/component/dialog/ReportPlaceDialog.kt (2)

55-56: ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ์„ฑ ๊ฐœ์„ 

ReportPlaceImage๋ฅผ ์ œ๊ฑฐํ•˜๊ณ  ๊ณต์œ  ์ปดํฌ๋„ŒํŠธ์ธ RegisterPlaceImage๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ๋ฆฌํŒฉํ† ๋งํ•œ ๊ฒƒ์€ ์ข‹์€ ๋ณ€๊ฒฝ์ž…๋‹ˆ๋‹ค. ์ฝ”๋“œ ์ค‘๋ณต์ด ์ œ๊ฑฐ๋˜๊ณ  ์œ ์ง€๋ณด์ˆ˜์„ฑ์ด ํ–ฅ์ƒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

Also applies to: 322-322


228-248: ํŒจ๋”ฉ ๋ณ€๊ฒฝ ํ™•์ธ ํ•„์š”

ReportTypesScreen์˜ ํŒจ๋”ฉ์ด horizontal์—์„œ vertical๋กœ ๋ณ€๊ฒฝ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ณ€๊ฒฝ์ด ์˜๋„๋œ ๊ฒƒ์ด๋ฉฐ UI๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ํ‘œ์‹œ๋˜๋Š”์ง€ ํ™•์ธํ•ด์ฃผ์„ธ์š”.

feature/search/src/main/java/com/teamsolply/solply/search/navigation/SearchNavigation.kt (1)

1-33: ํƒ€์ž… ์•ˆ์ „ ๋„ค๋น„๊ฒŒ์ด์…˜ ๊ตฌํ˜„ ์–‘ํ˜ธ

Jetpack Compose์˜ ํƒ€์ž… ์•ˆ์ „ ๋„ค๋น„๊ฒŒ์ด์…˜์„ ์ž˜ ํ™œ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. @serializable์„ ์‚ฌ์šฉํ•œ ๋ผ์šฐํŠธ ์ •์˜์™€ ๋ช…ํ™•ํ•œ ์ฝœ๋ฐฑ ๊ตฌ์กฐ๊ฐ€ ์ข‹์Šต๋‹ˆ๋‹ค.

core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/card/RegisterPlaceImage.kt (2)

34-112: ์ด๋ฏธ์ง€ ์„ ํƒ ์ปดํฌ๋„ŒํŠธ ๊ตฌํ˜„ ์–‘ํ˜ธ

3๊ฐœ์˜ ์ด๋ฏธ์ง€ ์Šฌ๋กฏ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋กœ์ง์ด ๋ช…ํ™•ํ•˜๊ณ , ๊ฐ ์ƒํƒœ(์„ ํƒ๋จ/์ถ”๊ฐ€ ๋ฒ„ํŠผ/๋นˆ ์Šฌ๋กฏ)๋ฅผ ์ ์ ˆํžˆ ์ฒ˜๋ฆฌํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.


115-128: getFileName ๊ตฌํ˜„ ํ™•์ธ

ํŒŒ์ผ๋ช… ์ถ”์ถœ ๋กœ์ง์ด ์ ์ ˆํ•œ ํด๋ฐฑ ์ฒด์ธ์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค๋งŒ MIME ํƒ€์ž…์„ ํ™•์ธํ•  ์ˆ˜ ์—†์„ ๋•Œ "jpg"๋ฅผ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š”๋ฐ, ์‹ค์ œ ์ด๋ฏธ์ง€ ํƒ€์ž…๊ณผ ์ผ์น˜ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฐฑ์—”๋“œ์—์„œ ํŒŒ์ผ ํ™•์žฅ์ž๋ฅผ ๊ฒ€์ฆํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ๋ฌธ์ œ์—†์ง€๋งŒ, ํ™•์ธํ•ด๋ณด์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค.

domain/search/src/main/java/com/teamsolply/solply/search/repository/SearchRepository.kt (1)

3-11: ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ์ธํ„ฐํŽ˜์ด์Šค ํ™•์žฅ ์ ์ ˆํ•จ

์ƒˆ๋กœ์šด ๋ฉ”์„œ๋“œ๊ฐ€ ๊ธฐ์กด ํŒจํ„ด(suspend + Result wrapper)์„ ๋”ฐ๋ฅด๊ณ  ์žˆ์œผ๋ฉฐ, ๋ช…ํ™•ํ•œ ๋„ค์ด๋ฐ๊ณผ ํƒ€์ž… ์‹œ๊ทธ๋‹ˆ์ฒ˜๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

domain/search/src/main/java/com/teamsolply/solply/search/model/SearchResultEntity.kt (1)

11-12: townId ํ•„๋“œ ์ถ”๊ฐ€ ๊ฒ€์ฆ ์™„๋ฃŒ - ๋ฌธ์ œ ์—†์Œ

SearchResultEntity์˜ townId ํ•„๋“œ ์ถ”๊ฐ€๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ตฌํ˜„๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

  • SearchRepositoryImpl.kt (lines 24-32)์˜ ์œ ์ผํ•œ ์ธ์Šคํ„ด์Šคํ™” ์ง€์ ์—์„œ ๋ชจ๋“  ํ•„๋“œ(placeId, placeName, thumbnailImageUrl, primaryTag, address, isBookmarked, townId)๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ œ๊ณต๋˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
  • townId๋Š” ์†Œ์Šค ๊ฐ์ฒด์—์„œ searchResult.townId๋กœ ์ •ํ™•ํžˆ ๋งคํ•‘๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
  • ๋‹ค๋ฅธ ์ธ์Šคํ„ด์Šคํ™” ์ง€์ ์ด ์—†์œผ๋ฏ€๋กœ ๋ชจ๋“  ์ƒ์„ฑ ์‚ฌ์ดํŠธ๊ฐ€ ์—…๋ฐ์ดํŠธ๋œ ์ƒํƒœ์ž…๋‹ˆ๋‹ค.
feature/course/src/main/java/com/teamsolply/solply/course/navigation/CourseNavigation.kt (1)

18-30: courseNavGraph ์‹œ๊ทธ๋‹ˆ์ฒ˜ ๋ณ€๊ฒฝ ๊ฒ€์ฆ ์™„๋ฃŒ - ๋ฌธ์ œ ์—†์Œ

courseNavGraph ํ˜ธ์ถœ ์ง€์ ์„ ๊ฒ€์ฆํ•œ ๊ฒฐ๊ณผ, ์œ ์ผํ•œ ํ˜ธ์ถœ ์ง€์ ์ธ MainScreen.kt (205-220์ค„)์ด ์ƒˆ๋กœ์šด ์‹œ๊ทธ๋‹ˆ์ฒ˜์— ๋งž๊ฒŒ ์™„๋ฒฝํ•˜๊ฒŒ ์—…๋ฐ์ดํŠธ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. 4๊ฐœ ํŒŒ๋ผ๋ฏธํ„ฐ(paddingValues, navigateToFavoriteTown, navigateToSearch, navigateToMaps)๊ฐ€ ๋ชจ๋‘ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ „๋‹ฌ๋˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

feature/main/src/main/java/com/teamsolply/solply/main/MainScreen.kt (5)

49-51: LGTM!

์ƒˆ๋กœ์šด ๊ฒ€์ƒ‰ ๋ฐ ์žฅ์†Œ ๋“ฑ๋ก ๊ธฐ๋Šฅ์„ ์œ„ํ•œ import๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค.


414-417: LGTM!

์žฅ์†Œ ๋“ฑ๋ก ๋„ค๋น„๊ฒŒ์ด์…˜์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ตฌํ˜„๋˜์—ˆ์œผ๋ฉฐ, ์ œ๊ณต๋œ RegisterPlaceNavigation.kt์˜ ์‹œ๊ทธ๋‹ˆ์ฒ˜์™€ ์ผ์น˜ํ•ฉ๋‹ˆ๋‹ค.


207-210: ๊ฒ€์ฆ ์™„๋ฃŒ: courseNavGraph ์‹œ๊ทธ๋‹ˆ์ฒ˜๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์—…๋ฐ์ดํŠธ๋จ

courseNavGraph ํ•จ์ˆ˜๊ฐ€ navigateToFavoriteTown: (Long) -> Unit๊ณผ navigateToSearch: () -> Unit ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ •ํ™•ํ•˜๊ฒŒ ์—…๋ฐ์ดํŠธ๋˜์—ˆ์œผ๋ฉฐ, MainScreen.kt์˜ ์ฝœ๋ฐฑ ์‚ฌ์šฉ๊ณผ ์ผ์น˜ํ•ฉ๋‹ˆ๋‹ค. placeNavGraph์™€ ์ผ๊ด€์„ฑ ์žˆ๊ฒŒ ๊ตฌํ˜„๋˜์—ˆ์Šต๋‹ˆ๋‹ค.


387-391: ์ฆ๊ฒจ์ฐพ๋Š” ๋งˆ์„ back ๋„ค๋น„๊ฒŒ์ด์…˜์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ตฌํ˜„๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๊ฒ€์ฆ ๊ฒฐ๊ณผ:

  • favoriteTownNavGraph ํ•จ์ˆ˜ ์‹œ๊ทธ๋‹ˆ์ฒ˜ ํ™•์ธ๋จ: navigateToBack: (Long?) -> Unit
  • MainNavigator.navigateFavoriteTownToMain(selectedTownId: Long?) ๋ฉ”์„œ๋“œ ํ™•์ธ๋จ (MainNavigator.kt:120-125)
  • MainScreen.kt (387-391)์˜ ์ฝœ๋ฐฑ ๊ตฌํ˜„์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์ „๋‹ฌํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์„ ํƒ๋œ ๋งˆ์„ ID๊ฐ€ savedStateHandle์— ์ €์žฅ๋˜๊ณ  ์ด์ „ ์Šคํƒ์œผ๋กœ ๋Œ์•„๊ฐ€๋Š” ํ”Œ๋กœ์šฐ๊ฐ€ ์ •์ƒ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

191-194: ๊ฒ€์ฆ ์™„๋ฃŒ: ๋„ค๋น„๊ฒŒ์ด์…˜ ๊ตฌํ˜„์ด ์˜ฌ๋ฐ”๋ฆ…๋‹ˆ๋‹ค.

placeNavGraph ํ•จ์ˆ˜ ์‹œ๊ทธ๋‹ˆ์ฒ˜์™€ ์ „๋‹ฌ๋˜๋Š” ์ฝœ๋ฐฑ์ด ๋ชจ๋‘ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ตฌํ˜„๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

  • placeNavGraph ์‹œ๊ทธ๋‹ˆ์ฒ˜ (PlaceNavigation.kt:18-19):

    • navigateToFavoriteTown: (Long) -> Unit โœ“
    • navigateToSearch: () -> Unit โœ“
  • MainNavigator ๋ฉ”์„œ๋“œ ๋ชจ๋‘ ์กด์žฌ:

    • navigateToFavoriteTown(navOptions: NavOptions = navOptions {}, selectedTownId: Long) โœ“
    • navigateToSearch() โœ“
  • ํƒ€์ž… ํ˜ธํ™˜์„ฑ:

    • { selectedTownId -> navigator.navigateToFavoriteTown(selectedTownId = selectedTownId) } โ†’ (Long) -> Unit โœ“
    • navigator::navigateToSearch โ†’ () -> Unit โœ“

๋ชจ๋“  ํƒ€์ž…์ด ์ผ์น˜ํ•˜๊ณ  ๋ฉ”์„œ๋“œ ์ฐธ์กฐ๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.

Comment on lines +27 to +36
buildConfigField(
"String",
"NAVER_DEVELOPERS_CLIENT_ID",
gradleLocalProperties(rootDir, providers).getProperty("naver.developers.client.id")
)
buildConfigField(
"String",
"NAVER_DEVELOPERS_CLIENT_SECRET",
gradleLocalProperties(rootDir, providers).getProperty("naver.developers.client.secret")
)
Copy link

Choose a reason for hiding this comment

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

โš ๏ธ Potential issue | ๐Ÿ”ด Critical

๋ณด์•ˆ ์ทจ์•ฝ์ : ๋ฏผ๊ฐํ•œ ์ •๋ณด๊ฐ€ APK์— ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.

NAVER_DEVELOPERS_CLIENT_SECRET๊ณผ ๊ฐ™์€ ๋ฏผ๊ฐํ•œ ์ •๋ณด๋ฅผ BuildConfig์— ์ €์žฅํ•˜๋ฉด APK ๋””์ปดํŒŒ์ผ์„ ํ†ตํ•ด ์‰ฝ๊ฒŒ ์ถ”์ถœ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ถŒ์žฅ ์‚ฌํ•ญ:

  • ํด๋ผ์ด์–ธํŠธ ์‹œํฌ๋ฆฟ์€ ๋ฐฑ์—”๋“œ ์„œ๋ฒ„์—์„œ ๊ด€๋ฆฌํ•˜๊ณ , ์•ฑ์€ ๋ฐฑ์—”๋“œ๋ฅผ ํ†ตํ•ด Naver API๋ฅผ ํ˜ธ์ถœ
  • ๋˜๋Š” Android Keystore์™€ NDK obfuscation์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ณดํ˜ธ
  • BuildConfig๋Š” ๊ณต๊ฐœ๋˜์–ด๋„ ๋ฌด๋ฐฉํ•œ ์ •๋ณด๋งŒ ์ €์žฅ

๊ด€๋ จ ๋ฌธ์„œ ํ™•์ธ์„ ์œ„ํ•œ ์›น ๊ฒ€์ƒ‰:

Android BuildConfig security best practices for API secrets

Comment on lines +18 to +19
naverDevelopersClientId = NAVER_DEVELOPERS_CLIENT_ID,
naverDevelopersClientSecret = NAVER_DEVELOPERS_CLIENT_SECRET,
Copy link

Choose a reason for hiding this comment

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

โš ๏ธ Potential issue | ๐Ÿ”ด Critical

๋ณด์•ˆ ์ฃผ์˜: ๋ฏผ๊ฐํ•œ ์ •๋ณด ์ฒ˜๋ฆฌ

์ด ์ฝ”๋“œ๋Š” BuildConfig.kt์—์„œ ์ถ”๊ฐ€๋œ Naver ๊ฐœ๋ฐœ์ž ์ธ์ฆ ์ •๋ณด๋ฅผ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์—ฐ๊ฒฐํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ BuildConfig.kt์—์„œ ์ง€์ ํ•œ ๋ณด์•ˆ ๋ฌธ์ œ๊ฐ€ ์—ฌ๊ธฐ์—๋„ ์ ์šฉ๋ฉ๋‹ˆ๋‹ค. ์‹œํฌ๋ฆฟ ์ •๋ณด๋Š” APK์— ํฌํ•จ๋˜์ง€ ์•Š๋„๋ก ๋ฐฑ์—”๋“œ์—์„œ ๊ด€๋ฆฌ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿค– Prompt for AI Agents
In
core/buildconfig/src/main/java/com/teamsolply/solply/buildconfig/impl/BuildConfigFieldsProviderImpl.kt
around lines 18-19, the Naver client ID/secret are being wired into the app
build config which embeds sensitive credentials into the APK; remove these
secret assignments from the client build config, stop shipping
NAVER_DEVELOPERS_CLIENT_ID and NAVER_DEVELOPERS_CLIENT_SECRET in the app, and
instead fetch any required credentials from a secure backend at runtime (or use
a secure token exchange flow). Update callers to request tokens or ephemeral
credentials from the backend rather than reading BuildConfig values, and ensure
secrets are stored only in server-side environment variables/secret manager and
not committed to source or included in the APK.

Comment on lines +50 to +54
.addInterceptor(loggingInterceptor.apply {
level = HttpLoggingInterceptor.Level.HEADERS
})
.addInterceptor(naverApiInterceptor)
.connectTimeout(30, TimeUnit.SECONDS)
Copy link

Choose a reason for hiding this comment

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

โš ๏ธ Potential issue | ๐Ÿ”ด Critical

ํ—ค๋” ๋กœ๊น…์œผ๋กœ ๋น„๋ฐ€ ํ‚ค๊ฐ€ ๋…ธ์ถœ๋ฉ๋‹ˆ๋‹ค.
HttpLoggingInterceptor๋ฅผ HEADERS ๋ ˆ๋ฒจ๋กœ ๊ฐ•์ œํ•˜๋ฉด์„œ X-Naver-Client-Secret๊นŒ์ง€ ๋กœ๊ทธ์— ๋‚จ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ด ๋ชจ๋“ˆ์ด ๋ฆด๋ฆฌ์Šค ๋นŒ๋“œ์—์„œ๋„ ๋™์ผํ•˜๊ฒŒ ์‹คํ–‰๋˜๋ฉด, ์šด์˜ ๋กœ๊ทธ์— ํด๋ผ์ด์–ธํŠธ ์‹œํฌ๋ฆฟ์ด ํ‰๋ฌธ์œผ๋กœ ๊ธฐ๋ก๋˜์–ด ์‹ฌ๊ฐํ•œ ๋ณด์•ˆ ์‚ฌ๊ณ ๋กœ ์ด์–ด์ง‘๋‹ˆ๋‹ค. ๋นŒ๋“œ ํ™˜๊ฒฝ์— ๋งž์ถฐ ์„ค์ •๋œ ๊ธฐ์กด ๋กœ๊น… ๋ ˆ๋ฒจ์„ ์กด์ค‘ํ•˜๊ณ , ํ•ด๋‹น ํ—ค๋” ๊ฐ’์€ ๋ฐ˜๋“œ์‹œ ๋งˆ์Šคํ‚นํ•˜์„ธ์š”.

-        .addInterceptor(loggingInterceptor.apply {
-            level = HttpLoggingInterceptor.Level.HEADERS
-        })
+        .addInterceptor(
+            loggingInterceptor.also {
+                it.redactHeader("X-Naver-Client-Id")
+                it.redactHeader("X-Naver-Client-Secret")
+            }
+        )
๐Ÿ“ 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
.addInterceptor(loggingInterceptor.apply {
level = HttpLoggingInterceptor.Level.HEADERS
})
.addInterceptor(naverApiInterceptor)
.connectTimeout(30, TimeUnit.SECONDS)
.addInterceptor(
loggingInterceptor.also {
it.redactHeader("X-Naver-Client-Id")
it.redactHeader("X-Naver-Client-Secret")
}
)
.addInterceptor(naverApiInterceptor)
.connectTimeout(30, TimeUnit.SECONDS)
๐Ÿค– Prompt for AI Agents
In core/network/src/main/java/com/teamsolply/solply/network/di/NaverApiModule.kt
around lines 50 to 54, the HttpLoggingInterceptor is forced to HEADERS which
will log sensitive header X-Naver-Client-Secret; change the setup to (1) respect
the current build/environment logging level instead of forcing HEADERS (e.g.,
use a configured or debug-only level), and (2) explicitly redact/mask the
X-Naver-Client-Secret header on the interceptor so its value never appears in
logs; ensure the interceptor configuration uses the existing environment/build
flag and adds header redaction for that header.

Comment on lines +25 to +30
data class PlaceImageDto(
@SerialName("displayOrder")
val displayOrder: Long,
@SerialName("tempFileKey")
val tempFileKey: String
) No newline at end of file
Copy link

Choose a reason for hiding this comment

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

โš ๏ธ Potential issue | ๐Ÿ”ด Critical

๐Ÿงฉ Analysis chain

displayOrder ํƒ€์ž… ๊ฒ€์ฆ ํ•„์š”

displayOrder๊ฐ€ Long ํƒ€์ž…์œผ๋กœ ์„ ์–ธ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ํ‘œ์‹œ ์ˆœ์„œ๋Š” ์ž‘์€ ์ •์ˆ˜๊ฐ’(Int)์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋ฐฑ์—”๋“œ API ์ŠคํŽ™๊ณผ ์ผ์น˜ํ•˜๋Š”์ง€ ํ™•์ธํ•ด์ฃผ์„ธ์š”.

API ๋ฌธ์„œ๋ฅผ ํ™•์ธํ•˜๊ฑฐ๋‚˜ ๋‹ค์Œ์„ ํ†ตํ•ด ๋ฐฑ์—”๋“œ ๊ณ„์•ฝ์„ ๊ฒ€์ฆํ•˜์„ธ์š”:


๐ŸŒ Web query:

Does the backend API for place registration expect displayOrder as Long or Int type?

๐Ÿ’ก Result:

Which backend/API are you asking about? (e.g., Google Places API, your company's service, a specific OpenAPI/Swagger URL or repo). I can then look up the schema and confirm whether displayOrder is Long or Int.


๋ฐฑ์—”๋“œ API๋ฅผ ํŠน์ •ํ•˜๊ธฐ ์œ„ํ•ด ์ฝ”๋“œ๋ฒ ์ด์Šค๋ฅผ ๋ถ„์„ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

์ฝ”๋“œ๋ฒ ์ด์Šค์—์„œ ๋ฐฑ์—”๋“œ API ์ŠคํŽ™์„ ์ฐพ๊ธฐ ์œ„ํ•ด ๊ตฌ์ฒด์ ์œผ๋กœ ๊ฒ€์ƒ‰ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.


---

๐Ÿ Script executed:

```shell
#!/bin/bash
# ์ฝ”๋“œ๋ฒ ์ด์Šค์—์„œ displayOrder ์ •์˜ ์ฐพ๊ธฐ
echo "=== displayOrder ์ •์˜ ๊ฒ€์ƒ‰ ===" 
rg -n "displayOrder" -C3

echo -e "\n=== OpenAPI/Swagger ํŒŒ์ผ ๊ฒ€์ƒ‰ ==="
find . -type f \( -name "*.yaml" -o -name "*.yml" -o -name "*.json" \) | grep -i -E "(openapi|swagger|api|spec)" | head -20

echo -e "\n=== API ์‘๋‹ต DTO ๊ฒ€์ƒ‰ ==="
fd -e kt | xargs grep -l "Response\|Response\|dto" | head -20

Length of output: 8029


ํƒ€์ž… ๋ถˆ์ผ์น˜๊ฐ€ ๋ฐœ๊ฒฌ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ถ”๊ฐ€ ๊ฒ€์ฆ์„ ์œ„ํ•ด ์ €์žฅ์†Œ ์ฝ”๋“œ๋ฅผ ํ™•์ธํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.


---

๐Ÿ Script executed:

```shell
#!/bin/bash
# SearchRepositoryImpl์—์„œ PlaceImageDto ๋งคํ•‘ ์ฝ”๋“œ ํ™•์ธ
echo "=== SearchRepositoryImpl์˜ PlaceImageDto ๋งคํ•‘ ์ฝ”๋“œ ==="
cat data/search/src/main/java/com/teamsolply/solply/search/repository/SearchRepositoryImpl.kt | sed -n '60,80p'

# ๋‹ค๋ฅธ PlaceImageDto ์‚ฌ์šฉ ์œ„์น˜ ํ™•์ธ
echo -e "\n=== PlaceImageDto ์‚ฌ์šฉ ์œ„์น˜ ==="
rg -n "PlaceImageDto" -C2

# ๋ฐฑ์—”๋“œ ์‘๋‹ต DTO์™€์˜ ๋น„๊ต
echo -e "\n=== ๋ฐฑ์—”๋“œ ์‘๋‹ต DTO์˜ displayOrder ํƒ€์ž… ==="
grep -r "displayOrder" data/maps/src/main/java/com/teamsolply/solply/maps/dto/response/ -A1 -B1

Length of output: 4074


displayOrder ํƒ€์ž… ๋ถˆ์ผ์น˜ ์ˆ˜์ • ํ•„์š”

๊ฒ€์ฆ ๊ฒฐ๊ณผ, displayOrder์˜ ํƒ€์ž…์ด ์š”์ฒญ๊ณผ ์‘๋‹ต ๊ฐ„์— ์ผ์น˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋ฐฑ์—”๋“œ ์‘๋‹ต DTO(GetPlaceDetailResponseDto.kt ๋ผ์ธ 55)๋Š” displayOrder๋ฅผ Int ํƒ€์ž…์œผ๋กœ ์ •์˜ํ•˜๊ณ  ์žˆ์ง€๋งŒ, ์š”์ฒญ DTO(RegisterPlaceRequestDto.kt ๋ผ์ธ 27)์—์„œ๋Š” Long ํƒ€์ž…์œผ๋กœ ์ •์˜๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” API ์ง๋ ฌํ™”/์—ญ์ง๋ ฌํ™” ์‹œ ํƒ€์ž… ๋ถˆ์ผ์น˜ ์˜ค๋ฅ˜๋ฅผ ์•ผ๊ธฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ˆ˜์ •์‚ฌํ•ญ:

  • data/search/src/main/java/com/teamsolply/solply/search/dto/request/RegisterPlaceRequestDto.kt ๋ผ์ธ 27: displayOrder: Long โ†’ displayOrder: Int ๋ณ€๊ฒฝ
  • domain/search/src/main/java/com/teamsolply/solply/search/model/RegisterPlaceEntity.kt ๋ผ์ธ 14: displayOrder: Long โ†’ displayOrder: Int ๋ณ€๊ฒฝ
  • feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceViewModel.kt ๋ผ์ธ 213: .toLong() ์ œ๊ฑฐ ํ›„ ์ •์ˆ˜ ์ธ๋ฑ์Šค ์‚ฌ์šฉ
๐Ÿค– Prompt for AI Agents
In
data/search/src/main/java/com/teamsolply/solply/search/dto/request/RegisterPlaceRequestDto.kt
around lines 25-30, change the PlaceImageDto.displayOrder type from Long to Int
to match the backend response; in
domain/search/src/main/java/com/teamsolply/solply/search/model/RegisterPlaceEntity.kt
around line 14 change the entity's displayOrder from Long to Int; in
feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceViewModel.kt
around line 213 remove the .toLong() conversion and pass/use an Int index
instead so all layers use Int for displayOrder and avoid serialization/type
mismatches.

Comment on lines +3 to +13
data class NaverLocalSearchResponseEntity(
val title: String,
val link: String,
val category: String,
val description: String,
val telephone: String,
val address: String,
val roadAddress: String,
val mapx: String,
val mapy: String
) No newline at end of file
Copy link

Choose a reason for hiding this comment

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

โš ๏ธ Potential issue | ๐Ÿ”ด Critical

๐Ÿงฉ Analysis chain

Naver API๊ฐ€ null ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”.

๋ชจ๋“  ํ•„๋“œ๊ฐ€ non-nullable String์œผ๋กœ ์„ ์–ธ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. API๊ฐ€ ์ผ๋ถ€ ํ•„๋“œ์— ๋Œ€ํ•ด null์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒฝ์šฐ ์—ญ์ง๋ ฌํ™” ์‹คํŒจ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ ์Šคํฌ๋ฆฝํŠธ๋กœ DTO ๋งคํ•‘์„ ํ™•์ธํ•˜์„ธ์š”:


๐Ÿ Script executed:

#!/bin/bash
# Naver API DTO์™€ Entity ๊ฐ„์˜ ๋งคํ•‘ ํ™•์ธ
rg -A 10 "NaverLocalSearchResponseDto" --type kotlin

Length of output: 2901



---

๐Ÿ Script executed:

```shell
#!/bin/bash
# ์ „์ฒด LocalSearchItem ์ •์˜ ํ™•์ธ
rg -A 20 "^data class LocalSearchItem" --type kotlin

Length of output: 1287


๐Ÿ Script executed:

#!/bin/bash
# NaverLocalSearchResponseEntity์™€์˜ ๋งคํ•‘ ๋กœ์ง ํ™•์ธ
rg -B 5 -A 10 "NaverLocalSearchResponseEntity" --type kotlin

Length of output: 11512


๐Ÿ Script executed:

#!/bin/bash
# @Serializable ๋˜๋Š” nullable ๊ด€๋ จ ์„ค์ • ํ™•์ธ
rg -B 3 -A 15 "LocalSearchItem" core/network/src/main/java/com/teamsolply/solply/network/model/NaverLocalSearchResponseDto.kt

Length of output: 369



---

๐ŸŒ Web query:

```web
Naver Local Search API response fields nullable optional telephone address

๐Ÿ’ก Result:

Short answer: telephone is effectively not returned (itโ€™s a legacy/empty element); address and roadAddress are the fields you should rely on (they appear when available). The official Local Search docs state telephone is โ€œan element that does not return a value (kept for backward compatibility)โ€ and show telephone empty in the response; address, roadAddress, mapx and mapy are the provided location fields. [1]

Source:

  • Naver Developers โ€” Search API: Local (response field descriptions and example). [1]

Naver API ๊ณ„์•ฝ ๋ถˆ์ผ์น˜๋กœ ์ธํ•œ ์—ญ์ง๋ ฌํ™” ์‹คํŒจ ์œ„ํ—˜

Naver Local Search API ๋ฌธ์„œ์— ๋”ฐ๋ฅด๋ฉด telephone ํ•„๋“œ๋Š” ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š์œผ๋ฉฐ(ํ•˜์œ„ ํ˜ธํ™˜์„ฑ ์œ ์ง€๋ฅผ ์œ„ํ•ด ์œ ์ง€), address์™€ roadAddress๋Š” ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•  ๋•Œ๋งŒ ์ œ๊ณต๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ํ˜„์žฌ ์ฝ”๋“œ์˜ LocalSearchItem DTO์™€ NaverLocalSearchResponseEntity ์—”ํ‹ฐํ‹ฐ๋Š” ๋ชจ๋“  ํ•„๋“œ(ํŠนํžˆ telephone)๋ฅผ non-nullable String์œผ๋กœ ์ •์˜ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋กœ ์ธํ•ด API ์‘๋‹ต์ด null ๊ฐ’์„ ํฌํ•จํ•˜๊ฑฐ๋‚˜ ํ•„๋“œ๋ฅผ ์ƒ๋žตํ•  ๊ฒฝ์šฐ Kotlinx Serialization ์—ญ์ง๋ ฌํ™”๊ฐ€ ์‹คํŒจํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

core/network/src/main/java/com/teamsolply/solply/network/model/NaverLocalSearchResponseDto.kt์˜ LocalSearchItem๊ณผ domain/search/src/main/java/com/teamsolply/solply/search/model/NaverLocalSearchResponseEntity.kt์˜ ํ•„๋“œ๋ฅผ nullable(String?)๋กœ ๋ณ€๊ฒฝํ•˜๊ฑฐ๋‚˜ Kotlinx Serialization์˜ ๊ธฐ๋ณธ๊ฐ’/์„ ํƒ์  ํ•„๋“œ ์ฒ˜๋ฆฌ๋ฅผ ์ถ”๊ฐ€ํ•˜์„ธ์š”.

๐Ÿค– Prompt for AI Agents
In
domain/search/src/main/java/com/teamsolply/solply/search/model/NaverLocalSearchResponseEntity.kt
around lines 3 to 13, the entity defines all fields as non-nullable Strings
which will break kotlinx.serialization deserialization when the Naver API omits
or returns null for fields like telephone, address, or roadAddress; change the
fields that may be absent (at minimum telephone, address, roadAddress) to
nullable types (String?) or provide explicit default values and update any
@Serializable settings so missing fields are tolerated, and mirror the same
nullable/default changes in
core/network/src/main/java/com/teamsolply/solply/network/model/NaverLocalSearchResponseDto.kt
LocalSearchItem so DTO-to-entity mapping handles nulls safely (e.g., map null to
empty string or keep nulls as appropriate).

imageKeys = tempKeys
)
).onSuccess {
).onSuccess { error ->
Copy link

Choose a reason for hiding this comment

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

โš ๏ธ Potential issue | ๐Ÿ”ด Critical

์„ฑ๊ณต ์ฝœ๋ฐฑ์—์„œ ์ž˜๋ชป๋œ ํŒŒ๋ผ๋ฏธํ„ฐ ์ด๋ฆ„ ์‚ฌ์šฉ

Line 566์—์„œ onSuccess ์ฝœ๋ฐฑ์˜ ํŒŒ๋ผ๋ฏธํ„ฐ ์ด๋ฆ„์ด error๋กœ ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ์˜๋ฏธ์ƒ ์ž˜๋ชป๋˜์—ˆ์œผ๋ฉฐ, ์„ฑ๊ณต ์‹œ ๋ฐ˜ํ™˜๋˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ์ด๋ฆ„์„ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ _๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ diff๋ฅผ ์ ์šฉํ•˜์—ฌ ์ˆ˜์ •ํ•˜์„ธ์š”:

-                    ).onSuccess { error ->
+                    ).onSuccess {
                         android.util.Log.d("PresignedUrl", "โœ… ์‹ ๊ณ  ์™„๋ฃŒ!")
                         delay(2500)
                         sendIntent(MapsIntent.ChangeReportPlaceDialogVisibility(visible = false))
๐Ÿ“ 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
).onSuccess { error ->
).onSuccess {
android.util.Log.d("PresignedUrl", "โœ… ์‹ ๊ณ  ์™„๋ฃŒ!")
delay(2500)
sendIntent(MapsIntent.ChangeReportPlaceDialogVisibility(visible = false))
๐Ÿค– Prompt for AI Agents
In feature/maps/src/main/java/com/teamsolply/solply/maps/MapsViewModel.kt around
line 566, the onSuccess callback parameter is incorrectly named "error"; rename
it to a meaningful success name (e.g., "result" or "data") if the returned value
is used, or replace it with "_" if unused, and update any references inside the
callback accordingly to reflect the new name.

dependencies {
implementation(projects.domain.place)
implementation(projects.feature.search)
implementation(projects.feature.course)
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

์˜์กด์„ฑ ์ถ”๊ฐ€ - course ๊ธฐ๋Šฅ ๋ชจ๋“ˆ ์—ฐ๊ฒฐ ํ™•์ธ ํ•„์š”

์ƒˆ๋กœ์šด projects.feature.course ์˜์กด์„ฑ์ด ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค. AI ์š”์•ฝ์— ๋”ฐ๋ฅด๋ฉด place ๋ชจ๋“ˆ์ด course ๊ด€๋ จ UI/๋„ค๋น„๊ฒŒ์ด์…˜ ์ปดํฌ๋„ŒํŠธ์— ์ ‘๊ทผํ•˜๊ธฐ ์œ„ํ•œ ๊ฒƒ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค. ์˜์กด์„ฑ ์ˆœ์„œ์™€ ๊ตฌ์กฐ๋Š” ์ ์ ˆํ•ด ๋ณด์ž…๋‹ˆ๋‹ค.

๋‹ค๋งŒ, ๋‹ค์Œ ์‚ฌํ•ญ์„ ํ™•์ธํ•ด์ฃผ์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค:

  • ์‹ค์ œ๋กœ place ๊ธฐ๋Šฅ ์ฝ”๋“œ์—์„œ course ๋ชจ๋“ˆ์˜ ์ปดํฌ๋„ŒํŠธ/ํด๋ž˜์Šค๊ฐ€ ์‚ฌ์šฉ๋˜๊ณ  ์žˆ๋Š”์ง€ ํ™•์ธ
  • ์ˆœํ™˜ ์˜์กด์„ฑ์ด ์—†๋Š”์ง€ ๊ฒ€์ฆ (feature.course โ†’ feature.place ์—ญ์ฐธ์กฐ ํ™•์ธ)

์ œ์•ˆ: ์•„๋ž˜ ์Šคํฌ๋ฆฝํŠธ๋กœ ์‹ค์ œ ์‚ฌ์šฉ ์—ฌ๋ถ€๋ฅผ ๊ฒ€์ฆํ•˜์„ธ์š”:


๐Ÿ Script executed:

#!/bin/bash
# course ๋ชจ๋“ˆ ์ปดํฌ๋„ŒํŠธ๊ฐ€ place ๊ธฐ๋Šฅ ์ฝ”๋“œ์—์„œ ์‚ฌ์šฉ๋˜๋Š”์ง€ ํ™•์ธ

# Place ๋ชจ๋“ˆ ๋‚ด์—์„œ course ๊ด€๋ จ ์ž„ํฌํŠธ ๊ฒ€์ƒ‰
find feature/place -type f -name "*.kt" -o -name "*.java" | xargs grep -l "import.*course" 2>/dev/null || echo "course ๊ด€๋ จ ์ž„ํฌํŠธ ์—†์Œ"

# Course ๋ชจ๋“ˆ์ด place๋ฅผ ์—ญ์ฐธ์กฐํ•˜์ง€ ์•Š๋Š”์ง€ ํ™•์ธ (์ˆœํ™˜ ์˜์กด์„ฑ ์ฒดํฌ)
if grep -r "feature.place" feature/course/build.gradle.kts 2>/dev/null; then
  echo "๊ฒฝ๊ณ : course ๋ชจ๋“ˆ์ด place๋ฅผ ์ฐธ์กฐํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค (์ˆœํ™˜ ์˜์กด์„ฑ ์œ„ํ—˜)"
else
  echo "โœ“ ์ˆœํ™˜ ์˜์กด์„ฑ ์—†์Œ"
fi

Length of output: 28


๋ฏธ์‚ฌ์šฉ ์˜์กด์„ฑ ์ œ๊ฑฐ ํ•„์š”

projects.feature.course ์˜์กด์„ฑ์ด ์ถ”๊ฐ€๋˜์—ˆ์œผ๋‚˜, ๊ฒ€์ฆ ๊ฒฐ๊ณผ place ๋ชจ๋“ˆ ๋‚ด ์–ด๋””์„œ๋„ course ๊ด€๋ จ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ž„ํฌํŠธ/์‚ฌ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋ถˆํ•„์š”ํ•œ ์˜์กด์„ฑ์€ ์ œ๊ฑฐํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

line 12์˜ implementation(projects.feature.course) ๋ผ์ธ์„ ์‚ญ์ œํ•˜์„ธ์š”.

๐Ÿค– Prompt for AI Agents
feature/place/build.gradle.kts around line 12: remove the unused dependency line
`implementation(projects.feature.course)` (delete line 12) and then refresh/sync
the Gradle project or run a build to confirm there are no missing imports or
compilation issues.

Comment on lines +97 to +107
fun getPlaceTypeIconResId(item: PlaceType): Int {
return when (item) {
PlaceType.ALL -> R.drawable.ic_caffe
PlaceType.CAFE -> R.drawable.ic_caffe
PlaceType.FOOD -> R.drawable.ic_food
PlaceType.BOOKSTORE -> R.drawable.ic_book
PlaceType.WALKING -> R.drawable.ic_walk
PlaceType.SHOPPING -> R.drawable.ic_shopping
PlaceType.UNIQUE_SPACE -> R.drawable.ic_unique
}
} No newline at end of file
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

์ค‘๋ณต๋œ ์•„์ด์ฝ˜ ๋งคํ•‘์„ ํ™•์ธํ•˜์„ธ์š”.

PlaceType.ALL๊ณผ PlaceType.CAFE๊ฐ€ ๋ชจ๋‘ R.drawable.ic_caffe๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค(๋ผ์ธ 99-100). ์ด๊ฒƒ์ด ์˜๋„๋œ ๊ฒƒ์ธ์ง€ ํ™•์ธ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ALL์€ ๋ณ„๋„์˜ ์•„์ด์ฝ˜(์˜ˆ: ์ „์ฒด ๋ชฉ๋ก ์•„์ด์ฝ˜)์„ ๊ฐ€์ ธ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿค– Prompt for AI Agents
In
feature/search/src/main/java/com/teamsolply/solply/registerplace/component/PlaceTypeDropDown.kt
around lines 97-107, the mapping returns R.drawable.ic_caffe for both
PlaceType.ALL and PlaceType.CAFE which appears unintended; change the
PlaceType.ALL branch to return a distinct "all" icon (e.g., R.drawable.ic_all or
R.drawable.ic_all_categories), or if that drawable does not exist add a new
drawable resource for the "all" state and update the mapping accordingly so ALL
and CAFE use different icons.

Comment on lines +196 to +217
val infos = response.presignedUrlInfos
val uris = uiState.value.selectedReportUris
val byName = uris.associateBy { resolver.getFileName(it) }

// 2. S3์— ํŒŒ์ผ ์—…๋กœ๋“œ
val result = runCatching {
coroutineScope {
infos.mapIndexed { index, info ->
val uri = byName[info.originalFileName]
?: error("URI for ${info.originalFileName} not found")
async {
uploadToPresignedUrl(
context = context,
uri = uri,
presignedUrl = info.presignedUrl
)
PlaceImageEntity(
displayOrder = (index + 1).toLong(),
tempFileKey = info.tempFileKey
)
}
}.awaitAll()
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

๋™์ผ ํŒŒ์ผ๋ช… ์„ ํƒ ์‹œ ์ž˜๋ชป๋œ ์‚ฌ์ง„์ด ์—…๋กœ๋“œ๋ฉ๋‹ˆ๋‹ค.
์—ฌ๊ธฐ์„œ๋Š” associateBy๋กœ ํŒŒ์ผ๋ช…์„ ํ‚ค๋กœ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š”๋ฐ, ์‚ฌ์šฉ์ž๊ฐ€ ๋™์ผํ•œ ์ด๋ฆ„์˜ ์ด๋ฏธ์ง€๋ฅผ ๋‘ ์žฅ ์„ ํƒํ•˜๋ฉด ๋งˆ์ง€๋ง‰ URI๋งŒ ๋‚จ๊ณ  ์•ž์„  URI๋Š” ๋ฎ์–ด์จ์ง‘๋‹ˆ๋‹ค. ๊ทธ ๊ฒฐ๊ณผ ์„œ๋กœ ๋‹ค๋ฅธ presigned URL์— ๋™์ผํ•œ ์ด๋ฏธ์ง€๊ฐ€ ์ „์†ก๋˜์–ด ์ž˜๋ชป๋œ ์ฒจ๋ถ€๊ฐ€ ์„œ๋ฒ„์— ์ €์žฅ๋ฉ๋‹ˆ๋‹ค. ๊ฐ ํŒŒ์ผ๋ช…์„ ํ๋กœ ๊ด€๋ฆฌํ•ด ์ค‘๋ณต ์ด๋ฆ„๋„ ์ˆœ์„œ๋Œ€๋กœ ์†Œ์ง„ํ•˜๋„๋ก ๋ฐ”๊ฟ”์ฃผ์„ธ์š”.

-import kotlinx.coroutines.async
+import kotlinx.coroutines.async
 import kotlinx.coroutines.awaitAll
 import kotlinx.coroutines.coroutineScope
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.launch
+import kotlin.collections.ArrayDeque
 ...
-                val infos = response.presignedUrlInfos
-                val uris = uiState.value.selectedReportUris
-                val byName = uris.associateBy { resolver.getFileName(it) }
+                val infos = response.presignedUrlInfos
+                val groupedUris = uiState.value.selectedReportUris
+                    .groupBy { resolver.getFileName(it) }
+                    .mapValues { ArrayDeque(it.value) }
 ...
-                        infos.mapIndexed { index, info ->
-                            val uri = byName[info.originalFileName]
-                                ?: error("URI for ${info.originalFileName} not found")
+                        infos.mapIndexed { index, info ->
+                            val uri = groupedUris[info.originalFileName]?.removeFirstOrNull()
+                                ?: error("URI for ${info.originalFileName} not found")
๐Ÿค– Prompt for AI Agents
In
feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceViewModel.kt
around lines 196 to 217, using associateBy(on selectedReportUris) drops
duplicates by filename causing wrong images to be uploaded when filenames
repeat; replace associateBy with a grouping that produces mutable queues/lists
(e.g., groupBy { resolver.getFileName(it) } and convert each value to a
MutableList) and when iterating infos pop/remove the first element from the
corresponding list for info.originalFileName (or throw a clear error if the list
is empty) so duplicate names are consumed in order and each presigned URL gets
the intended URI.

Comment on lines +32 to +33
@Query("subTag1Ids") subTag1Ids: String?,
@Query("subTag2Ids") subTag2Ids: String?
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

์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ ์ด๋ฆ„ ๋ณ€๊ฒฝ์— ๋Œ€ํ•œ ์ „์ฒด ์ฝ”๋“œ๋ฒ ์ด์Šค ๊ฒ€์ฆ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

subTagAIdList/subTagBIdList์—์„œ subTag1Ids/subTag2Ids๋กœ ํŒŒ๋ผ๋ฏธํ„ฐ๋ช…์ด ๋ณ€๊ฒฝ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๋ชจ๋“  ์ฝ”๋“œ๊ฐ€ ์ƒˆ๋กœ์šด ํŒŒ๋ผ๋ฏธํ„ฐ๋ช…์œผ๋กœ ์—…๋ฐ์ดํŠธ๋˜์—ˆ๋Š”์ง€ ํ™•์ธ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ ์Šคํฌ๋ฆฝํŠธ๋กœ getPlaces ๋ฉ”์„œ๋“œ์˜ ๋ชจ๋“  ํ˜ธ์ถœ ์œ„์น˜๋ฅผ ํ™•์ธํ•˜์„ธ์š”:


๐Ÿ Script executed:

#!/bin/bash
# PlaceService.getPlaces ํ˜ธ์ถœ ์œ„์น˜ ๋ฐ ํŒŒ๋ผ๋ฏธํ„ฐ ์‚ฌ์šฉ ํ™•์ธ
rg -n "\.getPlaces\(" --type kotlin -A 5 -B 2

# ํ˜น์‹œ ๋‚จ์•„์žˆ๋Š” ์ด์ „ ํŒŒ๋ผ๋ฏธํ„ฐ๋ช… ํ™•์ธ
rg -n "subTagAIdList|subTagBIdList" --type kotlin

Length of output: 5966


๋„ค ๊ฐœ์˜ ํŒŒ์ผ์—์„œ ํŒŒ๋ผ๋ฏธํ„ฐ ์ด๋ฆ„์„ ์ƒˆ๋กœ์šด ๊ทœ์น™์œผ๋กœ ์—…๋ฐ์ดํŠธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

PlaceService.kt์˜ ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ subTag1Ids/subTag2Ids๋กœ ๋ณ€๊ฒฝํ–ˆ์œผ๋‚˜, ํ˜ธ์ถœ ๊ณ„์ธต์˜ ํŒŒ๋ผ๋ฏธํ„ฐ ์ด๋ฆ„์€ ์—ฌ์ „ํžˆ subTagAIdList/subTagBIdList๋กœ ์œ ์ง€๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. PlaceRemoteDataSourceImpl์—์„œ๋งŒ ๋ณ€ํ™˜ ๋กœ์ง์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๊ณ  ์žˆ์–ด ์ผ๊ด€์„ฑ์ด ๋ถ€์กฑํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ ํŒŒ์ผ๋“ค์˜ ํŒŒ๋ผ๋ฏธํ„ฐ ์ด๋ฆ„์„ ์—…๋ฐ์ดํŠธํ•˜์„ธ์š”:

  • data/place/src/main/java/com/teamsolply/solply/place/source/PlaceRemoteDataSource.kt (lines 16-17): ์ธํ„ฐํŽ˜์ด์Šค ํŒŒ๋ผ๋ฏธํ„ฐ๋ช…
  • remote/place/src/main/java/com/teamsolply/solply/place/datasource/PlaceRemoteDataSourceImpl.kt (lines 30-31): ๊ตฌํ˜„์ฒด ํŒŒ๋ผ๋ฏธํ„ฐ๋ช…
  • data/place/src/main/java/com/teamsolply/solply/place/repository/PlaceRepositoryImpl.kt (lines 92-93, 99-100): ๋ฉ”์„œ๋“œ ํŒŒ๋ผ๋ฏธํ„ฐ๋ช… ๋ฐ ํ˜ธ์ถœ๋ถ€
  • domain/place/src/main/java/com/teamsolply/solply/place/repository/PlaceRepository.kt (lines 18-19): ์ธํ„ฐํŽ˜์ด์Šค ํŒŒ๋ผ๋ฏธํ„ฐ๋ช…
  • feature/place/src/main/java/com/teamsolply/solply/place/PlaceViewModel.kt (lines 233-234, 240-241): ๋ฉ”์„œ๋“œ ํŒŒ๋ผ๋ฏธํ„ฐ๋ช… ๋ฐ ํ˜ธ์ถœ๋ถ€
๐Ÿค– Prompt for AI Agents
In
remote/place/src/main/java/com/teamsolply/solply/place/service/PlaceService.kt
around lines 32-33 and across the call chain, parameter names were changed to
subTag1Ids/subTag2Ids but upstream layers still use subTagAIdList/subTagBIdList;
update all signatures and call sites to use the new names to keep consistency:
change the parameter names in
data/place/src/main/java/com/teamsolply/solply/place/source/PlaceRemoteDataSource.kt
(lines 16-17),
remote/place/src/main/java/com/teamsolply/solply/place/datasource/PlaceRemoteDataSourceImpl.kt
(lines 30-31),
domain/place/src/main/java/com/teamsolply/solply/place/repository/PlaceRepository.kt
(lines 18-19),
data/place/src/main/java/com/teamsolply/solply/place/repository/PlaceRepositoryImpl.kt
(lines 92-93 and 99-100) and
feature/place/src/main/java/com/teamsolply/solply/place/PlaceViewModel.kt (lines
233-234 and 240-241) by renaming parameters and updating any corresponding
method calls and variable names to subTag1Ids and subTag2Ids (or mediate
nullability/format conversions where previously handled in
PlaceRemoteDataSourceImpl), then run a build to fix all compile errors.

@leeseokchan00 leeseokchan00 merged commit c3911fe into develop Nov 17, 2025
1 check passed
@leeseokchan00 leeseokchan00 deleted the refactor/#144-first-qa branch November 17, 2025 08:07
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: 12

Caution

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

โš ๏ธ Outside diff range comments (2)
core/ui/src/main/java/com/teamsolply/solply/ui/util/PresignedUrlUploader.kt (1)

36-58: OkHttpClient ์žฌ์‚ฌ์šฉ ๋ฐ ํƒ€์ž„์•„์›ƒ ๊ตฌ์„ฑ ํ•„์š”

์ด ํ•จ์ˆ˜๋Š” ํ•ญ์ƒ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ฝ”๋ฃจํ‹ด(async ๋ธ”๋ก ๋‚ด)์—์„œ ํ˜ธ์ถœ๋˜๋ฏ€๋กœ ANR ์œ„ํ—˜์€ ์—†์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋‹ค์Œ ๋‘ ๊ฐ€์ง€ ์ฃผ์š” ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค:

  1. Line 52: ๋งค ํ˜ธ์ถœ๋งˆ๋‹ค ์ƒˆ๋กœ์šด OkHttpClient() ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ์ฝ”๋“œ๋ฒ ์ด์Šค์˜ ๋‹ค๋ฅธ ๋„คํŠธ์›Œํฌ ํด๋ผ์ด์–ธํŠธ๋Š” ๋ชจ๋‘ DI๋ฅผ ํ†ตํ•ด ์‹ฑ๊ธ€ํ†ค ์ธ์Šคํ„ด์Šค๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๋ฏ€๋กœ ํŒจํ„ด ๋ถˆ์ผ์น˜์ž…๋‹ˆ๋‹ค.

  2. ํƒ€์ž„์•„์›ƒ ๋ฏธ์„ค์ •: NetworkModule ๋ฐ NaverApiModule์˜ ๋ชจ๋“  OkHttpClient ์ธ์Šคํ„ด์Šค๋Š” connectTimeout(30, SECONDS), readTimeout(30, SECONDS), writeTimeout(30, SECONDS)๋ฅผ ์„ค์ •ํ•˜์ง€๋งŒ, ์ด ํ•จ์ˆ˜์˜ ํด๋ผ์ด์–ธํŠธ๋Š” ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

ํ•„์ˆ˜ ์ˆ˜์ •:

  • OkHttpClient๋ฅผ ์‹ฑ๊ธ€ํ†ค์œผ๋กœ ์ฃผ์ž…๋ฐ›๊ฑฐ๋‚˜ DI ํŒจํ„ด์— ๋งž๋„๋ก ๋ฆฌํŒฉํ† ๋ง
  • ํƒ€์ž„์•„์›ƒ ๊ตฌ์„ฑ ์ถ”๊ฐ€ (๊ธฐ์กด ๋„คํŠธ์›Œํฌ ํด๋ผ์ด์–ธํŠธ์™€ ๋™์ผํ•œ 30์ดˆ)
feature/course/src/main/java/com/teamsolply/solply/course/CourseViewModel.kt (1)

26-33: ์ฃผ์„ ์ฒ˜๋ฆฌ๋œ ์ฝ”๋“œ๋ฅผ ์ œ๊ฑฐํ•˜๊ฑฐ๋‚˜ TODO ์ถ”๊ฐ€๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

LoadSuccess ์ธํ…ํŠธ ๋‚ด๋ถ€์˜ ์ฃผ์„ ์ฒ˜๋ฆฌ๋œ ์ฝ”๋“œ๋Š” ๋” ์ด์ƒ ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š” ๊ฒƒ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค. ๋งŒ์•ฝ ํ–ฅํ›„ ์‚ฌ์šฉํ•  ๊ณ„ํš์ด๋ผ๋ฉด TODO ์ฃผ์„์„ ์ถ”๊ฐ€ํ•˜๊ณ , ๊ทธ๋ ‡์ง€ ์•Š๋‹ค๋ฉด ์ฝ”๋“œ๋ฅผ ์ œ๊ฑฐํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

 is CourseIntent.LoadSuccess -> {
-//                reduce {
-//                    copy(
-//                        user = intent.user,
-//                        courseList = intent.courses
-//                    )
-//                }
+    // TODO: Implement LoadSuccess handling or remove this intent if not needed
 }
๐Ÿงน Nitpick comments (19)
feature/search/src/main/java/com/teamsolply/solply/registerplace/component/RegisterPlaceItem.kt (1)

20-27: ์ ‘๊ทผ์„ฑ ๊ฐœ์„ ์„ ๊ณ ๋ คํ•ด์ฃผ์„ธ์š”.

ํด๋ฆญ ๊ฐ€๋Šฅํ•œ ํ•ญ๋ชฉ์ด์ง€๋งŒ ์Šคํฌ๋ฆฐ ๋ฆฌ๋”๋ฅผ ์œ„ํ•œ ๋ช…์‹œ์ ์ธ ์˜๋ฏธ ์ •๋ณด๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๋” ๋‚˜์€ ์ ‘๊ทผ์„ฑ์„ ์œ„ํ•ด semantics ๋ธ”๋ก์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ฐœ์„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

     Column(
         modifier = modifier
             .fillMaxWidth()
             .padding(horizontal = 20.dp, vertical = 16.dp)
+            .semantics(mergeDescendants = true) {
+                contentDescription = "$placeName, $placeAddress"
+            }
             .customClickable(rippleEnabled = false) {
                 onClick(placeName, placeAddress)
             }
     ) {
feature/maps/src/main/java/com/teamsolply/solply/maps/MapsViewModel.kt (1)

517-517: ๊ตฌ์กฐํ™”๋œ ๋กœ๊น… ํ”„๋ ˆ์ž„์›Œํฌ ์‚ฌ์šฉ ๊ถŒ์žฅ

android.util.Log๋ฅผ ์ง์ ‘ ์‚ฌ์šฉํ•˜๋Š” ๋Œ€์‹  Timber ๊ฐ™์€ ๊ตฌ์กฐํ™”๋œ ๋กœ๊น… ํ”„๋ ˆ์ž„์›Œํฌ ์‚ฌ์šฉ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ๋Š” ๋””๋ฒ„๊ทธ ๋กœ๊ทธ๋ฅผ ์ œ๊ฑฐํ•˜๊ฑฐ๋‚˜ ๋กœ๊ทธ ๋ ˆ๋ฒจ์„ ์กฐ์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

Also applies to: 520-522

core/ui/src/main/java/com/teamsolply/solply/ui/util/PresignedUrlUploader.kt (1)

29-32: ์ŠคํŠธ๋ฆผ ๋ณ€ํ™˜ ์ตœ์ ํ™”๋ฅผ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.

sink.outputStream()์„ ์‚ฌ์šฉํ•˜๋ฉด BufferedSink๋ฅผ ๋‹ค์‹œ OutputStream์œผ๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ๋น„ํšจ์œจ์ ์ž…๋‹ˆ๋‹ค. Okio์˜ ๋„ค์ดํ‹ฐ๋ธŒ API๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์„ฑ๋Šฅ์ด ํ–ฅ์ƒ๋ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ diff๋ฅผ ์ ์šฉํ•˜์—ฌ ์ตœ์ ํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

+import okio.source
+
 override fun writeTo(sink: BufferedSink) {
     context.contentResolver.openInputStream(uri)?.use { input ->
-        input.copyTo(sink.outputStream())
+        sink.writeAll(input.source())
     }
 }
remote/place/src/main/java/com/teamsolply/solply/place/datasource/PlaceRemoteDataSourceImpl.kt (1)

26-51: ํŒŒ๋ผ๋ฏธํ„ฐ ๋„ค์ด๋ฐ ์ผ๊ด€์„ฑ ๊ฐœ์„ ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.

์„œ๋น„์Šค API ํ˜ธ์ถœ ์‹œ subTag1Ids, subTag2Ids๋กœ ๋ณ€๊ฒฝ๋˜์—ˆ์œผ๋‚˜, ํ•จ์ˆ˜ ์‹œ๊ทธ๋‹ˆ์ฒ˜๋Š” ์—ฌ์ „ํžˆ subTagAIdList, subTagBIdList๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์–ด ๋„ค์ด๋ฐ ๋ถˆ์ผ์น˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ์ „์ฒด์ ์ธ ์ผ๊ด€์„ฑ์„ ์œ„ํ•ด ํ•จ์ˆ˜ ํŒŒ๋ผ๋ฏธํ„ฐ๋ช…๋„ ํ•จ๊ป˜ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•ด๋ณด์„ธ์š”.

 override suspend fun getPlaces(
     townId: Long,
     isBookmarkSearch: Boolean,
     mainTagId: Int?,
-    subTagAIdList: List<Int>?,
-    subTagBIdList: List<Int>?
+    subTag1IdList: List<Int>?,
+    subTag2IdList: List<Int>?
 ): GetPlacesResponseDto {
     return placeService.getPlaces(
         townId = townId,
         isBookmarkSearch = isBookmarkSearch,
         mainTagId = mainTagId,
-        subTag1Ids = if (subTagAIdList.isNullOrEmpty()) {
+        subTag1Ids = if (subTag1IdList.isNullOrEmpty()) {
             null
         } else {
-            subTagAIdList.joinToString(
+            subTag1IdList.joinToString(
                 separator = ","
             )
         },
-        subTag2Ids = if (subTagBIdList.isNullOrEmpty()) {
+        subTag2Ids = if (subTag2IdList.isNullOrEmpty()) {
             null
         } else {
-            subTagBIdList.joinToString(
+            subTag2IdList.joinToString(
                 separator = ","
             )
         }
     ).data
 }

์ฐธ๊ณ : ์ด ๋ณ€๊ฒฝ์„ ์ ์šฉํ•˜๋ฉด ์ƒ์œ„ ๋ ˆ์ด์–ด(PlaceRepository, PlaceViewModel ๋“ฑ)์˜ ํŒŒ๋ผ๋ฏธํ„ฐ๋ช…๋„ ํ•จ๊ป˜ ์—…๋ฐ์ดํŠธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

remote/search/src/main/java/com/teamsolply/solply/search/service/SearchService.kt (1)

18-21: ๋ฉ”์„œ๋“œ ์ด๋ฆ„ ๊ฐœ์„ ์„ ๊ณ ๋ คํ•˜์„ธ์š”.

๋ฉ”์„œ๋“œ ์ด๋ฆ„ requestsPlaces๋Š” ๋‹ค์†Œ ๋ถ€์ž์—ฐ์Šค๋Ÿฝ์Šต๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ๋‹จ์ผ ์žฅ์†Œ ๋“ฑ๋ก ์š”์ฒญ์ด๋ฏ€๋กœ requestPlace ๋˜๋Š” registerPlace๊ฐ€ ๋” ์ ์ ˆํ•œ ์ด๋ฆ„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

-    suspend fun requestsPlaces(
+    suspend fun requestPlace(
         @Body registerPlaceRequestDto: RegisterPlaceRequestDto
     ): BaseResponse<RegisterPlaceResponseDto>
domain/search/src/main/java/com/teamsolply/solply/search/model/NaverLocalSearchResponseEntity.kt (1)

3-13: ์ขŒํ‘œ ํ•„๋“œ์˜ ํƒ€์ž…๊ณผ ๋ฌธ์„œํ™”๋ฅผ ๊ณ ๋ คํ•˜์„ธ์š”.

mapx์™€ mapy ํ•„๋“œ๊ฐ€ ์ขŒํ‘œ ๊ฐ’์œผ๋กœ ๋ณด์ด๋Š”๋ฐ String ํƒ€์ž…์œผ๋กœ ์„ ์–ธ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. Naver API ์‘๋‹ต ํ˜•์‹์— ๋”ฐ๋ผ ์˜๋„๋œ ๊ฒƒ์ผ ์ˆ˜ ์žˆ์ง€๋งŒ, ํ–ฅํ›„ ์ˆซ์ž ์—ฐ์‚ฐ์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ ํƒ€์ž… ๋ณ€ํ™˜ ์˜ค๋ฒ„ํ—ค๋“œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ, ๊ฐ ํ•„๋“œ์˜ ์šฉ๋„์— ๋Œ€ํ•œ KDoc ๋ฌธ์„œํ™”๊ฐ€ ์žˆ์œผ๋ฉด ์œ ์ง€๋ณด์ˆ˜์— ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.

remote/search/src/main/java/com/teamsolply/solply/search/datasource/SearchRemoteDataSourceImpl.kt (1)

15-16: ๋ช…์‹œ์  ๋ฐ˜ํ™˜ ํƒ€์ž… ์ถ”๊ฐ€๋ฅผ ๊ณ ๋ คํ•˜์„ธ์š”.

ํƒ€์ž… ์ถ”๋ก ์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์ง€๋งŒ, ์ธํ„ฐํŽ˜์ด์Šค ์‹œ๊ทธ๋‹ˆ์ฒ˜์™€์˜ ์ผ๊ด€์„ฑ๊ณผ ๊ฐ€๋…์„ฑ ํ–ฅ์ƒ์„ ์œ„ํ•ด ๋ช…์‹œ์  ๋ฐ˜ํ™˜ ํƒ€์ž…์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

-    override suspend fun requestsPlaces(registerPlaceRequestDto: RegisterPlaceRequestDto) =
+    override suspend fun requestsPlaces(registerPlaceRequestDto: RegisterPlaceRequestDto): RegisterPlaceResponseDto =
         searchService.requestsPlaces(registerPlaceRequestDto = registerPlaceRequestDto).data
feature/course/src/main/java/com/teamsolply/solply/course/CourseContract.kt (1)

52-55: nullable selectedTownId ํŒŒ๋ผ๋ฏธํ„ฐ์˜ ์˜๋„๋ฅผ ๋ช…ํ™•ํžˆ ํ•˜์„ธ์š”.

selectedTownId๊ฐ€ Long?๋กœ ์ •์˜๋˜์–ด ์žˆ์ง€๋งŒ, ์‹ค์ œ ์‚ฌ์šฉ์ฒ˜(CourseScreen)๋ฅผ ๋ณด๋ฉด ํ•ญ์ƒ state.user.selectedTown.townId ๊ฐ’์„ ์ „๋‹ฌํ•˜๊ณ  ์žˆ์–ด null์ด ๋  ๊ฐ€๋Šฅ์„ฑ์ด ์—†์–ด ๋ณด์ž…๋‹ˆ๋‹ค. nullable๋กœ ์ •์˜ํ•œ ์ด์œ ๊ฐ€ ์žˆ๋‹ค๋ฉด ์ฃผ์„์œผ๋กœ ๋ช…์‹œํ•˜๊ฑฐ๋‚˜, null์ด ๋  ์ˆ˜ ์—†๋‹ค๋ฉด non-null ํƒ€์ž…์œผ๋กœ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•˜์„ธ์š”.

domain/search/src/main/java/com/teamsolply/solply/search/model/RegisterPlaceEntity.kt (1)

3-11: ๋„๋ฉ”์ธ ๊ฒ€์ฆ ๋กœ์ง ์ถ”๊ฐ€๋ฅผ ๊ณ ๋ คํ•˜์„ธ์š”.

RegisterPlaceEntity์— ๋น„์ฆˆ๋‹ˆ์Šค ๊ทœ์น™ ๊ฒ€์ฆ์ด ์—†์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด:

  • placeName๊ณผ address๊ฐ€ ๋นˆ ๋ฌธ์ž์—ด์ธ์ง€ ํ™•์ธ
  • subTagAIds, subTagBIds, images๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ ๋น„์–ด์žˆ์ง€ ์•Š์€์ง€ ํ™•์ธ

๊ฒ€์ฆ์„ presentation ๋ ˆ์ด์–ด์—์„œ๋งŒ ์ˆ˜ํ–‰ํ•  ๊ณ„ํš์ด๋ผ๋ฉด ํ˜„์žฌ ๊ตฌ์กฐ๊ฐ€ ์ ์ ˆํ•˜์ง€๋งŒ, ๋„๋ฉ”์ธ ๋ ˆ์ด์–ด์—์„œ ๋ถˆ๋ณ€ ์กฐ๊ฑด์„ ๋ณด์žฅํ•˜๋Š” ๊ฒƒ์ด ๋” ์•ˆ์ „ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

feature/search/src/main/java/com/teamsolply/solply/registerplace/component/PlaceTypeDropDown.kt (2)

22-94: PlaceTypeDropDown ์ปดํฌ์ €๋ธ” ์ „๋ฐ˜ ๊ตฌํ˜„์€ ์•ˆ์ •์ ์ด๋ฉฐ, ์†Œ์†Œํ•œ ์ •๋ฆฌ ํฌ์ธํŠธ๋งŒ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ๊ธฐ๋ณธ ๋ ˆ์ด๋ธ”/์•„์ดํ…œ ๋ ˆ์ด์•„์›ƒ, ์„ ํƒ๋œ ํƒ€์ž… ์ œ์™ธ ์ฒ˜๋ฆฌ ๋“ฑ ํ”Œ๋กœ์šฐ๋Š” ์ž์—ฐ์Šค๋Ÿฝ์Šต๋‹ˆ๋‹ค.
  • dropDownContents.forEachIndexed์—์„œ index๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋‹ˆ forEach๋กœ ๋‹จ์ˆœํ™”ํ•˜๊ฑฐ๋‚˜, ๋งˆ์ง€๋ง‰ ์•„์ดํ…œ ๋ถ„๊ธฐ(์˜ˆ: ๋งˆ์ง€๋ง‰ Divider ์ œ๊ฑฐ)์— ํ™œ์šฉํ•  ๊ณ„ํš์ด ์—†๋‹ค๋ฉด forEach๋กœ ๋ณ€๊ฒฝํ•ด๋„ ๋ฉ๋‹ˆ๋‹ค.
  • ์•„์ดํ…œ Row ์ „์ฒด์— customClickable์„ ์ ์šฉํ•œ ๊ฒƒ๋„ ํ„ฐ์น˜ ์˜์—ญ ๋ฉด์—์„œ ์ ์ ˆํ•ด ๋ณด์ž…๋‹ˆ๋‹ค.

97-106: ์•„์ด์ฝ˜ ๋งคํ•‘ ์˜๋„ ํ™•์ธ ๋ฐ ๋ฒ”์œ„ ์ถ•์†Œ ๊ณ ๋ ค

  • PlaceType.ALL๊ณผ PlaceType.CAFE๊ฐ€ ๋™์ผํ•œ ic_caffe ์•„์ด์ฝ˜์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š”๋ฐ, ์˜๋„๋œ UI๋ผ๋ฉด ๋ฌธ์ œ ์—†์ง€๋งŒ, ALL ์ „์šฉ ์•„์ด์ฝ˜์ด ์žˆ๋‹ค๋ฉด ๋ถ„๋ฆฌํ•˜๋Š” ํŽธ์ด ๋” ์ง๊ด€์ ์ž…๋‹ˆ๋‹ค.
  • getPlaceTypeIconResId๊ฐ€ ํ˜„์žฌ public(top-level)์ธ๋ฐ, register place UI ์™ธ๋ถ€์—์„œ ์žฌ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด internal ๋˜๋Š” ํŒŒ์ผ ๋‚ด๋ถ€ ์ „์šฉ์œผ๋กœ ๋ฒ”์œ„ ์ถ•์†Œํ•˜๋Š” ๊ฒƒ๋„ ๊ณ ๋ คํ•ด๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceViewModel.kt (3)

51-59: ์žฅ์†Œ๋ช… ์„ ํƒ ์‹œ ์„ฑ๊ณต ํ”Œ๋ž˜๊ทธ ํ† ๊ธ€ ๋กœ์ง ์˜๋„ ํ™•์ธ ํ•„์š”

  • SelectPlaceName ์ฒ˜๋ฆฌ์—์„œ isPlaceNameSuccess = !isPlaceNameSuccess๋กœ ํ† ๊ธ€ํ•˜๊ณ  ์žˆ๋Š”๋ฐ, UX ๊ด€์ ์—์„œ๋Š” โ€œ์„ ํƒ๋˜๋ฉด ํ•ญ์ƒ ์„ฑ๊ณต ์ƒํƒœ(true)โ€๋กœ ๊ฐ•์ œํ•˜๋Š” ํŽธ์ด ๋” ์ž์—ฐ์Šค๋Ÿฌ์šธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋™์ผ ์ธํ…ํŠธ๊ฐ€ ์—ฌ๋Ÿฌ ๋ฒˆ ๋“ค์–ด์˜ฌ ์ˆ˜ ์žˆ๋Š” ๊ตฌ์กฐ๋ผ๋ฉด ํ˜„์žฌ ๊ตฌํ˜„์ฒ˜๋Ÿผ ํ† ๊ธ€์ด ๋˜์–ด, ๋‘ ๋ฒˆ์งธ ์„ ํƒ์—์„œ ์„ฑ๊ณต ํ”Œ๋ž˜๊ทธ๊ฐ€ false๋กœ ๋‚ด๋ ค๊ฐˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ช…์‹œ์ ์œผ๋กœ ์„ฑ๊ณต์œผ๋กœ ๊ณ ์ •ํ•˜๋ ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

-                    copy(
-                        isPlaceNameSuccess = !isPlaceNameSuccess,
+                    copy(
+                        isPlaceNameSuccess = true,
                         placeName = intent.placeName,
                         placeAddress = intent.placeAddress
                     )

์˜๋„์ ์œผ๋กœ ํ† ๊ธ€์„ ์‚ฌ์šฉํ•œ ๊ฒƒ์ธ์ง€ ํ•œ ๋ฒˆ๋งŒ ํ™•์ธ ๋ถ€ํƒ๋“œ๋ฆฝ๋‹ˆ๋‹ค.


61-77: ๋“œ๋กญ๋‹ค์šด ๋‹ซํž˜ ์ƒํƒœ๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ false๋กœ ๋‘๋Š” ํŽธ์ด ๋” ์•ˆ์ „ํ•ฉ๋‹ˆ๋‹ค

  • ChangePlaceTypeDropDownVisible์™€ ClickDropDownItem ๋ชจ๋‘ isPlaceTypeDropdownExpanded = !isPlaceTypeDropdownExpanded๋กœ ํ† ๊ธ€ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์‹ค์ œ UI์—์„œ๋Š” ์•„์ดํ…œ ํด๋ฆญ ์‹œ ํ•ญ์ƒ ๋“œ๋กญ๋‹ค์šด์„ ๋‹ซ๋Š” ๋™์ž‘์ด ์˜ˆ์ƒ๋˜๋ฏ€๋กœ, ํ† ๊ธ€๋ณด๋‹ค๋Š” false๋กœ ๋ช…์‹œํ•˜๋Š” ํŽธ์ด ์ƒํƒœ ๊ผฌ์ž„ ๊ฐ€๋Šฅ์„ฑ์ด ์ ์Šต๋‹ˆ๋‹ค.

์˜ˆ์‹œ:

            is RegisterPlaceIntent.ClickDropDownItem -> {
                reduce {
                    copy(
                        selectedPlaceType = intent.placeType,
-                        isPlaceTypeDropdownExpanded = !isPlaceTypeDropdownExpanded
+                        isPlaceTypeDropdownExpanded = false
                    )
                }
            }

139-279: ์žฅ์†Œ ๋“ฑ๋ก ํ”Œ๋กœ์šฐ๋Š” ์ž˜ ๋‚˜๋‰˜์–ด ์žˆ์œผ๋‚˜, ์ƒํƒœ ์Šค๋ƒ…์ƒท ๋ฐ ํŒŒ์ผ๋ช… ๋งคํ•‘ ๋ถ€๋ถ„์€ ๋ณด์™„ ์—ฌ์ง€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค

์ข‹์€ ์ :

  • โ€œ์ด๋ฏธ์ง€ ์—†์Œ / ์žˆ์Œโ€ ์ผ€์ด์Šค๋ฅผ ๋ช…ํ™•ํžˆ ๋ถ„๊ธฐํ•˜๊ณ , presigned URL ๋ฐœ๊ธ‰ โ†’ ์—…๋กœ๋“œ โ†’ ๋“ฑ๋ก API ํ˜ธ์ถœ์ด๋ผ๋Š” 3๋‹จ๊ณ„ ํ”Œ๋กœ์šฐ๊ฐ€ ์ž˜ ๋“œ๋Ÿฌ๋‚ฉ๋‹ˆ๋‹ค.
  • runCatching + coroutineScope + async/awaitAll๋กœ ์—…๋กœ๋“œ๋ฅผ ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌํ•œ ๊ตฌ์กฐ๋„ ์ ์ ˆํ•ฉ๋‹ˆ๋‹ค.

๋ณด์™„์„ ๊ถŒ์žฅํ•˜๊ณ  ์‹ถ์€ ๋ถ€๋ถ„:

  1. UI ์ƒํƒœ ์Šค๋ƒ…์ƒท ์‚ฌ์šฉ

    • uiState.value๋ฅผ ์—ฌ๋Ÿฌ ๋ฒˆ ์ฝ์–ด ๊ฐ๊ฐ์˜ ํ•„๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š”๋ฐ, ๋“ฑ๋ก ์‹œ์ž‘ ์‹œ ํ•œ ๋ฒˆ ๋กœ์ปฌ ๋ณ€์ˆ˜๋กœ ์บก์ฒ˜ํ•ด ๋‘๋ฉด ์ค‘๊ฐ„์— ๋‹ค๋ฅธ ์ธํ…ํŠธ๋กœ state๊ฐ€ ๋ณ€ํ•ด๋„ ์š”์ฒญ ๋ฐ์ดํ„ฐ๋Š” ์ผ๊ด€๋˜๊ฒŒ ์œ ์ง€๋ฉ๋‹ˆ๋‹ค.
    • ์˜ˆ์‹œ: val state = uiState.value ์ดํ›„ state.placeName, state.selectedPlaceKeyword ๋“ฑ ์‚ฌ์šฉ.
  2. ํŒŒ์ผ๋ช… ๊ธฐ๋ฐ˜ ๋งคํ•‘์˜ ์ถฉ๋Œ ๊ฐ€๋Šฅ์„ฑ

    • presigned URL ์‘๋‹ต ๋งคํ•‘์—์„œ val byName = uris.associateBy { resolver.getFileName(it) }๋กœ ์ด๋ฆ„ ๊ธฐ์ค€ Map์„ ๋งŒ๋“ค๊ณ , info.originalFileName์œผ๋กœ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค.
    • ๋™์ผํ•œ ํŒŒ์ผ๋ช…์„ ๊ฐ€์ง„ URI๊ฐ€ 2๊ฐœ ์ด์ƒ์ธ ๊ฒฝ์šฐ ๋งˆ์ง€๋ง‰ ๊ฒƒ๋งŒ ๋‚จ๊ณ  ๋‚˜๋จธ์ง€๋Š” ๋ฎ์–ด์จ์งˆ ์ˆ˜ ์žˆ์–ด, ์˜๋„ํ•œ ๋งคํ•‘์ด ๊นจ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    • ์„œ๋ฒ„/ํด๋ผ์ด์–ธํŠธ ๋ชจ๋‘ ํŒŒ์ผ๋ช…์„ ์œ ์ผํ•˜๊ฒŒ ๋ณด์žฅํ•˜๋Š”์ง€, ์•„๋‹ˆ๋ฉด index ๊ธฐ๋ฐ˜ ๋งคํ•‘(์š”์ฒญ ์ˆœ์„œ ๊ธฐ์ค€)์œผ๋กœ ๋ฐ”๊พธ๋Š” ๊ฒƒ์ด ๋‚˜์„์ง€ ํ•œ ๋ฒˆ ์ ๊ฒ€์ด ํ•„์š”ํ•ด ๋ณด์ž…๋‹ˆ๋‹ค.
  3. ์ค‘๋ณต RegisterPlaceEntity ๋นŒ๋” ์ถ”์ถœ

    • ์ด๋ฏธ์ง€ ์œ ๋ฌด์— ๋”ฐ๋ผ ๊ฐ™์€ ํ•„๋“œ ์„ธํŠธ๋ฅผ ๋‘ ๋ฒˆ ์ž‘์„ฑํ•˜๊ณ  ์žˆ์œผ๋ฏ€๋กœ, buildRegisterPlaceEntity(images: List<PlaceImageEntity>) ๋ฅ˜์˜ private ํ—ฌํผ๋กœ ๊ณตํ†ตํ™”ํ•˜๋ฉด ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ํŽธํ•ด์ง‘๋‹ˆ๋‹ค.

์ „์ฒด์ ์œผ๋กœ ํฐ ๊ตฌ์กฐ๋Š” ์ž˜ ์„ค๊ณ„๋˜์–ด ์žˆ๊ณ , ์œ„ ํ•ญ๋ชฉ๋“ค์€ ์ฃผ๋กœ ์œ ์ง€๋ณด์ˆ˜์„ฑ๊ณผ ์ž ์žฌ์ ์ธ ์—ฃ์ง€ ์ผ€์ด์Šค๋ฅผ ์ค„์ด๊ธฐ ์œ„ํ•œ ์ œ์•ˆ์ž…๋‹ˆ๋‹ค.

data/search/src/main/java/com/teamsolply/solply/search/repository/SearchRepositoryImpl.kt (2)

36-55: searchAddress ๋งคํ•‘์€ ๊น”๋”ํ•˜์ง€๋งŒ, ์—๋Ÿฌ ๋กœ๊น…/๋ณ€ํ™˜ ์ •์ฑ…๋งŒ ํ•œ ๋ฒˆ ๋” ์ •๋ฆฌํ•˜๋ฉด ์ข‹๊ฒ ์Šต๋‹ˆ๋‹ค

  • runCatching { naverLocalSearchService.searchLocal(query = query).items } ํ›„ DTO โ†’ Entity ๋ณ€ํ™˜๊นŒ์ง€ mapCatching์œผ๋กœ ๋ฌถ์€ ๊ตฌ์กฐ๋Š” ๊ฐ„๊ฒฐํ•˜๊ณ  ์ข‹์Šต๋‹ˆ๋‹ค.
  • HtmlCompat.fromHtml(..., HtmlCompat.FROM_HTML_MODE_LEGACY).toString()์œผ๋กœ ํƒ€์ดํ‹€์—์„œ HTML ํƒœ๊ทธ๋ฅผ ์ œ๊ฑฐํ•ด ๋„๋ฉ”์ธ์— โ€œ๊นจ๋—ํ•œ ๋ฌธ์ž์—ดโ€๋งŒ ์ „๋‹ฌํ•˜๋Š” ์ „๋žต๋„ ํ•ฉ๋ฆฌ์ ์ž…๋‹ˆ๋‹ค.
  • ํ•„์š”ํ•˜๋‹ค๋ฉด, ํ˜ธ์ถœ ์ธก ๋””๋ฒ„๊น…์„ ์œ„ํ•ด ์—ฌ๊ธฐ์„œ ์‹คํŒจ ์‹œ ๋กœ๊ทธ ์ •๋„๋งŒ ๋‚จ๊ธฐ๊ฑฐ๋‚˜, ๋นˆ ๋ฆฌ์ŠคํŠธ๋กœ ๋Œ€์ฒดํ•˜๋Š” ๋“ฑ ๊ณตํ†ต ์ •์ฑ…์„ ์ •ํ•ด๋‘๋Š” ๊ฒƒ๋„ ๊ณ ๋ คํ•ด ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

57-80: requestsPlaces ๋งคํ•‘์€ ๋ช…ํ™•ํ•˜๋ฉฐ, ์ด๋ฏธ์ง€ DTO ๋ณ€ํ™˜๋„ ์ ์ ˆํ•ฉ๋‹ˆ๋‹ค

  • RegisterPlaceEntity โ†’ RegisterPlaceRequestDto๋กœ์˜ ํ•„๋“œ ๋งคํ•‘์ด 1:1๋กœ ์ž˜ ๋Œ€์‘๋˜๊ณ , images ๋ณ€ํ™˜ ์‹œ displayOrder, tempFileKey๋งŒ DTO๋กœ ๋„˜๊ธฐ๋Š” ๊ฒƒ๋„ ์„œ๋ฒ„ ๊ณ„์•ฝ์— ๋งž๋Š” ์‹ฌํ”Œํ•œ ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค.
  • runCatching { ... }.mapCatching { ... } ํŒจํ„ด์œผ๋กœ ๋„คํŠธ์›Œํฌ ์˜ˆ์™ธ๋ฅผ Result๋กœ ๊ฐ์‹ธ๋Š” ๊ตฌ์กฐ๋„ ์ผ๊ด€์„ฑ ์žˆ์Šต๋‹ˆ๋‹ค.

์ถ”๊ฐ€๋กœ, ์ด๋ฏธ์ง€ ํ•„๋“œ ๋งคํ•‘์ด ๋‹ค๋ฅธ ๊ณณ์—์„œ๋„ ๋ฐ˜๋ณต๋œ๋‹ค๋ฉด ๋ณ„๋„์˜ mapper ํ•จ์ˆ˜(์˜ˆ: PlaceImageEntity.toDto())๋กœ ๋ฝ‘์•„๋‘๋Š” ์ •๋„๋งŒ ๊ณ ๋ คํ•˜์‹œ๋ฉด ์ถฉ๋ถ„ํ•ด ๋ณด์ž…๋‹ˆ๋‹ค.

feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/favoriteTownNavigation/FavoriteTownNavigation.kt (1)

13-18: ํƒ€์ž… ์„ธ์ดํ”„ ๋ผ์šฐํŠธ๋กœ ๋ณ€๊ฒฝ๋œ ๋„ค๋น„๊ฒŒ์ด์…˜์€ ์ž˜ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค

  • FavoriteTown(val selectedTownId: Long) : Route๋กœ ๋ฐ”๊พธ๊ณ , navigate(FavoriteTown(selectedTownId), navOptions)๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹์€ ํƒ€์ž… ์„ธ์ดํ”„ํ•˜๊ณ  ์‹ค์ˆ˜ ์—ฌ์ง€๋ฅผ ์ค„์—ฌ์ค๋‹ˆ๋‹ค.
  • ๋‹ค๋งŒ navOptions๋ฅผ ํ•ญ์ƒ ์š”๊ตฌํ•˜๊ฒŒ ๋ณ€๊ฒฝ๋˜์—ˆ์œผ๋ฏ€๋กœ, ๊ธฐ์กด ํ˜ธ์ถœ๋ถ€์—์„œ NavOptions๋ฅผ ๋„˜๊ธฐ์ง€ ์•Š๋˜ ๊ณณ์€ ๋ชจ๋‘ ์—…๋ฐ์ดํŠธ๋˜์—ˆ๋Š”์ง€ ํ•œ ๋ฒˆ๋งŒ ํ™•์ธํ•ด ์ฃผ์„ธ์š”. ํ•„์š”ํ•˜๋‹ค๋ฉด navOptions: NavOptions? = null ๊ธฐ๋ณธ๊ฐ’์„ ๋‘๋Š” ๊ฒƒ๋„ ์˜ต์…˜์ž…๋‹ˆ๋‹ค.
feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/FavoriteTownRoute.kt (1)

178-245: RightTownPane์˜ ์„ ํƒ/๊ตฌ๋ถ„์„  ์ฒ˜๋ฆฌ๋„ ์•ˆ์ •์ ์ž…๋‹ˆ๋‹ค

  • selectedTownId์™€ ๋น„๊ตํ•ด ์„ ํƒ ์ƒํƒœ๋ฅผ ํŒ๋‹จํ•˜๊ณ , ํ…์ŠคํŠธ ์Šคํƒ€์ผ/์ƒ‰์ƒ์„ ๋ถ„๋ฆฌํ•œ ๋ถ€๋ถ„์ด ๋ช…ํ™•ํ•ฉ๋‹ˆ๋‹ค.
  • ์ฒซ ๋ฒˆ์งธ ์•„์ดํ…œ๊ณผ ๋‚˜๋จธ์ง€์— ๋Œ€ํ•ด ์ƒ๋‹จ/ํ•˜๋‹จ ๊ตฌ๋ถ„์„ ์„ ์ง์ ‘ ๊ทธ๋ฆฌ๋Š” drawBehind ๋กœ์ง๋„ ์ž˜ ๋™์ž‘ํ•  ๊ฒƒ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค.
  • ์„ ํƒ๋œ ํ•ญ๋ชฉ์—๋งŒ ์ฒดํฌ ์•„์ด์ฝ˜์„ ํ‘œ์‹œํ•˜๋Š” ์กฐ๊ฑด๋ฌธ๋„ ๋‹จ์ˆœ ๋ช…๋ฃŒํ•ฉ๋‹ˆ๋‹ค.

์ถ”๊ฐ€๋กœ, ๋ฆฌ์ŠคํŠธ ํ•ญ๋ชฉ ์ˆ˜๊ฐ€ ๋งŽ์•„์งˆ ๊ฒฝ์šฐ๋ฅผ ๋Œ€๋น„ํ•ด ์„ฑ๋Šฅ ์ตœ์ ํ™”๋ฅผ ๋” ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด, towns.firstOrNull() ํ˜ธ์ถœ์„ ๋ฃจํ”„ ๋ฐ–์œผ๋กœ ๋นผ๋Š” ์ •๋„์˜ ๋งˆ์ดํฌ๋กœ ์ตœ์ ํ™”๋Š” ๊ณ ๋ คํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ํ•„์ˆ˜๋Š” ์•„๋‹™๋‹ˆ๋‹ค.

feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceScreen.kt (1)

463-463: ๋ณต์žกํ•œ ์กฐ๊ฑด์‹์„ ์ถ”์ถœํ•˜์—ฌ ๊ฐ€๋…์„ฑ์„ ๊ฐœ์„ ํ•˜์„ธ์š”.

์™„๋ฃŒ ๋ฒ„ํŠผ์˜ ํ™œ์„ฑํ™” ์กฐ๊ฑด์ด ๋ณต์žกํ•ฉ๋‹ˆ๋‹ค. RegisterPlaceState์— computed property๋กœ ์ถ”์ถœํ•˜๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•ด๋ณด์„ธ์š”.

RegisterPlaceContract.kt์— ์ถ”๊ฐ€:

data class RegisterPlaceState(
    // ... ๊ธฐ์กด ํ•„๋“œ๋“ค
) : UiState {
    val resultCount: Int get() = searchResults.size
    val hasQuery: Boolean get() = placeName.isNotBlank()
    val isFormValid: Boolean get() = 
        placeName.isNotEmpty() && 
        selectedPlaceType != null && 
        selectedPlaceKeyword.isNotEmpty() && 
        selectedPlaceFeature.isNotEmpty()
}

์‚ฌ์šฉ:

-        selected = uiState.placeName.isNotEmpty() && uiState.selectedPlaceType != null && uiState.selectedPlaceKeyword.isNotEmpty() && uiState.selectedPlaceFeature.isNotEmpty(),
+        selected = uiState.isFormValid,
๐Ÿ“œ Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

๐Ÿ“ฅ Commits

Reviewing files that changed from the base of the PR and between 4eaf764 and fbfd672.

๐Ÿ“’ Files selected for processing (66)
  • build-logic/convention/src/main/java/com/teamsolply/solply/convention/BuildConfig.kt (1 hunks)
  • core/buildconfig/src/main/java/com/teamsolply/solply/buildconfig/impl/BuildConfigFieldsProviderImpl.kt (2 hunks)
  • core/common/src/main/java/com/teamsolply/solply/common/buildconfig/BuildConfigFields.kt (1 hunks)
  • core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/card/RegisterPlaceImage.kt (1 hunks)
  • core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/dropdown/SolplyBasicDropDown.kt (4 hunks)
  • core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/header/SolplyHomeHeader.kt (2 hunks)
  • core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/textfield/SolplyTextField.kt (11 hunks)
  • core/designsystem/src/main/res/drawable/ic_arrow_down_lg.xml (1 hunks)
  • core/model/src/main/java/com/teamsolply/solply/model/PlaceType.kt (1 hunks)
  • core/network/src/main/java/com/teamsolply/solply/network/di/NaverApiModule.kt (1 hunks)
  • core/network/src/main/java/com/teamsolply/solply/network/model/NaverLocalSearchResponseDto.kt (1 hunks)
  • core/network/src/main/java/com/teamsolply/solply/network/service/NaverLocalSearchService.kt (1 hunks)
  • core/ui/src/main/java/com/teamsolply/solply/ui/util/PresignedUrlUploader.kt (1 hunks)
  • data/maps/src/main/java/com/teamsolply/solply/maps/dto/response/PresignedUrlsResponseDto.kt (1 hunks)
  • data/place/src/main/java/com/teamsolply/solply/place/dto/response/GetPlacesResponseDto.kt (1 hunks)
  • data/place/src/main/java/com/teamsolply/solply/place/dto/response/GetRecommendPlaceDto.kt (1 hunks)
  • data/place/src/main/java/com/teamsolply/solply/place/mapper/PlaceEntityMapper.kt (1 hunks)
  • data/place/src/main/java/com/teamsolply/solply/place/repository/PlaceRepositoryImpl.kt (2 hunks)
  • data/search/src/main/java/com/teamsolply/solply/search/dto/request/RegisterPlaceRequestDto.kt (1 hunks)
  • data/search/src/main/java/com/teamsolply/solply/search/dto/response/RegisterPlaceResponseDto.kt (1 hunks)
  • data/search/src/main/java/com/teamsolply/solply/search/dto/response/SearchResponseDto.kt (2 hunks)
  • data/search/src/main/java/com/teamsolply/solply/search/repository/SearchRepositoryImpl.kt (2 hunks)
  • data/search/src/main/java/com/teamsolply/solply/search/source/SearchRemoteDataSource.kt (1 hunks)
  • domain/search/src/main/java/com/teamsolply/solply/search/model/NaverLocalSearchResponseEntity.kt (1 hunks)
  • domain/search/src/main/java/com/teamsolply/solply/search/model/RegisterPlaceEntity.kt (1 hunks)
  • domain/search/src/main/java/com/teamsolply/solply/search/model/SearchResultEntity.kt (1 hunks)
  • domain/search/src/main/java/com/teamsolply/solply/search/repository/SearchRepository.kt (1 hunks)
  • feature/course/src/main/java/com/teamsolply/solply/course/CourseContract.kt (1 hunks)
  • feature/course/src/main/java/com/teamsolply/solply/course/CourseScreen.kt (3 hunks)
  • feature/course/src/main/java/com/teamsolply/solply/course/CourseViewModel.kt (1 hunks)
  • feature/course/src/main/java/com/teamsolply/solply/course/component/FavoriteTownTopBar.kt (2 hunks)
  • feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/FavoriteTownContract.kt (1 hunks)
  • feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/FavoriteTownRoute.kt (10 hunks)
  • feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/FavoriteViewModel.kt (3 hunks)
  • feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/favoriteTownNavigation/FavoriteTownNavigation.kt (1 hunks)
  • feature/course/src/main/java/com/teamsolply/solply/course/navigation/CourseNavigation.kt (1 hunks)
  • feature/main/build.gradle.kts (1 hunks)
  • feature/main/src/main/AndroidManifest.xml (1 hunks)
  • feature/main/src/main/java/com/teamsolply/solply/main/MainNavigator.kt (3 hunks)
  • feature/main/src/main/java/com/teamsolply/solply/main/MainScreen.kt (4 hunks)
  • feature/maps/src/main/java/com/teamsolply/solply/maps/MapsViewModel.kt (5 hunks)
  • feature/maps/src/main/java/com/teamsolply/solply/maps/component/bottomsheet/PlaceDetailBottomSheet.kt (4 hunks)
  • feature/maps/src/main/java/com/teamsolply/solply/maps/component/dialog/ReportPlaceDialog.kt (5 hunks)
  • feature/mypage/src/main/java/com/teamsolply/solply/mypage/component/SolplyPersonaDropDown.kt (1 hunks)
  • feature/place/build.gradle.kts (1 hunks)
  • feature/place/src/main/java/com/teamsolply/solply/place/PlaceContract.kt (1 hunks)
  • feature/place/src/main/java/com/teamsolply/solply/place/PlaceScreen.kt (4 hunks)
  • feature/place/src/main/java/com/teamsolply/solply/place/PlaceViewModel.kt (2 hunks)
  • feature/place/src/main/java/com/teamsolply/solply/place/component/button/PlaceChipButton.kt (1 hunks)
  • feature/place/src/main/java/com/teamsolply/solply/place/navigation/PlaceNavigation.kt (1 hunks)
  • feature/search/build.gradle.kts (1 hunks)
  • feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceContract.kt (1 hunks)
  • feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceScreen.kt (1 hunks)
  • feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceViewModel.kt (1 hunks)
  • feature/search/src/main/java/com/teamsolply/solply/registerplace/component/PlaceTypeDropDown.kt (1 hunks)
  • feature/search/src/main/java/com/teamsolply/solply/registerplace/component/RegisterPlaceItem.kt (1 hunks)
  • feature/search/src/main/java/com/teamsolply/solply/registerplace/navigation/RegisterPlaceNavigation.kt (1 hunks)
  • feature/search/src/main/java/com/teamsolply/solply/search/SearchContract.kt (1 hunks)
  • feature/search/src/main/java/com/teamsolply/solply/search/SearchDialog.kt (0 hunks)
  • feature/search/src/main/java/com/teamsolply/solply/search/SearchScreen.kt (1 hunks)
  • feature/search/src/main/java/com/teamsolply/solply/search/SearchViewModel.kt (1 hunks)
  • feature/search/src/main/java/com/teamsolply/solply/search/navigation/SearchNavigation.kt (1 hunks)
  • remote/place/src/main/java/com/teamsolply/solply/place/datasource/PlaceRemoteDataSourceImpl.kt (1 hunks)
  • remote/place/src/main/java/com/teamsolply/solply/place/service/PlaceService.kt (1 hunks)
  • remote/search/src/main/java/com/teamsolply/solply/search/datasource/SearchRemoteDataSourceImpl.kt (2 hunks)
  • remote/search/src/main/java/com/teamsolply/solply/search/service/SearchService.kt (1 hunks)
๐Ÿ’ค Files with no reviewable changes (1)
  • feature/search/src/main/java/com/teamsolply/solply/search/SearchDialog.kt
๐Ÿงฐ Additional context used
๐Ÿงฌ Code graph analysis (20)
core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/card/RegisterPlaceImage.kt (1)
core/ui/src/main/java/com/teamsolply/solply/ui/image/AdaptationImage.kt (1)
  • AdaptationImage (15-69)
feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceViewModel.kt (3)
core/ui/src/main/java/com/teamsolply/solply/ui/base/BaseViewModel.kt (3)
  • reduce (44-46)
  • postSideEffect (48-52)
  • sendIntent (38-42)
domain/search/src/main/java/com/teamsolply/solply/search/repository/SearchRepository.kt (1)
  • searchAddress (10-10)
core/ui/src/main/java/com/teamsolply/solply/ui/util/PresignedUrlUploader.kt (1)
  • uploadToPresignedUrl (36-58)
feature/course/src/main/java/com/teamsolply/solply/course/CourseScreen.kt (1)
feature/main/src/main/java/com/teamsolply/solply/main/MainNavigator.kt (2)
  • navigateToFavoriteTown (167-169)
  • navigateToSearch (171-176)
feature/place/src/main/java/com/teamsolply/solply/place/PlaceScreen.kt (1)
feature/main/src/main/java/com/teamsolply/solply/main/MainNavigator.kt (2)
  • navigateToFavoriteTown (167-169)
  • navigateToSearch (171-176)
feature/place/src/main/java/com/teamsolply/solply/place/navigation/PlaceNavigation.kt (1)
feature/place/src/main/java/com/teamsolply/solply/place/PlaceScreen.kt (1)
  • PlaceRoute (64-180)
feature/search/src/main/java/com/teamsolply/solply/registerplace/navigation/RegisterPlaceNavigation.kt (2)
feature/main/src/main/java/com/teamsolply/solply/main/MainNavigator.kt (1)
  • navigate (42-82)
feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceScreen.kt (1)
  • RegisterPlaceRoute (66-140)
feature/place/src/main/java/com/teamsolply/solply/place/PlaceViewModel.kt (1)
core/ui/src/main/java/com/teamsolply/solply/ui/base/BaseViewModel.kt (1)
  • postSideEffect (48-52)
feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/FavoriteViewModel.kt (3)
core/ui/src/main/java/com/teamsolply/solply/ui/base/BaseViewModel.kt (2)
  • reduce (44-46)
  • postSideEffect (48-52)
data/course/src/main/java/com/teamsolply/solply/course/favoriteTown/repository/FavoriteTownRepositoryImpl.kt (1)
  • patchUserFavoriteTown (37-46)
domain/course/src/main/java/com/teamsolply/solply/course/favoriteTown/repository/FavoriteTownRepository.kt (1)
  • patchUserFavoriteTown (8-11)
feature/search/src/main/java/com/teamsolply/solply/search/SearchViewModel.kt (1)
core/ui/src/main/java/com/teamsolply/solply/ui/base/BaseViewModel.kt (1)
  • postSideEffect (48-52)
feature/course/src/main/java/com/teamsolply/solply/course/CourseViewModel.kt (1)
core/ui/src/main/java/com/teamsolply/solply/ui/base/BaseViewModel.kt (1)
  • postSideEffect (48-52)
feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/FavoriteTownRoute.kt (2)
feature/main/src/main/java/com/teamsolply/solply/main/MainNavigator.kt (1)
  • navigateToBack (116-118)
feature/course/src/main/java/com/teamsolply/solply/course/component/FavoriteTownTopBar.kt (1)
  • FavoriteTownTopBar (21-58)
feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/favoriteTownNavigation/FavoriteTownNavigation.kt (1)
feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/FavoriteTownRoute.kt (1)
  • FavoriteTownRoute (37-115)
feature/main/src/main/java/com/teamsolply/solply/main/MainScreen.kt (2)
feature/search/src/main/java/com/teamsolply/solply/search/navigation/SearchNavigation.kt (1)
  • searchNavGraph (16-30)
feature/search/src/main/java/com/teamsolply/solply/registerplace/navigation/RegisterPlaceNavigation.kt (1)
  • registerPlaceNavGraph (16-26)
feature/search/src/main/java/com/teamsolply/solply/registerplace/component/PlaceTypeDropDown.kt (1)
core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/dropdown/SolplyBasicDropDown.kt (1)
  • SolplyBasicDropDown (32-99)
feature/maps/src/main/java/com/teamsolply/solply/maps/MapsViewModel.kt (1)
core/ui/src/main/java/com/teamsolply/solply/ui/base/BaseViewModel.kt (1)
  • sendIntent (38-42)
feature/course/src/main/java/com/teamsolply/solply/course/navigation/CourseNavigation.kt (1)
feature/course/src/main/java/com/teamsolply/solply/course/CourseScreen.kt (1)
  • CourseRoute (31-86)
feature/search/src/main/java/com/teamsolply/solply/search/SearchScreen.kt (4)
core/ui/src/main/java/com/teamsolply/solply/ui/lifecycle/LaunchedEffectWithLifecycle.kt (1)
  • LaunchedEffectWithLifecycle (11-24)
feature/main/src/main/java/com/teamsolply/solply/main/MainNavigator.kt (2)
  • navigateToRegisterPlace (178-180)
  • navigateToBack (116-118)
core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/textfield/SolplyTextField.kt (1)
  • SolplyRenameCourseTextField (304-330)
feature/search/src/main/java/com/teamsolply/solply/search/component/SearchItem.kt (1)
  • SearchItem (28-89)
feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceScreen.kt (6)
core/ui/src/main/java/com/teamsolply/solply/ui/lifecycle/LaunchedEffectWithLifecycle.kt (1)
  • LaunchedEffectWithLifecycle (11-24)
core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/textfield/SolplyTextField.kt (2)
  • SolplyRenameCourseTextField (304-330)
  • SolplyFixedReportTextField (332-406)
feature/search/src/main/java/com/teamsolply/solply/registerplace/component/RegisterPlaceItem.kt (1)
  • RegisterPlaceItem (13-40)
feature/search/src/main/java/com/teamsolply/solply/registerplace/component/PlaceTypeDropDown.kt (1)
  • PlaceTypeDropDown (22-95)
core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/card/RegisterPlaceImage.kt (1)
  • RegisterPlaceImage (33-112)
core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/button/SolplyButton.kt (1)
  • SolplyBasicButton (57-83)
feature/search/src/main/java/com/teamsolply/solply/search/navigation/SearchNavigation.kt (2)
feature/main/src/main/java/com/teamsolply/solply/main/MainNavigator.kt (1)
  • navigate (42-82)
feature/search/src/main/java/com/teamsolply/solply/search/SearchScreen.kt (1)
  • SearchScreen (45-221)
feature/maps/src/main/java/com/teamsolply/solply/maps/component/dialog/ReportPlaceDialog.kt (1)
core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/card/RegisterPlaceImage.kt (1)
  • RegisterPlaceImage (33-112)
๐Ÿ”‡ Additional comments (82)
feature/course/src/main/java/com/teamsolply/solply/course/component/FavoriteTownTopBar.kt (2)

29-29: ์ƒ๋‹จ ํŒจ๋”ฉ ์ฆ๊ฐ€ ๋ณ€๊ฒฝ์‚ฌํ•ญ ์Šน์ธ

์ƒ๋‹จ ํŒจ๋”ฉ์„ 4.dp์—์„œ 16.dp๋กœ ์ฆ๊ฐ€์‹œํ‚จ ๊ฒƒ์€ UI ๊ฐœ์„ ์„ ์œ„ํ•œ ์˜๋„์ ์ธ ๋ณ€๊ฒฝ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค. ๋” ๋‚˜์€ ์‹œ๊ฐ์  ๊ณ„์ธต ๊ตฌ์กฐ์™€ ์—ฌ๋ฐฑ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.


42-42: ํ…์ŠคํŠธ ๋ณ€๊ฒฝ์— ๋Œ€ํ•œ ์˜๋ฏธ์  ๊ฒ€ํ†  ํ•„์š”

๋ ˆ์ด๋ธ”์ด "์ž์ฃผ ๊ฐ€๋Š” ๋™๋„ค"์—์„œ "๋™๋„ค ์„ค์ •"์œผ๋กœ ๋ณ€๊ฒฝ๋˜๋ฉด์„œ ์˜๋ฏธ๊ฐ€ "์ž์ฃผ ๋ฐฉ๋ฌธํ•˜๋Š” ์žฅ์†Œ"์—์„œ "์„ค์ •/๊ตฌ์„ฑ"์œผ๋กœ ๋ณ€๊ฒฝ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๊ธฐ๋Šฅ์˜ ๋ชฉ์ ์ด๋‚˜ ๋ฒ”์œ„๊ฐ€ ๋ณ€๊ฒฝ๋˜์—ˆ์Œ์„ ์‹œ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

์ด ํ…์ŠคํŠธ ๋ณ€๊ฒฝ์ด ๋ฆฌํŒฉํ† ๋ง๋œ ๊ธฐ๋Šฅ์˜ ์—…๋ฐ์ดํŠธ๋œ ๋ชฉ์ ๊ณผ ์ผ์น˜ํ•˜๋Š”์ง€ ํ™•์ธํ•ด ์ฃผ์„ธ์š”.

feature/place/src/main/java/com/teamsolply/solply/place/component/button/PlaceChipButton.kt (1)

50-50: ๋“œ๋กœ์–ด๋ธ” ๋ฆฌ์†Œ์Šค ๋ณ€๊ฒฝ์ด ๊ฒ€์ฆ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๊ฒ€์ฆ ๊ฒฐ๊ณผ:

  • โœ“ ์ƒˆ ๋ฆฌ์†Œ์Šค ic_arrow_down์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค (core/designsystem/src/main/res/drawable/ic_arrow_down.xml)
  • โœ“ ์ด์ „ ๋ฆฌ์†Œ์Šค ic_under_arrow๋Š” ์ฝ”๋“œ๋ฒ ์ด์Šค ์ „์ฒด์—์„œ ์™„์ „ํžˆ ์ œ๊ฑฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค (๋‚จ์€ ์‚ฌ์šฉ ์—†์Œ)

๋ณ€๊ฒฝ ์‚ฌํ•ญ์ด ์ผ๊ด€์„ฑ ์žˆ๊ฒŒ ์ ์šฉ๋˜์—ˆ์œผ๋ฏ€๋กœ ์ฝ”๋“œ๋Š” ์Šน์ธ ๊ฐ€๋Šฅํ•œ ์ƒํƒœ์ž…๋‹ˆ๋‹ค.

feature/maps/src/main/java/com/teamsolply/solply/maps/component/bottomsheet/PlaceDetailBottomSheet.kt (2)

309-309: ๋””์ž์ธ ์‹œ์Šคํ…œ ์ผ๊ด€์„ฑ ๊ฐœ์„ ์„ ์œ„ํ•œ ์ข‹์€ ๋ณ€๊ฒฝ์‚ฌํ•ญ์ž…๋‹ˆ๋‹ค.

lineHeight ์˜ค๋ฒ„๋ผ์ด๋“œ๋ฅผ ์ œ๊ฑฐํ•˜๊ณ  SolplyTheme.typography.caption14R ๊ธฐ๋ณธ ์Šคํƒ€์ผ์„ ์ง์ ‘ ์‚ฌ์šฉํ•˜๋„๋ก ๋ณ€๊ฒฝํ•˜์—ฌ, ํƒ€์ดํฌ๊ทธ๋ž˜ํ”ผ ์ผ๊ด€์„ฑ์ด ํ–ฅ์ƒ๋˜๊ณ  ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ์šฉ์ดํ•ด์กŒ์Šต๋‹ˆ๋‹ค. ๋””์ž์ธ ์‹œ์Šคํ…œ์˜ ์ค‘์•™ํ™”๋œ ์Šคํƒ€์ผ ๊ด€๋ฆฌ๋ฅผ ๋”ฐ๋ฅด๋Š” ์˜ฌ๋ฐ”๋ฅธ ์ ‘๊ทผ์ž…๋‹ˆ๋‹ค.

Also applies to: 334-334, 359-359


439-439: UI ๊ฐœ์„ ์„ ์œ„ํ•œ ์ ์ ˆํ•œ ์—ฌ๋ฐฑ ์กฐ์ •์ž…๋‹ˆ๋‹ค.

ํ•˜๋‹จ ์—ฌ๋ฐฑ์„ 40.dp์—์„œ 49.dp๋กœ ์ฆ๊ฐ€์‹œ์ผœ ์‹œ๊ฐ์  ๊ท ํ˜•์„ ๊ฐœ์„ ํ–ˆ์Šต๋‹ˆ๋‹ค. 1์ฐจ QA ํ”ผ๋“œ๋ฐฑ์„ ๋ฐ˜์˜ํ•œ ์ ์ ˆํ•œ ์กฐ์ •์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค.

feature/search/src/main/java/com/teamsolply/solply/registerplace/component/RegisterPlaceItem.kt (2)

13-19: ํ•จ์ˆ˜ ์‹œ๊ทธ๋‹ˆ์ฒ˜๊ฐ€ ์ž˜ ์„ค๊ณ„๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

ํ•จ์ˆ˜๊ฐ€ internal๋กœ ์ ์ ˆํžˆ ์ œํ•œ๋˜์–ด ์žˆ๊ณ , ๋งค๊ฐœ๋ณ€์ˆ˜ ๊ตฌ์กฐ๋„ ๋ช…ํ™•ํ•ฉ๋‹ˆ๋‹ค. Modifier๋ฅผ ๊ธฐ๋ณธ๊ฐ’๊ณผ ํ•จ๊ป˜ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์€ Compose ๋ชจ๋ฒ” ์‚ฌ๋ก€๋ฅผ ๋”ฐ๋ฆ…๋‹ˆ๋‹ค.


28-39: ํ…์ŠคํŠธ ์ปดํฌ๋„ŒํŠธ ๊ตฌํ˜„์ด ์ ์ ˆํ•ฉ๋‹ˆ๋‹ค.

์žฅ์†Œ ์ด๋ฆ„๊ณผ ์ฃผ์†Œ๊ฐ€ ๋ช…ํ™•ํ•œ ํƒ€์ดํฌ๊ทธ๋ž˜ํ”ผ ๊ณ„์ธต ๊ตฌ์กฐ๋กœ ํ‘œ์‹œ๋˜๋ฉฐ, SolplyTheme์„ ํ†ตํ•ด ์ผ๊ด€๋œ ์Šคํƒ€์ผ๋ง์ด ์ ์šฉ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ํ…์ŠคํŠธ ๊ฐ„ 7.dp ๊ฐ„๊ฒฉ๋„ ์ ์ ˆํ•ฉ๋‹ˆ๋‹ค.

feature/search/src/main/java/com/teamsolply/solply/search/SearchContract.kt (3)

23-23: ๆ–ฐใ—ใ„intentใฎใƒใƒณใƒ‰ใƒชใƒณใ‚ฐใƒญใ‚ธใƒƒใ‚ฏใฏๆญฃใ—ใๅฎŸ่ฃ…ใ•ใ‚Œใฆใ„ใพใ™ใ€‚

๊ฒ€์ฆ ๊ฒฐ๊ณผ, RegisterPlaceClick intent๋Š” SearchViewModel์˜ 39๋ฒˆ ์ค„์—์„œ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ฒ˜๋ฆฌ๋˜๊ณ  ์žˆ์œผ๋ฉฐ, NavigateToRegisterPlace side effect๋ฅผ ๋ฐœ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค. SearchScreen.kt์—์„œ intent๊ฐ€ ์ œ๋Œ€๋กœ ์ „์†ก๋˜๊ณ  ์žˆ์œผ๋ฏ€๋กœ ์ถ”๊ฐ€ ์ˆ˜์ •์ด ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.


30-36: ๋„ค๋น„๊ฒŒ์ด์…˜ ๊ตฌํ˜„ ํ™•์ธ๋จ - ๋ชจ๋“  ์š”์†Œ๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ตฌํ˜„๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฒ€์ฆ ๊ฒฐ๊ณผ, ์ƒˆ๋กœ์šด SearchSideEffect์˜ ๋ชจ๋“  ๋„ค๋น„๊ฒŒ์ด์…˜์ด ์™„์ „ํ•˜๊ฒŒ ๊ตฌํ˜„๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค:

  • NavigateToRegisterPlace๋Š” SearchViewModel์—์„œ ๋ฐœํ–‰๋˜๊ณ  SearchScreen์—์„œ navigateToRegisterPlace() ํ˜ธ์ถœ๋กœ ์ฒ˜๋ฆฌ๋จ
  • NavigateToPlaceDetail์€ placeId, townId ํŒŒ๋ผ๋ฏธํ„ฐ์™€ ํ•จ๊ป˜ SearchViewModel์—์„œ ๋ฐœํ–‰๋˜๊ณ  SearchScreen์—์„œ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ „๋‹ฌ๋จ
  • ๋Œ€์ƒ ํ™”๋ฉด(RegisterPlaceScreen, PlaceDetail)์ด ์กด์žฌํ•˜๊ณ  ๋„ค๋น„๊ฒŒ์ด์…˜ ํ•จ์ˆ˜๊ฐ€ ๊ตฌํ˜„๋˜์–ด ์žˆ์Œ

24-27: PlaceDetailClick intent๋Š” ์ ์ ˆํžˆ ๊ตฌํ˜„๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฒ€์ฆ ๊ฒฐ๊ณผ:

  1. โœ… ViewModel ํ•ธ๋“ค๋Ÿฌ ๊ตฌํ˜„๋จ (SearchViewModel.kt 40-45์ค„)
  2. โœ… ๋‘ ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ์ผ๊ด€๋˜๊ฒŒ ์‚ฌ์šฉ๋จ (Intent โ†’ ViewModel โ†’ SideEffect ์ฒด์ธ)
  3. โš ๏ธ ๋‹ค๋ฅธ ๋ชจ๋“ˆ๊ณผ์˜ ๋ถˆ์ผ์น˜: Maps ๋ชจ๋“ˆ์˜ PlaceDetailClick์€ placeId๋งŒ ์‚ฌ์šฉํ•˜๋ฉฐ, SearchSideEffect์˜ NavigateToPlaceDetail๋„ placeId๋งŒ ์ „๋‹ฌํ•˜๋Š” ๋ชจ๋“ˆ ๊ฐ„ ํŒจํ„ด์ด ๋‹ค๋ฆ…๋‹ˆ๋‹ค.

ํ˜„์žฌ ๊ตฌํ˜„์€ Search ๋ชจ๋“ˆ ๋‚ด์—์„œ ์ผ๊ด€์„ฑ ์žˆ๊ฒŒ ์ž‘๋™ํ•˜์ง€๋งŒ, ํ”Œ๋ ˆ์ด์Šค ์ƒ์„ธ ํ™”๋ฉด์— ์‹ค์ œ๋กœ townId๊ฐ€ ํ•„์š”ํ•œ์ง€ ํ™•์ธํ•˜๊ณ , ๋‹ค๋ฅธ ๋ชจ๋“ˆ๋“ค(Place, Course, Mypage)์˜ ๋™์ผํ•œ intent ํŒจํ„ด๊ณผ์˜ ์ผ๊ด€์„ฑ์„ ๊ฒ€ํ† ํ•˜์‹œ๊ธฐ๋ฅผ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.

feature/place/build.gradle.kts (1)

9-14: ์˜์กด์„ฑ ๊ตฌ์„ฑ ๊ฒ€ํ† 

์˜์กด์„ฑ์ด ์˜ฌ๋ฐ”๋ฅธ ์ˆœ์„œ์™€ ํ˜•์‹์œผ๋กœ ๋ฐฐ์—ด๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ๊ธฐ์กด ๊ตฌ์กฐ(domain.place, feature.search)์™€ ์ผ๊ด€์„ฑ ์žˆ๊ฒŒ ์ƒˆ๋กœ์šด ์˜์กด์„ฑ์ด ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

feature/maps/src/main/java/com/teamsolply/solply/maps/MapsViewModel.kt (1)

5-5: Import ๊ฒฝ๋กœ ๋ณ€๊ฒฝ์ด ์ •์ƒ์ ์œผ๋กœ ์™„๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๊ฒ€์ฆ ๊ฒฐ๊ณผ:

  • getFileName: ํ™•์žฅ ํ•จ์ˆ˜๋กœ core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/card/RegisterPlaceImage.kt (line 115)์— ์กด์žฌํ•˜๋ฉฐ, MapsViewModel์˜ line 538์—์„œ ์ •์ƒ์ ์œผ๋กœ ์‚ฌ์šฉ ์ค‘์ž…๋‹ˆ๋‹ค.
  • uploadToPresignedUrl: core/ui/src/main/java/com/teamsolply/solply/ui/util/PresignedUrlUploader.kt (line 36)์— ์กด์žฌํ•˜๋ฉฐ, import์ด ์ •์ƒ์ ์œผ๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.
  • ๊ธฐ์กด maps.util ๊ฒฝ๋กœ์˜ ํ•จ์ˆ˜๋“ค์€ ๋ชจ๋‘ ์ œ๊ฑฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/textfield/SolplyTextField.kt (6)

67-67: LGTM! ํŒจ๋”ฉ์„ ํŒŒ๋ผ๋ฏธํ„ฐํ™”ํ•˜์—ฌ ์œ ์—ฐ์„ฑ ํ–ฅ์ƒ

innerPadding ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ๊ฐ ํ…์ŠคํŠธ ํ•„๋“œ๊ฐ€ ์ž์ฒด ํŒจ๋”ฉ์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ฐœ์„ ํ–ˆ์Šต๋‹ˆ๋‹ค. BaseTextField๊ฐ€ private์ด๋ฏ€๋กœ ์ด ๋ณ€๊ฒฝ์€ ํŒŒ์ผ ๋‚ด๋ถ€์—๋งŒ ์˜ํ–ฅ์„ ๋ฏธ์น˜๋ฉฐ ์•ˆ์ „ํ•ฉ๋‹ˆ๋‹ค.

Also applies to: 83-83


208-208: LGTM! innerPadding ๊ฐ’ ์ „๋‹ฌ ํ™•์ธ

BaseTextField์— ์ ์ ˆํ•œ ํŒจ๋”ฉ ๊ฐ’์„ ์ „๋‹ฌํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.


351-353: shape ๋ฐ padding ๋ณ€๊ฒฝ์‚ฌํ•ญ ํ™•์ธ ํ•„์š”

๋‹ค์Œ UI ๋ณ€๊ฒฝ์‚ฌํ•ญ์ด ๋””์ž์ธ ์š”๊ตฌ์‚ฌํ•ญ๊ณผ ์ผ์น˜ํ•˜๋Š”์ง€ ํ™•์ธ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค:

  • RoundedCornerShape์ด 20.dp์—์„œ 16.dp๋กœ ๋ณ€๊ฒฝ๋จ
  • ์™ธ๋ถ€ ํŒจ๋”ฉ์ด ์ƒˆ๋กœ ์ถ”๊ฐ€๋จ (start: 21.dp, top: 17.dp, end: 21.dp, bottom: 17.dp)

์ด๋Ÿฌํ•œ ๋ณ€๊ฒฝ์€ ํ…์ŠคํŠธ ํ•„๋“œ์˜ ์ „์ฒด์ ์ธ ์‹œ๊ฐ์  ์™ธ๊ด€๊ณผ ๋ ˆ์ด์•„์›ƒ์— ์˜ํ–ฅ์„ ๋ฏธ์นฉ๋‹ˆ๋‹ค.


397-397: placeholder ํ…์ŠคํŠธ ๋ณ€๊ฒฝ ํ™•์ธ

placeholder ํ…์ŠคํŠธ์—์„œ ๊ด„ํ˜ธ๊ฐ€ ์ œ๊ฑฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค ("(์ตœ๋Œ€ 200์ž ์ž…๋ ฅ ๊ฐ€๋Šฅ)" โ†’ "์ตœ๋Œ€ 200์ž ์ž…๋ ฅ ๊ฐ€๋Šฅ"). ์ด๊ฒƒ์ด ์˜๋„๋œ UI ํ…์ŠคํŠธ ๋ณ€๊ฒฝ์ธ์ง€ ํ™•์ธํ•˜์„ธ์š”.


336-337: onFocusChanged ํŒŒ๋ผ๋ฏธํ„ฐ ์ถ”๊ฐ€ ๊ฒ€์ฆ ์™„๋ฃŒ

SolplyFixedReportTextField์˜ ์ƒˆ๋กœ์šด onFocusChanged ์ฝœ๋ฐฑ ํŒŒ๋ผ๋ฏธํ„ฐ๋Š” ๊ธฐ๋ณธ๊ฐ’ = {}์„ ๊ฐ€์ง€๊ณ  ์žˆ์–ด ํ•˜์œ„ ํ˜ธํ™˜์„ฑ์ด ์œ ์ง€๋ฉ๋‹ˆ๋‹ค.

  • RegisterPlaceScreen.kt (407-410): ํฌ์ปค์Šค ๋ณ€๊ฒฝ ์‹œ ์Šคํฌ๋กค ์ด๋™์„ ์ฒ˜๋ฆฌํ•˜์—ฌ ์ƒˆ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ ๊ทน ํ™œ์šฉ ์ค‘
  • WithdrawScreen.kt (148-150): ๊ธฐ์กด ์ฝ”๋“œ ์œ ์ง€, ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ์ž๋™ ์ฒ˜๋ฆฌ
  • ReportPlaceDialog.kt (302-304): ๊ธฐ์กด ์ฝ”๋“œ ์œ ์ง€, ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ์ž๋™ ์ฒ˜๋ฆฌ

๊ธฐ์กด ํ˜ธ์ถœ๋ถ€๋Š” ๋ณ€๊ฒฝ ์—†์ด ์ž‘๋™ํ•˜๋ฉฐ, ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์ด ํ•„์š”ํ•œ ๊ณณ์—์„œ ์„ ํƒ์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


314-314: innerPadding ํŒŒ๋ผ๋ฏธํ„ฐ ์ถ”๊ฐ€๋กœ ์ปค์Šคํ„ฐ๋งˆ์ด์ง• ๊ฐ€๋Šฅ

๊ธฐ๋ณธ๊ฐ’์ด ์žˆ๋Š” innerPadding ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ํ˜ธ์ถœ ์ธก์—์„œ ํ•„์š” ์‹œ ์ปค์Šคํ…€ ํŒจ๋”ฉ์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ธฐ์กด ํ˜ธ์ถœ ์ฝ”๋“œ์™€์˜ ํ˜ธํ™˜์„ฑ๋„ ์œ ์ง€๋ฉ๋‹ˆ๋‹ค. ๋ชจ๋“  ํ˜ธ์ถœ ๋ถ€(SearchScreen, RegisterPlaceScreen, RenameCourseBottomSheet)๊ฐ€ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ์ •์ƒ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

core/ui/src/main/java/com/teamsolply/solply/ui/util/PresignedUrlUploader.kt (2)

1-1: ํŒจํ‚ค์ง€ ๋ฆฌํŒฉํ† ๋ง์ด ์ ์ ˆํ•ฉ๋‹ˆ๋‹ค.

maps.util์—์„œ ui.util๋กœ์˜ ํŒจํ‚ค์ง€ ์ด๋™์€ ๋ชจ๋“ˆ ๊ตฌ์กฐ ๊ฐœ์„ ์— ๋ถ€ํ•ฉํ•ฉ๋‹ˆ๋‹ค.


13-19: LGTM!

Uri์˜ ์ปจํ…์ธ  ๊ธธ์ด๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ์กฐํšŒํ•˜๋Š” ๋กœ์ง์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ตฌํ˜„๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

feature/maps/src/main/java/com/teamsolply/solply/maps/component/dialog/ReportPlaceDialog.kt (1)

322-341: ์žฌ์‚ฌ์šฉ ์ปดํฌ๋„ŒํŠธ ์—ฐ๋™ ํ™•์ธ
RegisterPlaceImage๋กœ ๊ต์ฒดํ•˜๋ฉด์„œ onAddClick ๋ถ„๊ธฐ(๋‹ค์ค‘/๋‹จ์ผ ์„ ํƒ)์™€ remainSelectedUris ๊ณ„์‚ฐ์ด ๊ทธ๋Œ€๋กœ ์œ ์ง€๋ผ ์„ ํƒ ํ๋ฆ„์ด ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์ด์–ด์ง€๋Š” ์  ์ข‹์Šต๋‹ˆ๋‹ค. ๋””์ž์ธ ์‹œ์Šคํ…œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ฒฝ๋กœ๋งŒ ๋ฐ”๊ฟ” ์žฌํ™œ์šฉํ•œ ๋•๋ถ„์— UI ๊ฐ„๊ฒฉ๋„ ๊ธฐ์กด ๋ ˆ์ด์•„์›ƒ๊ณผ ์ž˜ ๋งž๋„ค์š”.

feature/main/build.gradle.kts (1)

18-18: LGTM!

๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ ๋ชจ๋“ˆ ์˜์กด์„ฑ ์ถ”๊ฐ€๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ํŒŒ์ผ๋“ค์˜ ๊ฒ€์ƒ‰ ๋„ค๋น„๊ฒŒ์ด์…˜ ํ†ตํ•ฉ๊ณผ ์ผ์น˜ํ•ฉ๋‹ˆ๋‹ค.

feature/search/build.gradle.kts (2)

11-11: LGTM!

์ง€๋„ ๋„๋ฉ”์ธ ์˜์กด์„ฑ ์ถ”๊ฐ€๊ฐ€ ์ ์ ˆํ•ฉ๋‹ˆ๋‹ค. ์žฅ์†Œ ์ƒ์„ธ ์ •๋ณด ๋ฐ ์ง€๋„ ํ†ตํ•ฉ์„ ์œ„ํ•ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.


12-13: Lottie ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์‚ฌ์šฉ์ด ํ™•์ธ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๊ฒ€์ฆ ๊ฒฐ๊ณผ, feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceScreen.kt์—์„œ Lottie ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์‹ค์ œ๋กœ ์‚ฌ์šฉ ์ค‘์ž…๋‹ˆ๋‹ค. RegisterPlaceScreen์—์„œ LottieAnimation, LottieCompositionSpec, LottieConstants, animateLottieCompositionAsState, rememberLottieComposition ๋“ฑ์˜ Lottie Compose API๋ฅผ importํ•˜๊ณ  ํ™œ์šฉํ•˜๊ณ  ์žˆ์œผ๋ฏ€๋กœ ์ถ”๊ฐ€๋œ ์˜์กด์„ฑ์€ ์ •๋‹นํ•˜๋ฉฐ ๋นŒ๋“œ์—์„œ ํ•„์š”ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ž…๋‹ˆ๋‹ค.

core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/header/SolplyHomeHeader.kt (2)

79-79: LGTM!

์ฝœ๋ฐฑ ํ˜ธ์ถœ์ด ์ƒˆ๋กœ์šด ์‹œ๊ทธ๋‹ˆ์ฒ˜์— ๋งž๊ฒŒ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์—…๋ฐ์ดํŠธ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.


23-28: ์ฝœ๋ฐฑ ์‹œ๊ทธ๋‹ˆ์ฒ˜ ๋ณ€๊ฒฝ ๊ฒ€์ฆ ์™„๋ฃŒ - ๋ชจ๋“  ํ˜ธ์ถœ ์ง€์ ์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์—…๋ฐ์ดํŠธ๋จ

์ „์ฒด ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ, SolplyHomeHeader ํ•จ์ˆ˜์˜ ํ˜ธ์ถœ ์ง€์ ์€ ์ •ํ™•ํžˆ 2๊ณณ์ž…๋‹ˆ๋‹ค:

  • feature/course/src/main/java/com/teamsolply/solply/course/CourseScreen.kt:102 - โœ“ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์—…๋ฐ์ดํŠธ๋จ
  • feature/place/src/main/java/com/teamsolply/solply/place/PlaceScreen.kt:215 - โœ“ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์—…๋ฐ์ดํŠธ๋จ

๋‘ ํ˜ธ์ถœ ์ง€์  ๋ชจ๋‘ changeSearchDialogVisibility ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ „๋‹ฌํ•˜๊ณ  ์žˆ์œผ๋ฉฐ, ์ƒˆ๋กœ์šด () -> Unit ์‹œ๊ทธ๋‹ˆ์ฒ˜์™€ ์ผ์น˜ํ•ฉ๋‹ˆ๋‹ค. ์ฝœ๋ฐฑ ์‹œ๊ทธ๋‹ˆ์ฒ˜ ๋ณ€๊ฒฝ์ด ๋ชจ๋“  ํ˜ธ์ถœ ์ง€์ ์—์„œ ์ผ๊ด€๋˜๊ฒŒ ์ ์šฉ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

data/search/src/main/java/com/teamsolply/solply/search/dto/response/SearchResponseDto.kt (2)

12-28: LGTM!

SearchResult์— townId ํ•„๋“œ ์ถ”๊ฐ€๊ฐ€ ์ ์ ˆํ•˜๊ฒŒ ๊ตฌํ˜„๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋„๋ฉ”์ธ ๋ชจ๋ธ์˜ SearchResultEntity ๋ณ€๊ฒฝ์‚ฌํ•ญ๊ณผ ์ผ์น˜ํ•ฉ๋‹ˆ๋‹ค.


1-1: ํŒจํ‚ค์ง€ ๊ฒฝ๋กœ ๋ณ€๊ฒฝ์ด ์™„์ „ํžˆ ์ ์šฉ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ถ”๊ฐ€ ์กฐ์น˜๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๊ฒ€์ฆ ๊ฒฐ๊ณผ, SearchResponseDto์˜ ๋ชจ๋“  import๊ฐ€ ์ƒˆ๋กœ์šด ํŒจํ‚ค์ง€ ๊ฒฝ๋กœ(com.teamsolply.solply.search.dto.response)๋กœ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์—…๋ฐ์ดํŠธ๋˜์—ˆ์Šต๋‹ˆ๋‹ค:

  • โœ“ SearchService.kt (line 6)
  • โœ“ SearchRemoteDataSourceImpl.kt (line 4)
  • โœ“ SearchRemoteDataSource.kt (line 5)

์ด์ „ ํŒจํ‚ค์ง€ ๊ฒฝ๋กœ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” import๋Š” ๋ฐœ๊ฒฌ๋˜์ง€ ์•Š์•˜์œผ๋ฏ€๋กœ, breaking change๊ฐ€ ์™„์ „ํžˆ ์ฒ˜๋ฆฌ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

feature/search/src/main/java/com/teamsolply/solply/search/navigation/SearchNavigation.kt (1)

1-33: LGTM!

๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ์„ ์œ„ํ•œ ๋„ค๋น„๊ฒŒ์ด์…˜ ๊ตฌ์กฐ๊ฐ€ ์ž˜ ๊ตฌํ˜„๋˜์—ˆ์Šต๋‹ˆ๋‹ค:

  • ํƒ€์ž… ์•ˆ์ „ ๋„ค๋น„๊ฒŒ์ด์…˜์„ ์œ„ํ•œ ์ง๋ ฌํ™” ๊ฐ€๋Šฅํ•œ ๋ผ์šฐํŠธ ๊ฐ์ฒด ์‚ฌ์šฉ
  • ์ ์ ˆํ•œ ์ฝœ๋ฐฑ ์ •์˜ (navigateToPlaceDetail, navigateToRegisterPlace, navigateToBack)
  • ๋‹ค๋ฅธ feature ๋ชจ๋“ˆ์˜ ๋„ค๋น„๊ฒŒ์ด์…˜ ํŒจํ„ด๊ณผ ์ผ๊ด€์„ฑ ์œ ์ง€
feature/place/src/main/java/com/teamsolply/solply/place/PlaceContract.kt (2)

72-82: LGTM!

PlaceSideEffect๊ฐ€ ์ƒˆ๋กœ์šด ๋„ค๋น„๊ฒŒ์ด์…˜ ํ”Œ๋กœ์šฐ๋ฅผ ์ง€์›ํ•˜๋„๋ก ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์—…๋ฐ์ดํŠธ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. NavigateToMap์€ ์œ ์ง€๋˜๋ฉด์„œ ๊ฒ€์ƒ‰๊ณผ ๊ด€์‹ฌ ๋™๋„ค ๋„ค๋น„๊ฒŒ์ด์…˜์„ ์œ„ํ•œ ์ƒˆ๋กœ์šด ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๊ฐ€ ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค.


39-70: ๋„ค๋น„๊ฒŒ์ด์…˜ ๊ธฐ๋ฐ˜ ๊ฒ€์ƒ‰ ๋ฆฌํŒฉํ† ๋ง์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ตฌํ˜„๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๊ฒ€์ฆ ๊ฒฐ๊ณผ, PlaceIntent์˜ ๋ณ€๊ฒฝ์‚ฌํ•ญ์ด PlaceViewModel๊ณผ PlaceScreen์—์„œ ์ผ๊ด€๋˜๊ฒŒ ์ฒ˜๋ฆฌ๋˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค:

  • PlaceViewModel.kt (๋ผ์ธ 142-148): ์ƒˆ๋กœ์šด ์ธํ…ํŠธ(NavigateToFavoriteTown, NavigateToSearch)๊ฐ€ ํ•ด๋‹น ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๋กœ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๋ณ€ํ™˜๋จ
  • PlaceScreen.kt (๋ผ์ธ 80-81, 112-118): ์ƒˆ๋กœ์šด ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๊ฐ€ ์ ์ ˆํ•˜๊ฒŒ ํ•ธ๋“ค๋ง๋จ
  • ์ด์ „ ๋‹ค์ด์–ผ๋กœ๊ทธ ๊ด€๋ จ ์ฝ”๋“œ(isSearchDialogVisible, ChangeSearchDialogVisibility)๊ฐ€ ์™„์ „ํžˆ ์ œ๊ฑฐ๋จ

๋ฆฌํŒฉํ† ๋ง์ด ์™„์ „ํ•˜๊ณ  ํ†ตํ•ฉ์ด ์ผ๊ด€์„ฑ ์žˆ๊ฒŒ ์ฒ˜๋ฆฌ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/FavoriteViewModel.kt (4)

26-43: LGTM!

loadTownTree ๋ฉ”์„œ๋“œ๊ฐ€ selectedTownId๋ฅผ ๋ฐ›์•„ ์ƒํƒœ์— ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์„ค์ •ํ•˜๋„๋ก ์—…๋ฐ์ดํŠธ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด์ œ ์ด์ „์— null๋กœ ๋ฆฌ์…‹๋˜๋˜ ๊ฒƒ์ด ์ „๋‹ฌ๋œ ๊ฐ’์„ ์œ ์ง€ํ•˜์—ฌ ์‚ฌ์šฉ์ž ์„ ํƒ์„ ๋ณด์กดํ•ฉ๋‹ˆ๋‹ค.


45-58: LGTM!

patchUserFavoriteTown์ด ์ด์ œ DismissWithResult ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๋ฅผ ๊ฒŒ์‹œํ•˜์—ฌ ์ ์ ˆํ•œ ๊ฒฐ๊ณผ ์ฒ˜๋ฆฌ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๋„ค๋น„๊ฒŒ์ด์…˜ ๊ฒฐ๊ณผ๋ฅผ ์ƒ์œ„ ํ™”๋ฉด์— ์ „๋‹ฌํ•˜๋Š” ํ‘œ์ค€ ํŒจํ„ด์ž…๋‹ˆ๋‹ค.


15-15: FavoriteTownSideEffect ํƒ€์ž… ๋ณ€๊ฒฝ ๊ฒ€์ฆ ์™„๋ฃŒ - ๋ฌธ์ œ ์—†์Œ

๊ฒ€์ฆ ๊ฒฐ๊ณผ, FavoriteTownSideEffect๋Š” FavoriteTownContract.kt์—์„œ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ •์˜๋˜์–ด ์žˆ์œผ๋ฉฐ, ๋ชจ๋“  ์‚ฌ์šฉ์ฒ˜์—์„œ ํƒ€์ž…์ด ์ผ์น˜ํ•ฉ๋‹ˆ๋‹ค:

  • FavoriteViewModel.kt:15 - BaseViewModel ์ œ๋„ค๋ฆญ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์‚ฌ์šฉ
  • FavoriteViewModel.kt:53 - DismissWithResult ํƒ€์ž…์œผ๋กœ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ „๋‹ฌ
  • FavoriteTownRoute.kt:56 - ์˜ฌ๋ฐ”๋ฅธ ํƒ€์ž…์œผ๋กœ ์ฒ˜๋ฆฌ

ํƒ€์ž… ๋ณ€๊ฒฝ์ด ์ผ๊ด€์„ฑ ์žˆ๊ฒŒ ์ ์šฉ๋˜์—ˆ์œผ๋ฏ€๋กœ ์ถ”๊ฐ€ ์กฐ์น˜๋Š” ๋ถˆํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.


17-24: ๊ฒ€์ฆ ์™„๋ฃŒ - ๋ชจ๋“  ํ˜ธ์ถœ ์ง€์ ์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ตฌํ˜„๋จ

LoadFavoriteTownList ํ˜ธ์ถœ์„ ํ™•์ธํ•œ ๊ฒฐ๊ณผ:

  • FavoriteTownRoute.kt:62์—์„œ ์œ ์ผํ•˜๊ฒŒ ์ƒ์„ฑ๋˜๋ฉฐ, selectedTownId ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ์ „๋‹ฌ
  • loadTownTree() ๋ฉ”์„œ๋“œ ์„œ๋ช…๊ณผ ์ธํ…ํŠธ ์ •์˜์˜ ํŒŒ๋ผ๋ฏธํ„ฐ ํƒ€์ž…(Long?)์ด ์ผ์น˜
  • FavoriteTownRoute ์ปดํฌ์ €๋ธ” ํŒŒ๋ผ๋ฏธํ„ฐ์—์„œ selectedTownId๋ฅผ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ˆ˜์‹ ํ•˜์—ฌ ์ „๋‹ฌ

์ฝ”๋“œ ๋ณ€๊ฒฝ์ด ์•ˆ์ „ํ•˜๊ณ  ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ตฌํ˜„๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

domain/search/src/main/java/com/teamsolply/solply/search/model/SearchResultEntity.kt (1)

5-13: townId ํ•„๋“œ ์ถ”๊ฐ€ ํ™•์ธ ์™„๋ฃŒ - ๋ชจ๋“  ์ƒ์„ฑ ์ง€์ ์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์—…๋ฐ์ดํŠธ๋จ

๊ฒ€์ฆ ๊ฒฐ๊ณผ, SearchResultEntity์˜ ์ƒˆ๋กœ์šด ํ•„์ˆ˜ ํ•„๋“œ townId๊ฐ€ ๋ชจ๋“  ์ƒ์„ฑ ์ง€์ ์—์„œ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ฒ˜๋ฆฌ๋˜์—ˆ์Šต๋‹ˆ๋‹ค:

  • SearchRepositoryImpl.kt (line 31): townId = searchResult.townId๋กœ ์„ค์ • โœ“
  • ๋‹ค๋ฅธ ์ƒ์„ฑ ์ง€์ : ์—†์Œ (SearchRepository, SearchContract๋Š” ์ธํ„ฐํŽ˜์ด์Šค/๋ฐ์ดํ„ฐ ํด๋ž˜์Šค๋งŒ ์ •์˜)
  • Factory/Builder ํŒจํ„ด: ์—†์Œ
  • ํ…Œ์ŠคํŠธ ํ”ฝ์Šค์ฒ˜: ์—†์Œ

Breaking change๊ฐ€ ์™„์ „ํ•˜๊ณ  ์ผ๊ด€๋˜๊ฒŒ ์ ์šฉ๋˜์—ˆ์œผ๋ฏ€๋กœ, ์ฝ”๋“œ ๋ณ€๊ฒฝ์‚ฌํ•ญ์ด ์•ˆ์ •์ ์ž…๋‹ˆ๋‹ค.

feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/FavoriteTownContract.kt (2)

22-25: LGTM! ๋„ค๋น„๊ฒŒ์ด์…˜ ๊ฐœ์„ ์ด ์ž˜ ๋ฐ˜์˜๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

LoadFavoriteTownList์— selectedTownId ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ์ดˆ๊ธฐ ์„ ํƒ ์ƒํƒœ๋ฅผ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๊ณ , ConfirmSelection์„ data object๋กœ ๋ณ€๊ฒฝํ•œ ๊ฒƒ์ด ์ ์ ˆํ•ฉ๋‹ˆ๋‹ค.


28-30: LGTM! ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ ๊ตฌ์กฐ๊ฐ€ ๊ฐœ์„ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

ํƒ€์ž…๋ช…์„ FavoriteTownSideEffect๋กœ ๋ณ€๊ฒฝํ•˜์—ฌ ๋ช…ํ™•์„ฑ์„ ๋†’์˜€๊ณ , DismissWithResult๋ฅผ ํ†ตํ•ด ์„ ํƒ๋œ ํƒ€์šด ID๋ฅผ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์–ด ๋„ค๋น„๊ฒŒ์ด์…˜ ๊ฒฐ๊ณผ ์ฒ˜๋ฆฌ๊ฐ€ ๊ฐœ์„ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

data/place/src/main/java/com/teamsolply/solply/place/mapper/PlaceEntityMapper.kt (1)

11-11: LGTM! DTO ํ•„๋“œ๋ช… ๋ณ€๊ฒฝ๊ณผ ์ผ์น˜ํ•ฉ๋‹ˆ๋‹ค.

PlaceDto์˜ ํ•„๋“œ๋ช…์ด primaryTag์—์„œ mainTag๋กœ ๋ณ€๊ฒฝ๋œ ๊ฒƒ์— ๋งž์ถฐ ๋งคํ•‘์„ ์—…๋ฐ์ดํŠธํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ํŒŒ์ผ๋“ค๊ณผ์˜ ์ผ๊ด€์„ฑ์ด ์œ ์ง€๋˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

feature/place/src/main/java/com/teamsolply/solply/place/PlaceViewModel.kt (3)

65-70: LGTM! ๊ฐ€๋…์„ฑ์ด ๊ฐœ์„ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์—ฌ๋Ÿฌ ์ค„๋กœ ํฌ๋งทํŒ…ํ•˜์—ฌ ์ฝ”๋“œ ๊ฐ€๋…์„ฑ์ด ํ–ฅ์ƒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.


142-143: LGTM! ๊ฒ€์ƒ‰ ๋„ค๋น„๊ฒŒ์ด์…˜์ด ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๊ฒ€์ƒ‰ ๋‹ค์ด์–ผ๋กœ๊ทธ ๋ฐฉ์‹์—์„œ ๋„ค๋น„๊ฒŒ์ด์…˜ ๊ธฐ๋ฐ˜ ์ ‘๊ทผ ๋ฐฉ์‹์œผ๋กœ ๋ณ€๊ฒฝ๋˜์–ด ๊ตฌ์กฐ๊ฐ€ ๊ฐœ์„ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.


144-148: LGTM! ๊ด€์‹ฌ ํƒ€์šด ๋„ค๋น„๊ฒŒ์ด์…˜ ์ฒ˜๋ฆฌ๊ฐ€ ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

selectedTownId๋ฅผ ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๋กœ ์ „๋‹ฌํ•˜์—ฌ ์ดˆ๊ธฐ ์„ ํƒ ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. FavoriteTownContract์˜ ๋ณ€๊ฒฝ์‚ฌํ•ญ๊ณผ ์ž˜ ์—ฐ๋™๋ฉ๋‹ˆ๋‹ค.

feature/main/src/main/AndroidManifest.xml (1)

9-9: LGTM! ํ‚ค๋ณด๋“œ ์ฒ˜๋ฆฌ๊ฐ€ ๊ฐœ์„ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

adjustResize ์„ค์ •์œผ๋กœ ์†Œํ”„ํŠธ ํ‚ค๋ณด๋“œ๊ฐ€ ๋‚˜ํƒ€๋‚  ๋•Œ ํ™”๋ฉด์ด ์ž๋™์œผ๋กœ ์กฐ์ •๋˜์–ด, ์ž…๋ ฅ ํ•„๋“œ๊ฐ€ ๊ฐ€๋ ค์ง€์ง€ ์•Š๋„๋ก ํ•ฉ๋‹ˆ๋‹ค. ๊ฒ€์ƒ‰ ๋ฐ ์ž…๋ ฅ ๊ธฐ๋Šฅ ์ถ”๊ฐ€์™€ ์ž˜ ๋งž๋Š” ์„ค์ •์ž…๋‹ˆ๋‹ค.

core/designsystem/src/main/res/drawable/ic_arrow_down_lg.xml (1)

7-11: LGTM! ๋“œ๋กญ๋‹ค์šด ์•„์ด์ฝ˜ ๋””์ž์ธ์ด ๊ฐœ์„ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

ํ™”์‚ดํ‘œ๊ฐ€ ๋” ํฌ๊ณ  ๋‘๊ป๊ฒŒ ๋ณ€๊ฒฝ๋˜์—ˆ์œผ๋ฉฐ, ์ƒ‰์ƒ์ด ๋ฐ์€ ํšŒ์ƒ‰์œผ๋กœ ์กฐ์ •๋˜์–ด ์‹œ๊ฐ์  ๊ฐœ์„ ์ด ์ด๋ฃจ์–ด์กŒ์Šต๋‹ˆ๋‹ค. SolplyBasicDropDown ์ปดํฌ๋„ŒํŠธ ์—…๋ฐ์ดํŠธ์™€ ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.

data/place/src/main/java/com/teamsolply/solply/place/repository/PlaceRepositoryImpl.kt (2)

74-87: LGTM! ํ•„๋“œ ๋งคํ•‘์ด ์ผ๊ด€๋˜๊ฒŒ ์—…๋ฐ์ดํŠธ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

RecommendPlaceInfo.primaryTag๊ฐ€ it.mainTag์—์„œ ๋งคํ•‘๋˜๋„๋ก ๋ณ€๊ฒฝ๋˜์–ด, DTO ํ•„๋“œ๋ช… ๋ณ€๊ฒฝ๊ณผ ์ผ์น˜ํ•ฉ๋‹ˆ๋‹ค.


89-112: LGTM! ํ•„๋“œ ๋งคํ•‘์ด ์ผ๊ด€๋˜๊ฒŒ ์—…๋ฐ์ดํŠธ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

PlaceEntity.primaryTag๊ฐ€ dto.mainTag์—์„œ ๋งคํ•‘๋˜๋„๋ก ๋ณ€๊ฒฝ๋˜์–ด, DTO ํ•„๋“œ๋ช… ๋ณ€๊ฒฝ๊ณผ ์ผ์น˜ํ•ฉ๋‹ˆ๋‹ค. ๋ชจ๋“  ๋ ˆ์ด์–ด์—์„œ ์ผ๊ด€๋œ ๋ณ€๊ฒฝ์ด ์™„๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

core/model/src/main/java/com/teamsolply/solply/model/PlaceType.kt (1)

16-24: ๋ฐฑ์—”๋“œ API ๊ณ„์•ฝ๊ณผ์˜ ID ๋งคํ•‘ ๊ฒ€์ฆ ํ•„์š” (UI ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋กœ ์ธํ•œ ์œ„ํ—˜๋„ ์™„ํ™”)

PlaceType.toId() ํ•จ์ˆ˜๋Š” UI ๊ฒ€์ฆ ๋กœ์ง์— ์˜ํ•ด ๋ณดํ˜ธ๋˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. RegisterPlaceScreen:340์—์„œ ALL์„ ํ•„ํ„ฐ๋งํ•˜๊ณ , ๋ฒ„ํŠผ์€ selectedPlaceType์ด null์ด ์•„๋‹ ๋•Œ๋งŒ ํ™œ์„ฑํ™”๋˜๋ฏ€๋กœ -1 ๋ฐ˜ํ™˜ ์ผ€์ด์Šค๋Š” ์‹ค์ œ ์‹คํ–‰ ํ๋ฆ„์—์„œ ๋„๋‹ฌํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ํ•˜๋“œ์ฝ”๋”ฉ๋œ ID ๋งคํ•‘(1-6)์ด ๋ฐฑ์—”๋“œ API ์ŠคํŽ™๊ณผ ์ •ํ™•ํžˆ ์ผ์น˜ํ•˜๋Š”์ง€ ์—ฌ์ „ํžˆ ํ™•์ธ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์ฝ”๋“œ๋ฒ ์ด์Šค ๋‚ด์—์„œ ๋ฐฑ์—”๋“œ API ๊ณ„์•ฝ ๋ฌธ์„œ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์œผ๋ฏ€๋กœ ์ˆ˜๋™ ๊ฒ€์ฆ์ด ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค.

์ถ”๊ฐ€๋กœ, ID ๋งคํ•‘์˜ ์ถœ์ฒ˜๋ฅผ ๋ช…์‹œํ•˜๋Š” ๋ฌธ์„œํ™”๋ฅผ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค:

/**
 * PlaceType์„ ๋ฐฑ์—”๋“œ API ID๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
 * ๋งคํ•‘ ๊ธฐ์ค€: [๋ฐฑ์—”๋“œ API ์ŠคํŽ™ URL ๋˜๋Š” ๋ฌธ์„œ ์ฐธ์กฐ]
 * 
 * @return ๋ฐฑ์—”๋“œ API ์ŠคํŽ™์— ์ •์˜๋œ ์žฅ์†Œ ํƒ€์ž… ID (1-6)
 *         ALL์ด๊ฑฐ๋‚˜ null์ธ ๊ฒฝ์šฐ๋Š” UI ๊ฒ€์ฆ์œผ๋กœ ์ธํ•ด ๋„๋‹ฌ ๋ถˆ๊ฐ€
 */
fun PlaceType?.toId(): Long = when (this) {
    // ...
}
feature/course/src/main/java/com/teamsolply/solply/course/CourseViewModel.kt (1)

43-49: LGTM! ๋„ค๋น„๊ฒŒ์ด์…˜ ๋กœ์ง์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ตฌํ˜„๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์ƒˆ๋กœ์šด ๋„ค๋น„๊ฒŒ์ด์…˜ ์ธํ…ํŠธ๋“ค์ด ์ ์ ˆํ•˜๊ฒŒ ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๊ณ  ์žˆ์œผ๋ฉฐ, BaseViewModel ํŒจํ„ด์„ ์ผ๊ด€๋˜๊ฒŒ ๋”ฐ๋ฅด๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

core/common/src/main/java/com/teamsolply/solply/common/buildconfig/BuildConfigFields.kt (1)

7-8: LGTM! BuildConfig ๋ณ€๊ฒฝ์‚ฌํ•ญ๊ณผ ์ผ๊ด€์„ฑ ์žˆ๊ฒŒ ํ•„๋“œ๊ฐ€ ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์ƒˆ๋กœ์šด ๋„ค์ด๋ฒ„ ๊ฐœ๋ฐœ์ž ์„ผํ„ฐ credential ํ•„๋“œ๋“ค์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

feature/mypage/src/main/java/com/teamsolply/solply/mypage/component/SolplyPersonaDropDown.kt (1)

39-46: LGTM! Composable ๊ธฐ๋ฐ˜ ๋ผ๋ฒจ๋กœ ๋ฆฌํŒฉํ† ๋ง๋˜์–ด ์œ ์—ฐ์„ฑ์ด ํ–ฅ์ƒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

defaultLabel์ด String์—์„œ Composable ๋žŒ๋‹ค๋กœ ๋ณ€๊ฒฝ๋˜์–ด, ๋ผ๋ฒจ์˜ ์Šคํƒ€์ผ๋ง ๋ฐ ๋ Œ๋”๋ง์„ ๋”์šฑ ์œ ์—ฐํ•˜๊ฒŒ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. SolplyBasicDropDown์˜ ์—…๋ฐ์ดํŠธ๋œ API์™€ ์ผ๊ด€์„ฑ ์žˆ๊ฒŒ ๊ตฌํ˜„๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

core/buildconfig/src/main/java/com/teamsolply/solply/buildconfig/impl/BuildConfigFieldsProviderImpl.kt (1)

6-7: LGTM! ์ƒˆ๋กœ์šด credential๋“ค์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์—ฐ๊ฒฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

NAVER_DEVELOPERS_CLIENT_ID์™€ NAVER_DEVELOPERS_CLIENT_SECRET์ด BuildConfigFields์— ์ ์ ˆํ•˜๊ฒŒ ์™€์ด์–ด๋ง๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

Also applies to: 18-19

data/place/src/main/java/com/teamsolply/solply/place/dto/response/GetRecommendPlaceDto.kt (1)

21-22: LGTM! GetPlacesResponseDto์™€ ์ผ๊ด€์„ฑ ์žˆ๊ฒŒ ํ•„๋“œ๋ช…์ด ๋ณ€๊ฒฝ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

primaryTag์—์„œ mainTag๋กœ์˜ ํ•„๋“œ๋ช… ๋ณ€๊ฒฝ์ด ๋‹ค๋ฅธ Place DTO๋“ค๊ณผ ์ผ๊ด€๋˜๊ฒŒ ์ ์šฉ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. GetPlacesResponseDto.kt์— ๋‚จ๊ธด ์ฝ”๋ฉ˜ํŠธ์™€ ๋™์ผํ•˜๊ฒŒ, ๋ฐฑ์—”๋“œ API ๋ณ€๊ฒฝ์‚ฌํ•ญ๊ณผ ๋™๊ธฐํ™”๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•ด์ฃผ์„ธ์š”.

feature/search/src/main/java/com/teamsolply/solply/search/SearchViewModel.kt (1)

39-45: LGTM!

์ƒˆ๋กœ์šด ์ธํ…ํŠธ ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ตฌํ˜„๋˜์—ˆ์Šต๋‹ˆ๋‹ค. RegisterPlaceClick๊ณผ PlaceDetailClick ์ธํ…ํŠธ๊ฐ€ ์ ์ ˆํ•œ ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๊ณ  ์žˆ์œผ๋ฉฐ, ๋„ค๋น„๊ฒŒ์ด์…˜ ํ”Œ๋กœ์šฐ๊ฐ€ ๋ช…ํ™•ํ•ฉ๋‹ˆ๋‹ค.

data/search/src/main/java/com/teamsolply/solply/search/dto/response/RegisterPlaceResponseDto.kt (1)

6-12: LGTM!

DTO ๊ตฌ์กฐ๊ฐ€ ๋ช…ํ™•ํ•˜๊ณ  ์ง๋ ฌํ™” ์–ด๋…ธํ…Œ์ด์…˜์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ ์šฉ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ํ•„๋“œ ํƒ€์ž…๋„ ์ ์ ˆํ•ฉ๋‹ˆ๋‹ค.

feature/course/src/main/java/com/teamsolply/solply/course/navigation/CourseNavigation.kt (1)

18-31: LGTM!

๋„ค๋น„๊ฒŒ์ด์…˜ ์ฝœ๋ฐฑ์ด ๋ช…ํ™•ํ•˜๊ฒŒ ๊ฐœ์„ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. navigateToFavoriteTown๊ณผ navigateToSearch ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ CourseRoute์˜ ์‹œ๊ทธ๋‹ˆ์ฒ˜์™€ ์ผ์น˜ํ•˜๋ฉฐ, ์ฝ”๋“œ ๊ฐ€๋…์„ฑ์ด ํ–ฅ์ƒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

domain/search/src/main/java/com/teamsolply/solply/search/repository/SearchRepository.kt (1)

10-11: LGTM!

์ƒˆ๋กœ์šด ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ๋ฉ”์„œ๋“œ๊ฐ€ ๊ธฐ์กด ํŒจํ„ด์„ ์ž˜ ๋”ฐ๋ฅด๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. Result ํƒ€์ž…์„ ์‚ฌ์šฉํ•œ ์—๋Ÿฌ ํ•ธ๋“ค๋ง๊ณผ ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์‚ฌ์šฉํ•œ ์ธํ„ฐํŽ˜์ด์Šค ์ •์˜๊ฐ€ ์ ์ ˆํ•ฉ๋‹ˆ๋‹ค.

remote/place/src/main/java/com/teamsolply/solply/place/service/PlaceService.kt (1)

32-33: ๋ฐฑ์—”๋“œ API ํŒŒ๋ผ๋ฏธํ„ฐ ์ด๋ฆ„์„ ํ™•์ธํ•˜์„ธ์š”.

์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ ์ด๋ฆ„์ด subTagAIdList/subTagBIdList์—์„œ subTag1Ids/subTag2Ids๋กœ ๋ณ€๊ฒฝ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๊ฐ€๋…์„ฑ ๊ฐœ์„ ์ด์ง€๋งŒ, ๋ฐฑ์—”๋“œ API๊ฐ€ ์ƒˆ๋กœ์šด ํŒŒ๋ผ๋ฏธํ„ฐ ์ด๋ฆ„์„ ์ง€์›ํ•˜๋Š”์ง€ ํ™•์ธ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. API ๊ณ„์•ฝ์ด ์ผ์น˜ํ•˜์ง€ ์•Š์œผ๋ฉด ๋Ÿฐํƒ€์ž„ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฐฑ์—”๋“œ ํŒ€๊ณผ ํ™•์ธํ•˜๊ฑฐ๋‚˜ API ๋ฌธ์„œ๋ฅผ ๊ฒ€ํ† ํ•˜์—ฌ ํŒŒ๋ผ๋ฏธํ„ฐ ์ด๋ฆ„์ด ์ผ์น˜ํ•˜๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”. ๊ฐ€๋Šฅํ•˜๋‹ค๋ฉด ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ๋ฅผ ํ†ตํ•ด ๊ฒ€์ฆํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.

core/network/src/main/java/com/teamsolply/solply/network/service/NaverLocalSearchService.kt (1)

7-15: ์ถ”๊ฐ€ ๊ฒ€์ฆ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ๋ฆฌ๋ทฐ ๋Œ“๊ธ€์—์„œ ์–ธ๊ธ‰ํ•œ "sim" ์ •๋ ฌ ์˜ต์…˜์ด Naver Local Search API์˜ ์œ ํšจํ•œ ์˜ต์…˜์ธ์ง€ ํ™•์ธํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

๊ธฐ๋ณธ ์ •๋ ฌ ์˜ต์…˜์€ API ์‚ฌ์–‘๊ณผ ์ผ์น˜ํ•ฉ๋‹ˆ๋‹ค.

Naver Local Search API์˜ ์ •๋ ฌ ์˜ต์…˜์€ "random"๊ณผ "comment" ๋‘ ๊ฐ€์ง€์ด๋ฉฐ, "random"์ด API์˜ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ๊ถŒ์žฅ๋˜๋Š” ์˜ต์…˜์ž…๋‹ˆ๋‹ค. ํ˜„์žฌ ์ฝ”๋“œ์˜ ๊ธฐ๋ณธ๊ฐ’ ์„ค์ •์ด ์ •ํ™•ํ•ฉ๋‹ˆ๋‹ค. Naver API ์ธ์ฆ(Client ID, Secret)์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์„ค์ •๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๊ฒƒ์€ ๋ณ„๋„์˜ ์‹œ์Šคํ…œ ์„ค์ • ๊ฒ€์ฆ ์˜์—ญ์ž…๋‹ˆ๋‹ค.

core/network/src/main/java/com/teamsolply/solply/network/model/NaverLocalSearchResponseDto.kt (1)

5-12: LGTM!

๋„ค์ด๋ฒ„ ๋กœ์ปฌ ๊ฒ€์ƒ‰ API ์‘๋‹ต ๊ตฌ์กฐ๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ •์˜๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

feature/search/src/main/java/com/teamsolply/solply/registerplace/navigation/RegisterPlaceNavigation.kt (1)

1-29: LGTM!

RegisterPlace ํ™”๋ฉด์˜ ๋„ค๋น„๊ฒŒ์ด์…˜ ๊ตฌ์„ฑ์ด ํ”„๋กœ์ ํŠธ์˜ ๋‹ค๋ฅธ feature ๋ชจ๋“ˆ๋“ค๊ณผ ์ผ๊ด€๋œ ํŒจํ„ด์„ ๋”ฐ๋ฅด๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

feature/course/src/main/java/com/teamsolply/solply/course/CourseContract.kt (2)

14-36: LGTM!

๋‹ค์ด์–ผ๋กœ๊ทธ ์ƒํƒœ๋ฅผ CourseState์—์„œ ์ œ๊ฑฐํ•˜์—ฌ ๋„ค๋น„๊ฒŒ์ด์…˜์œผ๋กœ ์ฑ…์ž„์„ ๋ถ„๋ฆฌํ•œ ๊ฒƒ์ด ์ข‹์€ ๋ฆฌํŒฉํ† ๋ง์ž…๋‹ˆ๋‹ค.


66-77: LGTM!

Intent์™€ SideEffect๊ฐ€ ์ผ๊ด€๋˜๊ฒŒ ์ •์˜๋˜์–ด ๋ช…์‹œ์ ์ธ ๋„ค๋น„๊ฒŒ์ด์…˜ ํ๋ฆ„์„ ์ž˜ ํ‘œํ˜„ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/dropdown/SolplyBasicDropDown.kt (3)

89-90: LGTM!

๋“œ๋กญ๋‹ค์šด UI์—๋Š” slide ์• ๋‹ˆ๋ฉ”์ด์…˜๋ณด๋‹ค expand/shrink ์• ๋‹ˆ๋ฉ”์ด์…˜์ด ๋” ์ ํ•ฉํ•˜๋ฉฐ, ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์ด ๊ฐœ์„ ๋ฉ๋‹ˆ๋‹ค.


70-70: ์•„์ด์ฝ˜ ๋ฆฌ์†Œ์Šค ๋ณ€๊ฒฝ ํ™•์ธ ์™„๋ฃŒ

์ƒˆ๋กœ์šด ic_arrow_down_lg ๋ฆฌ์†Œ์Šค ํŒŒ์ผ์ด core/designsystem/src/main/res/drawable/ ๋””๋ ‰ํ† ๋ฆฌ์— ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. ๋ณ€๊ฒฝ์‚ฌํ•ญ์ด ์œ ํšจํ•ฉ๋‹ˆ๋‹ค.


34-34: Breaking API ๋ณ€๊ฒฝ์‚ฌํ•ญ ๊ฒ€์ฆ ์™„๋ฃŒ - ๋ชจ๋“  ํ˜ธ์ถœ๋ถ€ ์ •์ƒ ์—…๋ฐ์ดํŠธ๋จ

SolplyBasicDropDown ํ˜ธ์ถœ๋ถ€ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ, ํ”„๋กœ์ ํŠธ ๋‚ด ๋ชจ๋“  ์‚ฌ์šฉ์ฒ˜(PlaceTypeDropDown, SolplyPersonaDropDown)๊ฐ€ ์ƒˆ๋กœ์šด ์‹œ๊ทธ๋‹ˆ์ฒ˜ defaultLabel: @Composable RowScope.() -> Unit์œผ๋กœ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์—…๋ฐ์ดํŠธ๋˜์—ˆ์Œ์„ ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ธฐ์กด String ๊ธฐ๋ฐ˜์˜ ํ˜ธ์ถœ์€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

domain/search/src/main/java/com/teamsolply/solply/search/model/RegisterPlaceEntity.kt (2)

13-16: LGTM!

์ด๋ฏธ์ง€ ์—”ํ‹ฐํ‹ฐ ๊ตฌ์กฐ๊ฐ€ ๋ช…ํ™•ํ•˜๊ณ  ์ ์ ˆํ•ฉ๋‹ˆ๋‹ค.


18-21: LGTM!

์‘๋‹ต ์—”ํ‹ฐํ‹ฐ ๊ตฌ์กฐ๊ฐ€ ์ ์ ˆํ•ฉ๋‹ˆ๋‹ค.

feature/place/src/main/java/com/teamsolply/solply/place/navigation/PlaceNavigation.kt (1)

16-30: LGTM!

๋„ค๋น„๊ฒŒ์ด์…˜ ๊ตฌ์กฐ๊ฐ€ Course ๋ชจ๋“ˆ์˜ ๋ณ€๊ฒฝ์‚ฌํ•ญ๊ณผ ์ผ๊ด€๋˜๊ฒŒ ๋ฆฌํŒฉํ† ๋ง๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์ด์–ผ๋กœ๊ทธ ๊ธฐ๋ฐ˜ ์ ‘๊ทผ์—์„œ ๋ช…์‹œ์ ์ธ ๋„ค๋น„๊ฒŒ์ด์…˜ ์ฝœ๋ฐฑ์œผ๋กœ ๋ณ€๊ฒฝํ•˜์—ฌ ๊ด€์‹ฌ์‚ฌ์˜ ๋ถ„๋ฆฌ๊ฐ€ ๊ฐœ์„ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

feature/course/src/main/java/com/teamsolply/solply/course/CourseScreen.kt (3)

31-67: LGTM!

CourseRoute๊ฐ€ ์ƒˆ๋กœ์šด ๋„ค๋น„๊ฒŒ์ด์…˜ ํŒจํ„ด์„ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ตฌํ˜„ํ•˜๊ณ  ์žˆ์œผ๋ฉฐ, ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ ์ฒ˜๋ฆฌ๊ฐ€ ์ ์ ˆํ•ฉ๋‹ˆ๋‹ค.


69-86: LGTM!

Intent ์ „์†ก ๋กœ์ง์ด ์ƒˆ๋กœ์šด Contract์™€ ์ผ์น˜ํ•˜๋ฉฐ, ๋‹ค์ด์–ผ๋กœ๊ทธ ์ƒํƒœ ๊ด€๋ฆฌ์—์„œ ๋„ค๋น„๊ฒŒ์ด์…˜ ๊ธฐ๋ฐ˜ ์ ‘๊ทผ์œผ๋กœ ๊น”๋”ํ•˜๊ฒŒ ์ „ํ™˜๋˜์—ˆ์Šต๋‹ˆ๋‹ค.


88-108: LGTM!

CourseScreen ์‹œ๊ทธ๋‹ˆ์ฒ˜๊ฐ€ ์—…๋ฐ์ดํŠธ๋˜์–ด ๋‹ค์ด์–ผ๋กœ๊ทธ ๊ฐ€์‹œ์„ฑ boolean ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ์ œ๊ฑฐ๋˜๊ณ  ๋‹จ์ˆœํ•œ ์ฝœ๋ฐฑ์œผ๋กœ ๋ณ€๊ฒฝ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. UI ๊ตฌ์„ฑ์ด ๋” ๊ฐ„๊ฒฐํ•ด์กŒ์Šต๋‹ˆ๋‹ค.

feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceViewModel.kt (1)

106-111: ์ฒจ๋ถ€ ์ด๋ฏธ์ง€ URI ์ตœ๋Œ€ 3๊ฐœ ์ œํ•œ ๋กœ์ง์€ ๋ช…ํ™•ํ•˜๊ณ  ์•ˆ์ „ํ•ด ๋ณด์ž…๋‹ˆ๋‹ค

  • remain = (3 - current.size).coerceAtLeast(0) ํ›„ take(remain)์œผ๋กœ ์ž˜๋ผ๋‚ด์–ด, ํ•ญ์ƒ ์ตœ๋Œ€ 3๊ฐœ๊นŒ์ง€๋งŒ ์œ ์ง€ํ•˜๋Š” ๋กœ์ง์ด ๊น”๋”ํ•ฉ๋‹ˆ๋‹ค.
  • ์ค‘๋ณต URI ํ—ˆ์šฉ ์—ฌ๋ถ€๋งŒ ๊ธฐํš/UX ๊ด€์ ์—์„œ ํ•œ ๋ฒˆ๋งŒ ํ™•์ธํ•˜๋ฉด ๋  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค (ํ˜„์žฌ ๊ตฌํ˜„์€ ๊ฐ™์€ URI๋ฅผ ์—ฌ๋Ÿฌ ๋ฒˆ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ๋„ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค).
data/search/src/main/java/com/teamsolply/solply/search/repository/SearchRepositoryImpl.kt (1)

19-34: getPlaceSearch ํ™•์žฅ ๋งคํ•‘์€ ์ž์—ฐ์Šค๋Ÿฝ์Šต๋‹ˆ๋‹ค

  • isBookmarked, townId๋ฅผ ๊ทธ๋Œ€๋กœ SearchResultEntity์— ์ถ”๊ฐ€ ๋งคํ•‘ํ•œ ๋ถ€๋ถ„์€ ๋ช…ํ™•ํ•˜๊ณ , ๊ธฐ์กด ํ•„๋“œ์™€๋„ ์ผ๊ด€์„ฑ ์žˆ์Šต๋‹ˆ๋‹ค.
  • PlaceType.fromApiCode(searchResult.primaryTag) ์‚ฌ์šฉ๋„ ๋„๋ฉ”์ธ ๋ชจ๋ธ ์ชฝ ์ฑ…์ž„ ๋ถ„๋ฆฌ๋ฅผ ์ž˜ ์ง€ํ‚ค๊ณ  ์žˆ๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.
feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/favoriteTownNavigation/FavoriteTownNavigation.kt (1)

20-32: backStackEntry.toRoute ์‚ฌ์šฉ๊ณผ selectedTownId ์ „๋‹ฌ ํ๋ฆ„์€ ์ผ๊ด€์ ์ž…๋‹ˆ๋‹ค

  • composable<FavoriteTown> { backStackEntry -> ... }์™€ backStackEntry.toRoute<FavoriteTown>().selectedTownId๋กœ argument๋ฅผ ๊บผ๋‚ด๋Š” ๊ตฌ์กฐ๊ฐ€ FavoriteTownRoute์˜ selectedTownId ํŒŒ๋ผ๋ฏธํ„ฐ์™€ ์ž˜ ๋งž์Šต๋‹ˆ๋‹ค.
  • navigateToBack: (Long?) -> Unit์œผ๋กœ ์„ ํƒ๋œ ๋™๋„ค ID๋ฅผ ์ƒ์œ„๋กœ ์ „๋‹ฌํ•˜๋Š” ๊ตฌ์กฐ๋„ FavoriteTownRoute์™€์˜ ๊ณ„์•ฝ์— ๋งž๊ฒŒ ์ •๋ฆฌ๋œ ๊ฒƒ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค.
feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/FavoriteTownRoute.kt (3)

37-64: FavoriteTownRoute์˜ ViewModel ์—ฐ๋™๊ณผ ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ ์ฒ˜๋ฆฌ ๊ตฌ์กฐ๋Š” ๋ช…ํ™•ํ•ฉ๋‹ˆ๋‹ค

  • selectedTownId๋ฅผ ์ธ์ž๋กœ ๋ฐ›์•„ FavoriteTownIntent.LoadFavoriteTownList๋ฅผ ๋ณด๋‚ด๋Š” ๊ตฌ์กฐ๊ฐ€ ์ดˆ๊ธฐ ์ง„์ž… ๋กœ์ง์„ ์ž˜ ๋“œ๋Ÿฌ๋‚ด๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
  • LaunchedEffect(Unit) ๋‚ด๋ถ€์—์„œ sideEffect.collect ๋ฐ ์ดˆ๊ธฐ ๋กœ๋“œ ์ธํ…ํŠธ๋ฅผ ๋ถ„๋ฆฌํ•ด ๋‘” ๊ฒƒ๋„ ์žฌ๊ตฌ์„ฑ ์‹œ ์ค‘๋ณต ์‹คํ–‰์„ ๋ง‰๋Š” ํŒจํ„ด์œผ๋กœ ์ ์ ˆํ•ฉ๋‹ˆ๋‹ค.
  • ๋‹จ, ์ดˆ๊ธฐ ๋กœ๋“œ ์ „์— ์‚ฌ์šฉ์ž๊ฐ€ ๋’ค๋กœ๊ฐ€๊ธฐ/ํ™ˆ ๋ฒ„ํŠผ์„ ๋น ๋ฅด๊ฒŒ ๋ˆ„๋ฅผ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ, ๊ทธ ๊ฒฝ์šฐ state.selectedTownId๊ฐ€ null์ธ ์ฑ„๋กœ navigateToBack(null)์ด ํ˜ธ์ถœ๋˜๋Š” ๊ฒƒ์ด ์˜๋„๋œ ๋™์ž‘์ธ์ง€ ํ•œ ๋ฒˆ๋งŒ ํ™•์ธํ•ด ์ฃผ์„ธ์š”.

70-97: TopBar ๋ฐ ๋ฆฌ์ŠคํŠธ Pane์˜ ์ธํ…ํŠธ ์ „ํŒŒ๋Š” ์ผ๊ด€์ ์ž…๋‹ˆ๋‹ค

  • FavoriteTownTopBar์˜ ๋’ค๋กœ๊ฐ€๊ธฐ/ํ™ˆ ๋ฒ„ํŠผ์ด ๋ชจ๋‘ handleDismiss๋ฅผ ํ˜ธ์ถœํ•˜๊ณ , ์ด ํ•ธ๋“ค๋Ÿฌ๊ฐ€ navigateToBack(state.selectedTownId)๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ตฌ์กฐ๋ผ์„œ ์‹ค์ œ ์„ ํƒ ๊ฐ’์ด ์ƒ์œ„๋กœ ์ž˜ ์ „๋‹ฌ๋ฉ๋‹ˆ๋‹ค.
  • LeftRegionPane / RightTownPane์—์„œ ๊ฐ๊ฐ FavoriteTownIntent.SelectRegion, FavoriteTownIntent.SelectTown์„ ๋ณด๋‚ด๋Š” ๊ฒƒ๋„ ViewModel ์ค‘์‹ฌ ์•„ํ‚คํ…์ฒ˜์— ๋งž์Šต๋‹ˆ๋‹ค.

UX ๊ด€์ ์—์„œ โ€œํ™ˆ ์•„์ด์ฝ˜ ํƒญ ์‹œ ํ•ญ์ƒ ๋‹จ์ˆœ back์ธ์ง€, ๋‹ค๋ฅธ ์Šคํƒ ์ •๋ฆฌ ๋™์ž‘์ด ํ•„์š”ํ•œ์ง€โ€ ์ •๋„๋งŒ ๊ธฐํš๊ณผ ๋งž๋Š”์ง€ ํ™•์ธํ•˜์‹œ๋ฉด ์ข‹๊ฒ ์Šต๋‹ˆ๋‹ค.


118-175: LeftRegionPane๋Š” ๊ฐ€๋…์„ฑ๊ณผ ์„ ํƒ ์ƒํƒœ ํ‘œํ˜„์ด ๊ฐœ์„ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค

  • ์„ ํƒ ์—ฌ๋ถ€์— ๋”ฐ๋ผ ๋ฐฐ๊ฒฝ์ƒ‰๊ณผ textColor๋ฅผ ๋ถ„๋ฆฌํ•œ ๋ถ€๋ถ„์ด ์ด์ „๋ณด๋‹ค ์ฝ๊ธฐ ์‰ฝ๊ณ , ๋””์ž์ธ ํ† ํฐ๋„ ์ผ๊ด€์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
  • SolplyTheme.typography.body16M๋ฅผ ์‚ฌ์šฉํ•ด FontWeight๋ฅผ ์ง์ ‘ ์ง€์ •ํ•˜์ง€ ์•Š๊ณ  ํƒ€์ดํฌ ์Šคํƒ€์ผ๋กœ ํ†ตํ•ฉํ•œ ๊ฒƒ๋„ ์œ ์ง€๋ณด์ˆ˜์— ์œ ๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

ํŠน๋ณ„ํ•œ ๋กœ์ง ์ด์Šˆ๋Š” ์—†๊ณ , ์„ฑ๋Šฅ ์ธก๋ฉด์—์„œ๋„ LazyColumn + key = { it.id } ์‚ฌ์šฉ์ด ์ ์ ˆํ•ฉ๋‹ˆ๋‹ค.

feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceContract.kt (1)

11-58: ๊ณ„์•ฝ(Contract) ๊ตฌ์กฐ๊ฐ€ ์ž˜ ์ •์˜๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

MVI ํŒจํ„ด์„ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๋”ฐ๋ฅด๊ณ  ์žˆ์œผ๋ฉฐ, ์ƒํƒœ์™€ ์ธํ…ํŠธ๊ฐ€ ๋ช…ํ™•ํ•˜๊ฒŒ ๋ถ„๋ฆฌ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. Immutable ์ปฌ๋ ‰์…˜ ์‚ฌ์šฉ๋„ ์ ์ ˆํ•ฉ๋‹ˆ๋‹ค.

feature/place/src/main/java/com/teamsolply/solply/place/PlaceScreen.kt (2)

68-69: ๋„ค๋น„๊ฒŒ์ด์…˜ ๋ฆฌํŒฉํ† ๋ง์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ ์šฉ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์ƒˆ๋กœ์šด navigateToFavoriteTown๊ณผ navigateToSearch ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ์ถ”๊ฐ€๋˜์–ด ๋„ค๋น„๊ฒŒ์ด์…˜ ์˜๋„๊ฐ€ ๋ช…ํ™•ํ•˜๊ฒŒ ๋ถ„๋ฆฌ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. MainNavigator.kt์˜ ๊ด€๋ จ ๋ฉ”์„œ๋“œ๋“ค๊ณผ ์ผ์น˜ํ•ฉ๋‹ˆ๋‹ค.


190-190: changeSearchDialogVisibility API ์‹œ๊ทธ๋‹ˆ์ฒ˜ ๋ณ€๊ฒฝ์ด ์ผ๊ด€๋˜๊ฒŒ ์ ์šฉ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๊ฒ€์ฆ ๊ฒฐ๊ณผ, changeSearchDialogVisibility์˜ ์‹œ๊ทธ๋‹ˆ์ฒ˜ ๋ณ€๊ฒฝ((Boolean) -> Unit โ†’ () -> Unit)์ด ์ฝ”๋“œ๋ฒ ์ด์Šค ์ „์ฒด์—์„œ ์ผ๊ด€๋˜๊ฒŒ ์ ์šฉ๋˜์—ˆ์Šต๋‹ˆ๋‹ค:

  • PlaceScreen.kt: ๋งค๊ฐœ๋ณ€์ˆ˜ ์ •์˜(190์ค„), ๊ตฌํ˜„(117์ค„), ํ˜ธ์ถœ(221์ค„) ๋ชจ๋‘ () -> Unit ํ˜•์‹ โœ“
  • CourseScreen.kt: ๋งค๊ฐœ๋ณ€์ˆ˜ ์ •์˜(93์ค„), ๊ตฌํ˜„(81์ค„), ํ˜ธ์ถœ(107์ค„) ๋ชจ๋‘ () -> Unit ํ˜•์‹ โœ“
  • SolplyHomeHeader.kt: ๋งค๊ฐœ๋ณ€์ˆ˜ ์ •์˜(27์ค„), ํ˜ธ์ถœ(79์ค„) ๋ชจ๋‘ ๋งค๊ฐœ๋ณ€์ˆ˜ ์—†์ด ์‹คํ–‰ โœ“

๋ชจ๋“  ํ˜ธ์ถœ ์ง€์ ์ด ์ •์ƒ์ ์œผ๋กœ ์—…๋ฐ์ดํŠธ๋˜์—ˆ์œผ๋ฉฐ, Boolean ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๋ ˆ๊ฑฐ์‹œ ์ฝ”๋“œ๋Š” ์—†์Šต๋‹ˆ๋‹ค.

feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceScreen.kt (2)

192-205: ์ด๋ฏธ์ง€ ์„ ํƒ ๋กœ์ง์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ตฌํ˜„๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๋‚จ์€ ์Šฌ๋กฏ ์ˆ˜์— ๋”ฐ๋ผ ๋‹จ์ผ/๋‹ค์ค‘ ์ด๋ฏธ์ง€ ์„ ํƒ๊ธฐ๋ฅผ ์ ์ ˆํ•˜๊ฒŒ ๋ถ„๊ธฐํ•˜๊ณ  ์žˆ์œผ๋ฉฐ, maxItems ์ œํ•œ๋„ ์ •ํ™•ํ•˜๊ฒŒ ๊ณ„์‚ฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.


142-471: ํ™”๋ฉด ๊ตฌ์กฐ๊ฐ€ ์ž˜ ์„ค๊ณ„๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๋‹ค๋‹จ๊ณ„ ํผ์ด ์ƒํƒœ์— ๋”ฐ๋ผ ์ ์ ˆํ•˜๊ฒŒ ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง๋˜๊ณ  ์žˆ์œผ๋ฉฐ, ํ‚ค๋ณด๋“œ ์ฒ˜๋ฆฌ(BringIntoViewRequester)์™€ ํฌ์ปค์Šค ๊ด€๋ฆฌ๊ฐ€ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์„ ๊ณ ๋ คํ•˜์—ฌ ๊ตฌํ˜„๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

Comment on lines +27 to +36
buildConfigField(
"String",
"NAVER_DEVELOPERS_CLIENT_ID",
gradleLocalProperties(rootDir, providers).getProperty("naver.developers.client.id")
)
buildConfigField(
"String",
"NAVER_DEVELOPERS_CLIENT_SECRET",
gradleLocalProperties(rootDir, providers).getProperty("naver.developers.client.secret")
)
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

๋กœ์ปฌ ํ”„๋กœํผํ‹ฐ ๋ˆ„๋ฝ ์‹œ ์—๋Ÿฌ ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

์ƒˆ๋กœ์šด ๋„ค์ด๋ฒ„ ๊ฐœ๋ฐœ์ž ์„ผํ„ฐ credential๋“ค์ด ์ถ”๊ฐ€๋˜์—ˆ์ง€๋งŒ, getProperty() ํ˜ธ์ถœ ์‹œ ํ”„๋กœํผํ‹ฐ๊ฐ€ ์—†์œผ๋ฉด ๋นŒ๋“œ๊ฐ€ ์‹คํŒจํ•ฉ๋‹ˆ๋‹ค. ํŒ€์›๋“ค์ด ๋นŒ๋“œ ์‹คํŒจ๋ฅผ ๊ฒช์ง€ ์•Š๋„๋ก ๋‹ค์Œ ์‚ฌํ•ญ๋“ค์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค:

  1. README ๋˜๋Š” ๋ฌธ์„œ์— ํ•„์ˆ˜ ๋กœ์ปฌ ํ”„๋กœํผํ‹ฐ ์ถ”๊ฐ€
  2. ๊ธฐ๋ณธ๊ฐ’ ์ œ๊ณต ๋˜๋Š” ๋ช…ํ™•ํ•œ ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ ์ถ”๊ฐ€

๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ฐœ์„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

 buildConfigField(
     "String",
     "NAVER_DEVELOPERS_CLIENT_ID",
-    gradleLocalProperties(rootDir, providers).getProperty("naver.developers.client.id")
+    gradleLocalProperties(rootDir, providers).getProperty("naver.developers.client.id") 
+        ?: throw GradleException("naver.developers.client.id must be defined in local.properties")
 )
 buildConfigField(
     "String",
     "NAVER_DEVELOPERS_CLIENT_SECRET",
-    gradleLocalProperties(rootDir, providers).getProperty("naver.developers.client.secret")
+    gradleLocalProperties(rootDir, providers).getProperty("naver.developers.client.secret")
+        ?: throw GradleException("naver.developers.client.secret must be defined in local.properties")
 )

๋˜ํ•œ README ํŒŒ์ผ์— ๋‹ค์Œ ํ”„๋กœํผํ‹ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜๋„๋ก ๋ฌธ์„œํ™”๊ฐ€ ํ•„์š”ํ•œ์ง€ ํ™•์ธํ•ด์ฃผ์„ธ์š”:

  • naver.developers.client.id
  • naver.developers.client.secret


---

๐Ÿ Script executed:

```shell
#!/bin/bash
# Find the BuildConfig.kt file and examine the full context
find . -name "BuildConfig.kt" -type f 2>/dev/null | head -20

Length of output: 86


๐Ÿ Script executed:

#!/bin/bash
# Search for gradleLocalProperties function definition
rg -n "gradleLocalProperties" -A 5 -B 2

Length of output: 6692


๐Ÿ Script executed:

#!/bin/bash
# Check for existing local.properties setup documentation
find . -name "README*" -o -name "*.md" | xargs grep -l "local.properties" 2>/dev/null || echo "No README with local.properties found"

Length of output: 37


๐Ÿ Script executed:

#!/bin/bash
# Look for other uses of getProperty in the codebase to see how they handle missing values
rg -n "getProperty\(" -A 1 -B 1 --type=kt

Length of output: 26


๐Ÿ Script executed:

#!/bin/bash
# Check if there's a setup guide or documentation file
find . -type f \( -name "SETUP*" -o -name "setup*" -o -name "LOCAL*" \) 2>/dev/null | head -10

Length of output: 0







๐Ÿ Script executed:

#!/bin/bash
# Search for any example or template files for properties
find . -type f \( -name "*example*" -o -name "*template*" -o -name "*.properties" \) 2>/dev/null | grep -E "\.(properties|txt|md)" | head -20

Length of output: 62


๐Ÿ Script executed:

#!/bin/bash
# Look at the full BuildConfig.kt file to see all properties
cat build-logic/convention/src/main/java/com/teamsolply/solply/convention/BuildConfig.kt

Length of output: 1447


๐Ÿ Script executed:

#!/bin/bash
# Check if there's any gradle setup documentation
find . -name "README*" -o -name "*.md" | head -30

Length of output: 184


๐Ÿ Script executed:

#!/bin/bash
# Search for error handling patterns in gradle files
rg -n "elvis|getProperty|\?:|?: throw" -g "*.gradle.kts" -g "*.gradle" -A 2

Length of output: 127


๐ŸŒ Web query:

Android Gradle Plugin gradleLocalProperties getProperty null behavior missing property

๐Ÿ’ก Result:

Short answer: gradleLocalProperties.getProperty(...) behaves like java.util.Properties.getProperty โ€” it returns null when the key is missing (it does not throw). If you need a non-null value, either provide a default or test for null/hasProperty (or use Gradle's project.findProperty / hasProperty when reading project properties, since project.getProperty throws if missing). [1][2][3]

References

  • Java Properties.getProperty docs (returns null if not found). [1]
  • Gradle guidance: project.getProperty throws; project.findProperty/hasProperty return null/allow checks. (discussion / history). [2]
  • AGP source shows property-access code uses get/getProperties() (i.e. map lookup), consistent with null-on-missing behavior. [3]

๋ชจ๋“  ๋กœ์ปฌ ํ”„๋กœํผํ‹ฐ์— ๋Œ€ํ•œ ์—๋Ÿฌ ์ฒ˜๋ฆฌ ์ถ”๊ฐ€ ํ•„์š”

๋ฌธ์ œ๋ฅผ ์žฌํ™•์ธํ•œ ๊ฒฐ๊ณผ, ์ด ๋ฌธ์ œ๋Š” ์ƒˆ๋กœ์šด Naver ํ”„๋กœํผํ‹ฐ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ํŒŒ์ผ์˜ ๋ชจ๋“  buildConfigField ํ˜ธ์ถœ(BASE_URL, KAKAO_NATIVE_KEY, NAVER_CLIENT_ID ํฌํ•จ)์— ์˜ํ–ฅ์„ ๋ฏธ์นฉ๋‹ˆ๋‹ค. getProperty()๋Š” ํ”„๋กœํผํ‹ฐ๊ฐ€ ๋ˆ„๋ฝ๋˜๋ฉด null์„ ๋ฐ˜ํ™˜ํ•˜๋ฉฐ, ์ด๋กœ ์ธํ•ด ๋นŒ๋“œ๊ฐ€ ์‹คํŒจํ•ฉ๋‹ˆ๋‹ค.

๊ถŒ์žฅ์‚ฌํ•ญ:

  1. ์ผ๊ด„ ํ•ด๊ฒฐ: ๋‹ค์„ฏ ๊ฐœ ํ”„๋กœํผํ‹ฐ ๋ชจ๋‘์— ๋Œ€ํ•ด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์—๋Ÿฌ ์ฒ˜๋ฆฌ ์ถ”๊ฐ€

    buildConfigField(
        "String",
    -   "NAVER_DEVELOPERS_CLIENT_ID",
    -   gradleLocalProperties(rootDir, providers).getProperty("naver.developers.client.id")
    +   "NAVER_DEVELOPERS_CLIENT_ID",
    +   gradleLocalProperties(rootDir, providers).getProperty("naver.developers.client.id")
    +       ?: throw GradleException("naver.developers.client.id must be defined in local.properties")
    )
  2. ๋ฌธ์„œํ™”: README์— ํ•„์ˆ˜ ๋กœ์ปฌ ํ”„๋กœํผํ‹ฐ ๋ชฉ๋ก๊ณผ ์„ค์ • ๋ฐฉ๋ฒ• ์ถ”๊ฐ€

    • base.url
    • kakao.native.key
    • naver.client.id
    • naver.developers.client.id
    • naver.developers.client.secret
๐Ÿ“ 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
buildConfigField(
"String",
"NAVER_DEVELOPERS_CLIENT_ID",
gradleLocalProperties(rootDir, providers).getProperty("naver.developers.client.id")
)
buildConfigField(
"String",
"NAVER_DEVELOPERS_CLIENT_SECRET",
gradleLocalProperties(rootDir, providers).getProperty("naver.developers.client.secret")
)
buildConfigField(
"String",
"NAVER_DEVELOPERS_CLIENT_ID",
gradleLocalProperties(rootDir, providers).getProperty("naver.developers.client.id")
?: throw GradleException("naver.developers.client.id must be defined in local.properties")
)
buildConfigField(
"String",
"NAVER_DEVELOPERS_CLIENT_SECRET",
gradleLocalProperties(rootDir, providers).getProperty("naver.developers.client.secret")
)

Comment on lines +14 to +25
@Serializable
data class LocalSearchItem(
val title: String,
val link: String,
val category: String,
val description: String,
val telephone: String,
val address: String,
val roadAddress: String,
val mapx: String,
val mapy: String
) No newline at end of file
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

๋„ค์ด๋ฒ„ API ์‘๋‹ต ํ•„๋“œ์˜ null ๊ฐ€๋Šฅ์„ฑ์„ ํ™•์ธํ•˜์„ธ์š”.

๋ชจ๋“  ํ•„๋“œ๊ฐ€ non-nullable๋กœ ์ •์˜๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋„ค์ด๋ฒ„ ๋กœ์ปฌ ๊ฒ€์ƒ‰ API ๋ฌธ์„œ๋ฅผ ํ™•์ธํ•˜์—ฌ telephone, description ๋“ฑ์˜ ํ•„๋“œ๊ฐ€ ํ•ญ์ƒ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋Š”์ง€ ๊ฒ€์ฆ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์ผ๋ถ€ ํ•„๋“œ๊ฐ€ ๋นˆ ๋ฌธ์ž์—ด์ด๋‚˜ null์„ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด nullable ํƒ€์ž…์œผ๋กœ ๋ณ€๊ฒฝํ•˜๊ฑฐ๋‚˜ ๊ธฐ๋ณธ๊ฐ’ ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


๐ŸŒ Web query:

๋„ค์ด๋ฒ„ ๋กœ์ปฌ ๊ฒ€์ƒ‰ API ์‘๋‹ต ํ•„๋“œ ์ค‘ telephone, description ํ•„๋“œ๊ฐ€ null ๋˜๋Š” ๋นˆ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ํ™•์ธ

๐Ÿ’ก Result:

๋„ค. ๋‹ค์Œ ๋ฌธ์„œ ๊ทผ๊ฑฐ๋กœ ์ •๋ฆฌํ•˜๋ฉด:

  • telephone ํ•„๋“œ: โ€œ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š๋Š” ์š”์†Œโ€๋กœ ํ‘œ๊ธฐ๋˜์–ด ์žˆ์–ด ๋นˆ๊ฐ’(๋˜๋Š” ๋น„์–ด์žˆ๋Š” ์š”์†Œ)์„ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. [1].
  • description ํ•„๋“œ: ์„ค๋ช… ๋ฌธ์ž์—ด๋กœ ์ •์˜๋˜์–ด ์žˆ์œผ๋‚˜ ํ•ญ๋ชฉ์— ๋”ฐ๋ผ ๋‚ด์šฉ์ด ๋น„์–ด์žˆ์„ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๋นˆ ๋ฌธ์ž์—ด์œผ๋กœ ์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(๋ฌธ์„œ ์˜ˆ์‹œ์—๋„ telephone์€ ๋น„์–ด์žˆ๊ณ  description์€ ์กด์žฌํ•˜๋Š” ํ˜•ํƒœ๊ฐ€ ๋‚˜์˜ต๋‹ˆ๋‹ค). [1].

์ฐธ๊ณ : ์›๋ฌธ API ๋ ˆํผ๋Ÿฐ์Šค โ€” ๋„ค์ด๋ฒ„ ๊ฒ€์ƒ‰ > ์ง€์—ญ(๋กœ์ปฌ) ์‘๋‹ต ํ•„๋“œ ์„ค๋ช…. [1]

์ถœ์ฒ˜
[1] ๋„ค์ด๋ฒ„ Developers โ€” ๊ฒ€์ƒ‰ > ์ง€์—ญ(๋กœ์ปฌ) API ๋ ˆํผ๋Ÿฐ์Šค (์‘๋‹ต ํ•„๋“œ ์„ค๋ช…).


๋„ค์ด๋ฒ„ API ์‘๋‹ต์—์„œ null ๋˜๋Š” ๋นˆ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๋Š” ํ•„๋“œ๋ฅผ nullable๋กœ ๋ณ€๊ฒฝํ•˜์„ธ์š”.

๋„ค์ด๋ฒ„ ๋กœ์ปฌ ๊ฒ€์ƒ‰ API ๋ฌธ์„œ ํ™•์ธ ๊ฒฐ๊ณผ, telephone ํ•„๋“œ๋Š” "๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š๋Š” ์š”์†Œ"๋กœ ํ‘œ๊ธฐ๋˜์–ด ์žˆ๊ณ , description ํ•„๋“œ๋„ ํ•ญ๋ชฉ์— ๋”ฐ๋ผ ๋นˆ ๋ฌธ์ž์—ด์„ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ˜„์žฌ ๋ชจ๋“  ํ•„๋“œ๊ฐ€ non-nullable String์œผ๋กœ ์ •์˜๋˜์–ด ์žˆ์–ด API ์‘๋‹ต์ด null์„ ๋ฐ˜ํ™˜ํ•  ๊ฒฝ์šฐ ์—ญ์ง๋ ฌํ™”์— ์‹คํŒจํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • telephone: String?์œผ๋กœ ๋ณ€๊ฒฝ
  • description: String?์œผ๋กœ ๋ณ€๊ฒฝ ๋˜๋Š” ๊ธฐ๋ณธ๊ฐ’("") ์„ค์ •
๐Ÿค– Prompt for AI Agents
In
core/network/src/main/java/com/teamsolply/solply/network/model/NaverLocalSearchResponseDto.kt
around lines 14 to 25, the LocalSearchItem data class declares all fields as
non-nullable Strings but the Naver API can return null or empty values for some
fields; change the telephone property to nullable (String?) and change
description to either nullable (String?) or provide a default value (e.g., "")
to avoid deserialization failures; update the property types accordingly and
ensure any code that consumes these fields handles the nullable/empty cases.

Comment on lines +8 to 9
@SerialName("presignedGetUrlInfos")
val presignedUrlInfos: List<PresignedUrlInfo>
Copy link

Choose a reason for hiding this comment

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

โš ๏ธ Potential issue | ๐Ÿ”ด Critical

๐Ÿงฉ Analysis chain

๋ฐฑ์—”๋“œ API ๋ณ€๊ฒฝ์‚ฌํ•ญ๊ณผ์˜ ๋™๊ธฐํ™”๋ฅผ ํ™•์ธํ•ด์ฃผ์„ธ์š”.

JSON ํ‚ค๊ฐ€ "presignedUrlInfos"์—์„œ "presignedGetUrlInfos"๋กœ ๋ณ€๊ฒฝ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ์ง๋ ฌํ™”/์—ญ์ง๋ ฌํ™” ๊ณ„์•ฝ์„ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์ด๋ฏ€๋กœ, ๋ฐฑ์—”๋“œ์—์„œ ๋™์ผํ•œ ํ‚ค ์ด๋ฆ„์œผ๋กœ ์‘๋‹ต์„ ๋ณด๋‚ด๊ณ  ์žˆ๋Š”์ง€ ํ™•์ธ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ๋ฐฑ์—”๋“œ๊ฐ€ ์•„์ง ์—…๋ฐ์ดํŠธ๋˜์ง€ ์•Š์•˜๋‹ค๋ฉด ๋Ÿฐํƒ€์ž„์— ์—ญ์ง๋ ฌํ™” ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‹คํ–‰ํ•˜์—ฌ ์ด DTO๊ฐ€ ์‚ฌ์šฉ๋˜๋Š” ๊ณณ์„ ํ™•์ธํ•ด์ฃผ์„ธ์š”:


์„ ํƒ์  ์ œ์•ˆ: ํ”„๋กœํผํ‹ฐ ์ด๋ฆ„๊ณผ ์ง๋ ฌํ™” ์ด๋ฆ„์˜ ์ผ๊ด€์„ฑ์„ ๊ณ ๋ คํ•ด๋ณด์„ธ์š”.

๋‚ด๋ถ€ ํ”„๋กœํผํ‹ฐ ์ด๋ฆ„์€ presignedUrlInfos์ด์ง€๋งŒ JSON ํ‚ค๋Š” "presignedGetUrlInfos"๋กœ ๋‹ค๋ฆ…๋‹ˆ๋‹ค. ์˜๋„์ ์ธ ์„ค๊ณ„๋ผ๋ฉด ๋ฌธ์ œ์—†์ง€๋งŒ, ์œ ์ง€๋ณด์ˆ˜์„ฑ์„ ์œ„ํ•ด ์ด๋ฆ„์„ ์ผ์น˜์‹œํ‚ค๋Š” ๊ฒƒ๋„ ๊ณ ๋ คํ•ด๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋งŒ์•ฝ ์ผ๊ด€์„ฑ์„ ์›ํ•˜์‹ ๋‹ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

 @Serializable
 data class PresignedUrlsResponseDto(
     @SerialName("presignedGetUrlInfos")
-    val presignedUrlInfos: List<PresignedUrlInfo>
+    val presignedGetUrlInfos: List<PresignedUrlInfo>
 )

๋‹จ, ์ด ๊ฒฝ์šฐ ์ด ํ”„๋กœํผํ‹ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ชจ๋“  ์ฝ”๋“œ๋ฅผ ํ•จ๊ป˜ ์ˆ˜์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.


๐Ÿ Script executed:

#!/bin/bash
# Description: PresignedUrlsResponseDto ์‚ฌ์šฉ์ฒ˜๋ฅผ ํ™•์ธํ•˜์—ฌ ์˜ํ–ฅ ๋ฒ”์œ„ ํŒŒ์•…

# PresignedUrlsResponseDto๊ฐ€ ์‚ฌ์šฉ๋˜๋Š” ๋ชจ๋“  ์œ„์น˜ ๊ฒ€์ƒ‰
rg -n --type kotlin -C3 'PresignedUrlsResponseDto' -g '!**/PresignedUrlsResponseDto.kt'

Length of output: 5813


Now I need to verify the actual implementation of the DTO field to see if it has a default value and search for any usages.

Based on my verification through both code analysis and Kotlin serialization documentation, I can now generate the final rewritten review comment.

๋ฐฑ์—”๋“œ API ์‘๋‹ต ํ˜•์‹์ด ๋ฐ˜๋“œ์‹œ ์—…๋ฐ์ดํŠธ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค (ํ•„์ˆ˜ ๊ฒ€์ฆ)

@SerialName์ด "presignedUrlInfos"์—์„œ "presignedGetUrlInfos"๋กœ ๋ณ€๊ฒฝ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. Kotlin kotlinx.serialization์€ ํ•„๋“œ๊ฐ€ ๋ˆ„๋ฝ๋˜์—ˆ์„ ๋•Œ ์ƒ์„ฑ์ž๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์—†์–ด MissingFieldException์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

ํ˜„์žฌ presignedUrlInfos๋Š” ๊ธฐ๋ณธ๊ฐ’ ์—†๋Š” List<PresignedUrlInfo> ํƒ€์ž…์ด๋ฏ€๋กœ ํ•„์ˆ˜ ํ•„๋“œ์ž…๋‹ˆ๋‹ค. ๊ธฐ๋ณธ๊ฐ’ ์—†์ด JSON์—์„œ ํ•ด๋‹น ํ‚ค๊ฐ€ ๋ˆ„๋ฝ๋˜๋ฉด MissingFieldException์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ๋ฐฑ์—”๋“œ๊ฐ€ ์—ฌ์ „ํžˆ "presignedUrlInfos" ํ‚ค๋กœ ์‘๋‹ตํ•˜๋ฉด ๋Ÿฐํƒ€์ž„์— ์—ญ์ง๋ ฌํ™” ์˜ค๋ฅ˜๋กœ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์ค‘๋‹จ๋ฉ๋‹ˆ๋‹ค.

ํ•„์ˆ˜ ํ™•์ธ ์‚ฌํ•ญ:

  • ๋ฐฑ์—”๋“œ API๊ฐ€ "presignedGetUrlInfos" ํ‚ค๋กœ ์‘๋‹ตํ•˜๋„๋ก ์—…๋ฐ์ดํŠธ๋˜์—ˆ๋Š”์ง€ ํ™•์ธ
  • ์Šคํ…Œ์ด์ง•/ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ ์‹ค์ œ ์‘๋‹ต ํ˜•์‹ ๊ฒ€์ฆ
๐Ÿค– Prompt for AI Agents
In
data/maps/src/main/java/com/teamsolply/solply/maps/dto/response/PresignedUrlsResponseDto.kt
around lines 8-9, the @SerialName was changed from "presignedUrlInfos" to
"presignedGetUrlInfos", making the field a required non-null List and causing
MissingFieldException if the backend still sends the old key; fix by either (A)
restoring the original serial name to match the backend, or (B) give
presignedUrlInfos a safe default (e.g., = emptyList()) or make it nullable so
deserialization wonโ€™t fail, and coordinate with the backend team to confirm the
response key in staging/prod.

Comment on lines +23 to +24
@SerialName("mainTag")
val mainTag: String,
Copy link

Choose a reason for hiding this comment

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

โš ๏ธ Potential issue | ๐Ÿ”ด Critical

๐Ÿงฉ Analysis chain

๋ฐฑ์—”๋“œ API ๊ณ„์•ฝ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ํ™•์ธํ•ด์ฃผ์„ธ์š”.

ํ•„๋“œ๋ช…์ด primaryTag์—์„œ mainTag๋กœ ๋ณ€๊ฒฝ๋˜์—ˆ๊ณ , @SerialName ์–ด๋…ธํ…Œ์ด์…˜๋„ ํ•จ๊ป˜ ์—…๋ฐ์ดํŠธ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๋ฐฑ์—”๋“œ API ์‘๋‹ต ๊ตฌ์กฐ๊ฐ€ ๋ณ€๊ฒฝ๋˜์—ˆ์Œ์„ ์˜๋ฏธํ•˜๋ฏ€๋กœ, ๋ฐฑ์—”๋“œ ํŒ€๊ณผ์˜ ๋™๊ธฐํ™”๊ฐ€ ์™„๋ฃŒ๋˜์—ˆ๋Š”์ง€ ํ™•์ธ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ ์Šคํฌ๋ฆฝํŠธ๋กœ ๊ด€๋ จ๋œ ๋ชจ๋“  DTO์™€ ๋งคํผ๊ฐ€ ์ผ๊ด€๋˜๊ฒŒ ์—…๋ฐ์ดํŠธ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”:


๐Ÿ Script executed:

#!/bin/bash
# Description: Verify all references to primaryTag have been updated to mainTag

# Search for any remaining references to primaryTag in DTOs and mappers
rg -n "primaryTag" --type=kt -g '!**/build/**'

Length of output: 26


Actually, let me correct that - I need access to the repository. Let me try a different approach:


๐Ÿ Script executed:

#!/bin/bash
# Search for remaining primaryTag references using glob patterns instead of file type
echo "=== Searching for primaryTag references in Kotlin files ==="
rg -n "primaryTag" -g '*.kt' 

echo -e "\n=== Checking GetPlacesResponseDto.kt content ==="
find . -name "GetPlacesResponseDto.kt" -type f 2>/dev/null | head -5 | xargs -I {} cat {}

echo -e "\n=== Searching for related DTO files with Tag references ==="
rg -n "Tag" -g '*.kt' --type=kotlin 2>/dev/null || rg -n "@SerialName" -g '**/*Dto.kt' -A2 -B2

Length of output: 26660


๐Ÿ Script executed:

#!/bin/bash
# Search for primaryTag in all files recursively
echo "=== Searching for primaryTag in the codebase ==="
grep -r "primaryTag" --include="*.kt" . 2>/dev/null || echo "No primaryTag found (or grep not available)"

echo -e "\n=== Listing DTO response files ==="
find . -path "*/dto/response/*" -name "*.kt" -type f 2>/dev/null | head -10

Length of output: 4039


API ๊ณ„์•ฝ ๋ณ€๊ฒฝ์ด ๋ถˆ์™„์ „ํ•˜๊ฒŒ ์ ์šฉ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ถ”๊ฐ€ DTO ํŒŒ์ผ๋“ค๋„ ์—…๋ฐ์ดํŠธ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ๋‹ค์Œ DTO ํŒŒ์ผ๋“ค์—์„œ ์—ฌ์ „ํžˆ primaryTag๋ฅผ ์‚ฌ์šฉ ์ค‘์ž…๋‹ˆ๋‹ค:

  • data/search/src/main/java/com/teamsolply/solply/search/dto/response/SearchResponseDto.kt
  • data/maps/src/main/java/com/teamsolply/solply/maps/dto/response/GetCourseDetailResponseDto.kt
  • data/mypage/src/main/java/com/teamsolply/solply/mypage/dto/response/PlaceListResponseDto.kt
  • data/collection/src/main/java/com/teamsolply/solply/collection/dto/response/PlaceListResponseDto.kt

GetPlacesResponseDto๋งŒ ์—…๋ฐ์ดํŠธ๋˜์—ˆ์œผ๋‚˜, ๋ฐฑ์—”๋“œ API ๋ณ€๊ฒฝ์ด ๋‹ค๋ฅธ ์—”๋“œํฌ์ธํŠธ์—๋„ ์ ์šฉ๋˜์—ˆ๋‹ค๋ฉด ์œ„ ํŒŒ์ผ๋“ค๋„ ํ•จ๊ป˜ mainTag๋กœ ์ผ๊ด€๋˜๊ฒŒ ๋ณ€๊ฒฝ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋ถˆ์™„์ „ํ•œ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜์€ ํ•ด๋‹น ์—”๋“œํฌ์ธํŠธ์—์„œ ์ง๋ ฌํ™” ์‹คํŒจ๋ฅผ ์•ผ๊ธฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿค– Prompt for AI Agents
In
data/place/src/main/java/com/teamsolply/solply/place/dto/response/GetPlacesResponseDto.kt
around lines 23-24, the DTO was changed to use @SerialName("mainTag") val
mainTag: String but other DTOs still use primaryTag; update the other DTOs to
match: open each of the listed files and rename the property from primaryTag to
mainTag, add or update @SerialName("mainTag") annotation, ensure the property
type and nullability match the API contract, adjust any imports/usages and
serialization tests or mappers accordingly so all endpoints consistently use
mainTag.

Comment on lines +3 to +4
import com.teamsolply.solply.search.dto.request.RegisterPlaceRequestDto
import com.teamsolply.solply.search.dto.response.RegisterPlaceResponseDto
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

์ƒˆ๋กœ์šด ์žฅ์†Œ ๋“ฑ๋ก API ๊ตฌํ˜„์„ ํ™•์ธํ•ด์ฃผ์„ธ์š”.

SearchRemoteDataSource ์ธํ„ฐํŽ˜์ด์Šค์— requestsPlaces ํ•จ์ˆ˜๊ฐ€ ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ธํ„ฐํŽ˜์ด์Šค ์‹œ๊ทธ๋‹ˆ์ฒ˜๋Š” ์˜ฌ๋ฐ”๋ฅด์ง€๋งŒ, ๊ตฌํ˜„์ฒด์™€ ๊ด€๋ จ DTO, ์„œ๋น„์Šค ๋ ˆ์ด์–ด๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ตฌํ˜„๋˜์—ˆ๋Š”์ง€ ํ™•์ธ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ ์Šคํฌ๋ฆฝํŠธ๋กœ ๊ตฌํ˜„ ์ƒํƒœ๋ฅผ ํ™•์ธํ•˜์„ธ์š”:

Also applies to: 9-9


๐Ÿ Script executed:

#!/bin/bash
# Description: Verify the implementation of requestsPlaces across layers

# Check for implementation in DataSource
echo "=== SearchRemoteDataSource Implementation ==="
rg -A 5 "class.*SearchRemoteDataSourceImpl" --type=kt

# Check for service layer
echo "=== SearchService API Endpoint ==="
rg -A 3 "fun.*requestsPlaces" --type=kt -g '**/service/**'

# Check for DTO definitions
echo "=== RegisterPlace DTOs ==="
fd -e kt "RegisterPlace" --type f

Length of output: 1009


๊ฒ€์ฆ์„ ๊ณ„์† ์ง„ํ–‰ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๋จผ์ € ripgrep ๋ช…๋ น์–ด๋ฅผ ์ˆ˜์ •ํ•˜๊ณ  ๊ด€๋ จ ํŒŒ์ผ๋“ค์„ ํ™•์ธํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.


๐Ÿ Script executed:

#!/bin/bash
# Fixed script to verify requestsPlaces implementation

echo "=== SearchRemoteDataSource Interface and Implementation ==="
rg -A 10 "fun requestsPlaces" data/search/src/main/java/com/teamsolply/solply/search/source/

echo ""
echo "=== SearchRemoteDataSource.kt (First 30 lines) ==="
head -30 data/search/src/main/java/com/teamsolply/solply/search/source/SearchRemoteDataSource.kt

echo ""
echo "=== Checking for SearchRemoteDataSourceImpl ==="
find . -name "*SearchRemoteDataSourceImpl*" -type f

echo ""
echo "=== RegisterPlaceRequestDto content ==="
cat data/search/src/main/java/com/teamsolply/solply/search/dto/request/RegisterPlaceRequestDto.kt

echo ""
echo "=== RegisterPlaceResponseDto content ==="
cat data/search/src/main/java/com/teamsolply/solply/search/dto/response/RegisterPlaceResponseDto.kt

echo ""
echo "=== Checking service layer for requestsPlaces usage ==="
find . -path "*/service/*" -name "*.kt" -type f -exec rg -l "requestsPlaces" {} \;

Length of output: 2280


๊ฒ€์ฆ์„ ๊ณ„์† ์ง„ํ–‰ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๊ตฌํ˜„์ฒด์™€ ์„œ๋น„์Šค ๋ ˆ์ด์–ด๋ฅผ ํ™•์ธํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.


๐Ÿ Script executed:

#!/bin/bash

echo "=== SearchRemoteDataSourceImpl Implementation ==="
cat ./remote/search/src/main/java/com/teamsolply/solply/search/datasource/SearchRemoteDataSourceImpl.kt

echo ""
echo "=== SearchService requestsPlaces usage ==="
rg -B 3 -A 15 "fun requestsPlaces\|requestsPlaces" ./remote/search/src/main/java/com/teamsolply/solply/search/service/SearchService.kt

Length of output: 888


SearchService.kt ํŒŒ์ผ์„ ์ง์ ‘ ํ™•์ธํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.


๐Ÿ Script executed:

#!/bin/bash

echo "=== SearchService.kt full content ==="
cat ./remote/search/src/main/java/com/teamsolply/solply/search/service/SearchService.kt

echo ""
echo "=== Verify RegisterPlaceResponseDto import in SearchRemoteDataSourceImpl ==="
grep -n "RegisterPlaceResponseDto" ./remote/search/src/main/java/com/teamsolply/solply/search/datasource/SearchRemoteDataSourceImpl.kt

Length of output: 887


SearchRemoteDataSourceImpl.kt์—์„œ ๋ฐ˜ํ™˜ ํƒ€์ž… ์„ ์–ธ๊ณผ import ์ถ”๊ฐ€ ํ•„์š”

SearchRemoteDataSource ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌํ˜„์ด ๋ถˆ์™„์ „ํ•ฉ๋‹ˆ๋‹ค:

  • 16๋ฒˆ์งธ ์ค„: requestsPlaces ํ•จ์ˆ˜์— ๋ช…์‹œ์  ๋ฐ˜ํ™˜ ํƒ€์ž… : RegisterPlaceResponseDto ์ถ”๊ฐ€ ํ•„์š”
  • 3๋ฒˆ์งธ ์ค„: RegisterPlaceResponseDto import ๋ˆ„๋ฝ (ํ˜„์žฌ RegisterPlaceRequestDto๋งŒ import๋จ)

SearchService ๋ฐ DTO ์ •์˜๋Š” ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ตฌํ˜„๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๐Ÿค– Prompt for AI Agents
In
data/search/src/main/java/com/teamsolply/solply/search/source/SearchRemoteDataSource.kt
around lines 3 to 16, the implementation is missing the RegisterPlaceResponseDto
import and the explicit return type on the requestsPlaces function; add an
import for com.teamsolply.solply.search.dto.response.RegisterPlaceResponseDto at
the top of the file and update the function signature on line 16 to declare the
return type as : RegisterPlaceResponseDto so the implementation matches the
interface.

Comment on lines +579 to 583
}.onFailure { error ->
android.util.Log.e("PresignedUrl", "โŒ Presigned URL ๋ฐœ๊ธ‰ ์‹คํŒจ: ${error.message}", error)

// TODO. presigned url ๋ฐœ๊ธ‰ ์‹คํŒจ
}
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

Presigned URL ๋ฐœ๊ธ‰ ์‹คํŒจ ์ฒ˜๋ฆฌ ๋ˆ„๋ฝ

Presigned URL ๋ฐœ๊ธ‰ ์‹คํŒจ ์‹œ ๋กœ๊ทธ๋งŒ ์ถœ๋ ฅํ•˜๊ณ  ์‚ฌ์šฉ์ž์—๊ฒŒ ํ”ผ๋“œ๋ฐฑ์ด ์—†์Šต๋‹ˆ๋‹ค. TODO ์ฃผ์„์ด ์žˆ์ง€๋งŒ, ์‚ฌ์šฉ์ž์—๊ฒŒ ์˜ค๋ฅ˜๋ฅผ ์•Œ๋ฆฌ๊ณ  ๋‹ค์ด์–ผ๋กœ๊ทธ๋ฅผ ๋‹ซ๋Š” ๋“ฑ์˜ ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‚ฌ์šฉ์ž ํ”ผ๋“œ๋ฐฑ์„ ์ถ”๊ฐ€ํ•˜์„ธ์š”:

             }.onFailure { error ->
                 android.util.Log.e("PresignedUrl", "โŒ Presigned URL ๋ฐœ๊ธ‰ ์‹คํŒจ: ${error.message}", error)
-
-                // TODO. presigned url ๋ฐœ๊ธ‰ ์‹คํŒจ
+                // TODO: ์‚ฌ์šฉ์ž์—๊ฒŒ ์˜ค๋ฅ˜ ์Šค๋‚ต๋ฐ” ํ‘œ์‹œ
+                delay(2500)
+                sendIntent(MapsIntent.ChangeReportPlaceDialogVisibility(visible = false))
             }

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

๐Ÿค– Prompt for AI Agents
In feature/maps/src/main/java/com/teamsolply/solply/maps/MapsViewModel.kt around
lines 579 to 583, the onFailure block only logs the presigned URL error and
leaves a TODO; update it to provide user feedback and close any related dialog:
set or emit an error UI state (e.g., update LiveData/StateFlow with an error
message), ensure the dialog related to presigned URL creation is dismissed (emit
an event flag or call the dialog-close handler), and optionally show a transient
message (Toast/Snackbar event) so the user sees the failure; keep the existing
Log.e call but add the UI event emission on the main thread so the UI can react.

dependencies {
implementation(projects.domain.place)
implementation(projects.feature.search)
implementation(projects.feature.course)
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

์žฅ์†Œ ๊ธฐ๋Šฅ์˜ ์ฝ”์Šค ๊ธฐ๋Šฅ ์˜์กด์„ฑ ์ถ”๊ฐ€ ํ™•์ธ

feature.course ์˜์กด์„ฑ์ด ์ถ”๊ฐ€๋˜์—ˆ์œผ๋ฉฐ, ์ด๋Š” ์ œ๊ณต๋œ PR ์š”์•ฝ๊ณผ ์ผ์น˜ํ•˜๋Š” ๊ณผ์ •์ž…๋‹ˆ๋‹ค. ๋‹ค๋งŒ, ๋‹ค์Œ ์‚ฌํ•ญ์„ ํ™•์ธํ•ด ์ฃผ์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค:

  1. feature.course๊ฐ€ ์‹ค์ œ๋กœ ์žฅ์†Œ ๊ธฐ๋Šฅ ์ฝ”๋“œ ๋‚ด์—์„œ ์‚ฌ์šฉ๋˜๊ณ  ์žˆ๋Š”์ง€ ํ™•์ธ
  2. ์ˆœํ™˜ ์˜์กด์„ฑ(circular dependency) ๋ฌธ์ œ๊ฐ€ ์—†๋Š”์ง€ ํ™•์ธ (์˜ˆ: feature.course๊ฐ€ feature.place๋ฅผ ์˜์กดํ•˜์ง€ ์•Š๋Š”์ง€)

๋‹ค์Œ ๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด ์ˆœํ™˜ ์˜์กด์„ฑ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:


๐Ÿ Script executed:

#!/bin/bash
# feature/place์™€ feature/course ๊ฐ„์˜ ์ˆœํ™˜ ์˜์กด์„ฑ ํ™•์ธ
# feature/course/build.gradle.kts์—์„œ feature.place ์˜์กด์„ฑ ํ™•์ธ

if [ -f "feature/course/build.gradle.kts" ]; then
    echo "=== Checking feature/course/build.gradle.kts ==="
    grep -n "projects.feature.place" feature/course/build.gradle.kts && echo "โš ๏ธ Circular dependency detected!" || echo "โœ“ No circular dependency found"
else
    echo "feature/course/build.gradle.kts not found"
fi

# feature/place ๋””๋ ‰ํ† ๋ฆฌ ๋‚ด์—์„œ course ๊ด€๋ จ import ํ™•์ธ
echo ""
echo "=== Checking imports in feature/place ==="
fd -e kt -e java -x grep -l "feature\.course\|course" {} \; 2>/dev/null | head -10

Length of output: 1120


๐Ÿ Script executed:

#!/bin/bash
# Properly scoped search for feature/place directory
echo "=== Checking for course-related imports in feature/place source files ==="
fd -e kt -e java . feature/place/src -x grep -l "course\|Course" {} \; 2>/dev/null || echo "No matches found"

echo ""
echo "=== Direct check: feature/place directory structure ==="
ls -la feature/place/ 2>/dev/null || echo "feature/place directory not found"

echo ""
echo "=== Search for actual imports of feature.course or course packages in feature/place ==="
fd -e kt -e java . feature/place -x grep -n "import.*course\|from.*course" {} \; 2>/dev/null | head -20 || echo "No import statements found"

Length of output: 270


๐Ÿ Script executed:

#!/bin/bash
# Find repository structure
echo "=== Finding all build.gradle.kts files ==="
fd -e "build.gradle.kts" 2>/dev/null | head -20

echo ""
echo "=== Finding directories with 'place' in name ==="
fd -t d "place" 2>/dev/null

echo ""
echo "=== Finding directories with 'feature' in name ==="
fd -t d "feature" 2>/dev/null | head -20

echo ""
echo "=== Root directory structure ==="
ls -la 2>/dev/null | head -20

Length of output: 1828


๐Ÿ Script executed:

#!/bin/bash
# Read the build.gradle.kts file
echo "=== Reading feature/place/build.gradle.kts ==="
cat feature/place/build.gradle.kts 2>/dev/null || echo "File not found"

echo ""
echo "=== Verify feature/course module exists ==="
ls -la feature/course 2>/dev/null || echo "feature/course not found"

echo ""
echo "=== Search feature/place source for course imports ==="
grep -r "import.*course\|from.*course" feature/place/src 2>/dev/null | head -20 || echo "No course imports found"

echo ""
echo "=== Search feature/place source for Course class usage ==="
grep -r "Course\|course" feature/place/src 2>/dev/null | grep -v "//\|comment" | head -20 || echo "No Course usage found"

Length of output: 804


๐Ÿ Script executed:

#!/bin/bash
# Final comprehensive search for any course-related usage
echo "=== Final comprehensive search in feature/place ==="
find feature/place/src -type f \( -name "*.kt" -o -name "*.java" \) -exec cat {} \; | grep -i "course" && echo "Found course usage" || echo "No course usage found in feature/place source files"

echo ""
echo "=== List all Kotlin files in feature/place/src ==="
find feature/place/src -type f -name "*.kt" -o -name "*.java"

echo ""
echo "=== Check if there are Navigation or Compose references to course in feature/place ==="
grep -r "navigate\|route\|screen" feature/place/src 2>/dev/null | head -10 || echo "No navigation found"

Length of output: 2887


feature.course ์˜์กด์„ฑ์ด ์‚ฌ์šฉ๋˜์ง€ ์•Š์Œ

๊ฒ€์ฆ ๊ฒฐ๊ณผ, feature/place ๋ชจ๋“ˆ์—์„œ projects.feature.course ์˜์กด์„ฑ์ด ์„ ์–ธ๋˜์–ด ์žˆ์œผ๋‚˜ ์‹ค์ œ ์ฝ”๋“œ์—์„œ๋Š” ์‚ฌ์šฉ๋˜์ง€ ์•Š๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์ˆœํ™˜ ์˜์กด์„ฑ: โœ“ ์—†์Œ
  • ์‹ค์ œ ์‚ฌ์šฉ: โœ— ๋ฏธ์‚ฌ์šฉ (16๊ฐœ์˜ ๋ชจ๋“  Kotlin/Java ํŒŒ์ผ ๊ฒ€ํ† )
    • course ํŒจํ‚ค์ง€ import ์—†์Œ
    • Course ํด๋ž˜์Šค ์ฐธ์กฐ ์—†์Œ
    • ๋„ค๋น„๊ฒŒ์ด์…˜ ์ฝœ๋ฐฑ์—๋„ course ๊ด€๋ จ ๊ธฐ๋Šฅ ์—†์Œ

ํ•ด๊ฒฐ๋ฐฉ์•ˆ: ์˜์กด์„ฑ์„ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ ์ œ๊ฑฐํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š” ์˜์กด์„ฑ์€ ๋นŒ๋“œ ๊ฒฐํ•ฉ๋„๋ฅผ ์ฆ๊ฐ€์‹œํ‚ค๊ณ  ์œ ์ง€๋ณด์ˆ˜๋ฅผ ์–ด๋ ต๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿค– Prompt for AI Agents
In feature/place/build.gradle.kts at line 12, the declared dependency
implementation(projects.feature.course) is unused across the module; remove this
line from the build script to eliminate an unnecessary dependency (or, if the
feature.course API is intended to be used, add the required imports/usages in
the place module and verify compilation). After removing or adding usage, run a
clean build and update module documentation if needed.

val placeAddress: String = "",
val selectedPlaceType: PlaceType? = null,
val searchResults: List<NaverLocalSearchResponseEntity> = persistentListOf(),
// ์ฒซ๋ฒˆ์จฐ
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

์˜คํƒ€๋ฅผ ์ˆ˜์ •ํ•˜์„ธ์š”.

์ฃผ์„์— "์ฒซ๋ฒˆ์จฐ"๊ฐ€ "์ฒซ๋ฒˆ์งธ"๋กœ ์ˆ˜์ •๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

-    // ์ฒซ๋ฒˆ์จฐ
+    // ์ฒซ๋ฒˆ์งธ
     val isPlaceNameSuccess: Boolean = false,
๐Ÿ“ 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
// ์ฒซ๋ฒˆ์จฐ
// ์ฒซ๋ฒˆ์งธ
๐Ÿค– Prompt for AI Agents
In
feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceContract.kt
around line 16, fix the typo in the comment by replacing "์ฒซ๋ฒˆ์จฐ" with "์ฒซ๋ฒˆ์งธ"
(ensure only the comment text is changed and no other code or formatting is
modified).

Comment on lines +177 to +190
val placeKeywords = listOf(
PlaceKeywordItem(7L, "์ปคํ”ผ/๋””์ €ํŠธ"),
PlaceKeywordItem(8L, "์ž‘์—…"),
PlaceKeywordItem(9L, "๋…์„œ"),
PlaceKeywordItem(10L, "ํž๋ง")
)
val placeFeatures = listOf(
PlaceKeywordItem(11L, "์‹œ๊ทธ๋‹ˆ์ฒ˜ ๋ฉ”๋‰ด"),
PlaceKeywordItem(12L, "๊ฐ์„ฑ ์ธํ…Œ๋ฆฌ์–ด"),
PlaceKeywordItem(13L, "์ฝ˜์„ผํŠธ ๋งŽ์Œ"),
PlaceKeywordItem(14L, "์‹œ๊ฐ„์ œํ•œ ์—†์Œ"),
PlaceKeywordItem(15L, "์ฑ„๊ด‘ ์ข‹์Œ"),
PlaceKeywordItem(16L, "๋ฐ”ํ…Œ์ด๋ธ”"),
)
Copy link

Choose a reason for hiding this comment

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

๐Ÿ› ๏ธ Refactor suggestion | ๐ŸŸ  Major

ํ‚ค์›Œ๋“œ์™€ ํŠน์ง• ๋ฐ์ดํ„ฐ๋ฅผ ํ•˜๋“œ์ฝ”๋”ฉํ•˜์ง€ ๋งˆ์„ธ์š”.

placeKeywords์™€ placeFeatures๊ฐ€ Composable ๋‚ด๋ถ€์— ํ•˜๋“œ์ฝ”๋”ฉ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ID ๊ฐ’๋“ค(7L, 8L ๋“ฑ)์ด ๋ฐฑ์—”๋“œ์™€ ์—ฐ๊ด€๋˜์–ด ์žˆ์„ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์œผ๋ฏ€๋กœ, ๋‹ค์Œ ์ค‘ ํ•˜๋‚˜์˜ ๋ฐฉ์‹์œผ๋กœ ๊ฐœ์„ ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค:

  • ViewModel์—์„œ ์ƒํƒœ๋กœ ์ œ๊ณตํ•˜์—ฌ ๋ฐฑ์—”๋“œ์—์„œ ๊ฐ€์ ธ์˜ค๊ธฐ
  • ๋ณ„๋„์˜ Constants ํŒŒ์ผ๋กœ ๋ถ„๋ฆฌํ•˜์—ฌ ์ค‘์•™ ๊ด€๋ฆฌ

Constants๋กœ ๋ถ„๋ฆฌํ•˜๋Š” ์˜ˆ์‹œ:

object PlaceRegistrationConstants {
    val PLACE_KEYWORDS = listOf(
        PlaceKeywordItem(7L, "์ปคํ”ผ/๋””์ €ํŠธ"),
        PlaceKeywordItem(8L, "์ž‘์—…"),
        PlaceKeywordItem(9L, "๋…์„œ"),
        PlaceKeywordItem(10L, "ํž๋ง")
    )
    
    val PLACE_FEATURES = listOf(
        PlaceKeywordItem(11L, "์‹œ๊ทธ๋‹ˆ์ฒ˜ ๋ฉ”๋‰ด"),
        PlaceKeywordItem(12L, "๊ฐ์„ฑ ์ธํ…Œ๋ฆฌ์–ด"),
        PlaceKeywordItem(13L, "์ฝ˜์„ผํŠธ ๋งŽ์Œ"),
        PlaceKeywordItem(14L, "์‹œ๊ฐ„์ œํ•œ ์—†์Œ"),
        PlaceKeywordItem(15L, "์ฑ„๊ด‘ ์ข‹์Œ"),
        PlaceKeywordItem(16L, "๋ฐ”ํ…Œ์ด๋ธ”")
    )
}
๐Ÿค– Prompt for AI Agents
In
feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceScreen.kt
around lines 177-190, the placeKeywords and placeFeatures lists are hardcoded
inside the Composable (including backend-linked IDs); remove these hardcoded
values and provide them from a non-UI source โ€” either expose them as
LiveData/StateFlow in the ViewModel (fetch from backend or initialize there) and
observe that state in the Composable, or move them into a central Constants
object (e.g., PlaceRegistrationConstants) and reference those constants from the
Composable; update usages to read from the ViewModel or constants and delete the
inline lists from the Composable.

Comment on lines +36 to +49
override fun handleIntent(intent: RegisterPlaceIntent) {
when (intent) {
is RegisterPlaceIntent.InputPlaceNameText -> {
reduce {
copy(placeName = intent.text)
}
searchJob?.cancel()
searchJob = viewModelScope.launch {
delay(500)
if (intent.text.length >= 2) {
searchAddress(intent.text)
}
}
}
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

๊ฒ€์ƒ‰ ๋””๋ฐ”์šด์Šค ๊ตฌ์กฐ ๋•Œ๋ฌธ์— ์ด์ „ ๋„คํŠธ์›Œํฌ ์š”์ฒญ์ด ์ทจ์†Œ๋˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • InputPlaceNameText์—์„œ searchJob์„ ์ทจ์†Œํ•ด ๋””๋ฐ”์šด์Šค๋ฅผ ๊ตฌํ˜„ํ•œ ์ ์€ ์ข‹์ง€๋งŒ, searchAddress ๋‚ด๋ถ€์—์„œ ๋‹ค์‹œ viewModelScope.launch { ... }๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด์„œ ๋””๋ฐ”์šด์Šค Job๊ณผ ์‹ค์ œ ๋„คํŠธ์›Œํฌ Job์ด ๋ถ„๋ฆฌ๋ฉ๋‹ˆ๋‹ค.
  • ๊ทธ ๊ฒฐ๊ณผ, ์ด์ „ ๊ฒ€์ƒ‰์˜ ๋„คํŠธ์›Œํฌ ์š”์ฒญ์ด ์•„์ง ์ง„ํ–‰ ์ค‘์ธ ์ƒํƒœ์—์„œ ์‚ฌ์šฉ์ž๊ฐ€ ์ƒˆ๋กœ์šด ๊ฒ€์ƒ‰์–ด๋ฅผ ์ž…๋ ฅํ•˜๋ฉด, ๋Šฆ๊ฒŒ ๋๋‚œ ์ด์ „ ์š”์ฒญ ๊ฒฐ๊ณผ๊ฐ€ ์ตœ์‹  ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ๋ฅผ ๋ฎ์–ด์“ฐ๋Š” ์ƒํ™ฉ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ˆ˜์ • ๋ฐฉํ–ฅ ์ œ์•ˆ:

  1. searchAddress๋ฅผ suspend ํ•จ์ˆ˜๋กœ ๋ฐ”๊พธ๊ณ , ๋””๋ฐ”์šด์Šค ์ฝ”๋ฃจํ‹ด ๋‚ด๋ถ€์—์„œ ์ง์ ‘ ํ˜ธ์ถœํ•ด ๊ฐ™์€ Job์— ๋ฌถ์ด๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
  2. ์‹คํŒจ ์ผ€์ด์Šค๋„ ๊ฐ™์ด ์ฒ˜๋ฆฌํ•˜๋ฉด UX๊ฐ€ ๋” ์•ˆ์ •์ ์ž…๋‹ˆ๋‹ค.
-    private fun searchAddress(query: String) {
-        viewModelScope.launch {
-            searchRepository.searchAddress(query = query)
-                .onSuccess {
-                    reduce {
-                        copy(searchResults = it)
-                    }
-                }
-        }
-    }
+    private suspend fun searchAddress(query: String) {
+        searchRepository.searchAddress(query = query)
+            .onSuccess { results ->
+                reduce { copy(searchResults = results) }
+            }
+            .onFailure {
+                // ํ•„์š”ํ•˜๋‹ค๋ฉด ๋กœ๊ทธ/์—๋Ÿฌ ์ƒํƒœ ์—…๋ฐ์ดํŠธ
+            }
+    }

์œ„ ๋ณ€๊ฒฝ ํ›„ InputPlaceNameText์˜ launch ๋ธ”๋ก ์•ˆ์—์„œ๋Š” ๊ทธ๋Œ€๋กœ searchAddress(intent.text)๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด searchJob?.cancel()๋กœ ๋””๋ฐ”์šด์Šค Job์„ ์ทจ์†Œํ•  ๋•Œ ๋„คํŠธ์›Œํฌ ์š”์ฒญ๋„ ํ•จ๊ป˜ ์ทจ์†Œ๋ฉ๋‹ˆ๋‹ค.

Also applies to: 128-137

๐Ÿค– Prompt for AI Agents
In
feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceViewModel.kt
around lines 36-49 (and similarly for the block at 128-137), the debounce Job
cancels but the actual network request is launched in a separate coroutine
inside searchAddress, so cancelling searchJob does not cancel the network call;
make searchAddress a suspend function (remove its internal
viewModelScope.launch), surface network call exceptions/results through return
values or sealed results, and call searchAddress(intent.text) directly inside
the debounce coroutine launched for searchJob so that cancelling searchJob
cancels the network request as well; also handle failure cases (emit error state
or a retry indicator) so the UI remains consistent.

@coderabbitai coderabbitai bot mentioned this pull request Jan 6, 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.

[Refactor] ์žฅ์†Œ ui 1์ฐจ ์ˆ˜์ •

2 participants