Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
6f00438
[fix] 보호장소, 발견장소 데이터 수정
ikseong00 Jan 4, 2026
bcd27bc
[fix] 하단바(BNV) 노출 로직 수정
ikseong00 Jan 4, 2026
7a28f91
[feat] bg_radius_20 배경 색상 제거
ikseong00 Jan 4, 2026
f033342
[refactor] 보호 장소 UI 수정
ikseong00 Jan 4, 2026
bed4636
[fix] 디스코드 에러 로깅 범위 수정
ikseong00 Jan 4, 2026
e5ff60c
[feat] 게스트 로그인 버튼 UI 복원
ikseong00 Jan 4, 2026
0a23bc3
[fix] 지도 위치 정보 없을 시 지도 숨김 처리
ikseong00 Jan 4, 2026
dffa147
[refactor] 게스트 로그인 토스트 메시지 수정
ikseong00 Jan 4, 2026
80b9257
[feat] refreshToken 추가
ikseong00 Jan 4, 2026
40cd83a
[refactor] 메인 컬러 변경
ikseong00 Jan 4, 2026
3ce4483
[fix] 회원 탈퇴 완료 시 토큰을 제거하는 것으로 수정
ikseong00 Jan 4, 2026
e91d2c2
[feat] 조회 createdAt 필드 추가
ikseong00 Jan 4, 2026
76944d8
[refactor] 온보딩 프로필 설정 로직 제거
ikseong00 Jan 4, 2026
a8886ac
[refactor] 스플래시 화면 레거시 색상 적용
ikseong00 Jan 4, 2026
1bca665
[fix] 마이페이지 프로필 응답값 수정
ikseong00 Jan 9, 2026
a7b9f3a
[refactor] 회원가입 API 요청 형식 변경
ikseong00 Jan 9, 2026
af8f1a5
[feat] 토큰 재발급 API 구현
ikseong00 Jan 9, 2026
c511eb7
[feat] 토큰 재발급 로직 구현
ikseong00 Jan 9, 2026
de3647c
[feat] 게스트 로그인 시 이미 가입된 계정이면 에러 메시지 표시
ikseong00 Jan 9, 2026
450d33b
[feat] 게스트 유저 제보 기능 제한
ikseong00 Jan 9, 2026
b96e2d9
[feat] 홈 화면 스크롤 최상단 이동 버튼 제거
ikseong00 Jan 13, 2026
3bfa6be
[chore] 앱 버전 정보 업데이트
ikseong00 Jan 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ android {
applicationId = "com.kuit.findu"
minSdk = 28
targetSdk = 35
versionCode = 12
versionName = "1.0.11"
versionCode = 13
versionName = "1.0.12"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
buildConfigField("String", "GPT_KEY", properties["GPT_KEY"].toString())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.kuit.findu.data.datalocal.datasource
interface DeviceLocalDataSource {
var deviceId: String
var nickname: String
var isGuestLogin: Boolean

fun clear()
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ class DeviceLocalDataSourceImpl @Inject constructor(
get() = sharedPreferences.getString(NICKNAME, INITIAL_VALUE).toString()
set(value) = sharedPreferences.edit { putString(NICKNAME, value) }

override var isGuestLogin: Boolean
get() = sharedPreferences.getBoolean(IS_GUEST_LOGIN, false)
set(value) = sharedPreferences.edit { putBoolean(IS_GUEST_LOGIN, value) }

override fun clear() {
val currentDeviceId = deviceId
sharedPreferences.edit {
Expand All @@ -34,6 +38,7 @@ class DeviceLocalDataSourceImpl @Inject constructor(
const val PREFERENCES_NAME = "device_preferences"
const val DEVICE_ID = "deviceId"
const val NICKNAME = "nickname"
const val IS_GUEST_LOGIN = "isGuestLogin"

const val INITIAL_VALUE = ""
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,23 @@ import com.kuit.findu.data.dataremote.model.base.NullableBaseResponse
import com.kuit.findu.data.dataremote.model.request.CheckNicknameRequestDto
import com.kuit.findu.data.dataremote.model.request.GuestLoginRequestDto
import com.kuit.findu.data.dataremote.model.request.LoginRequestDto
import com.kuit.findu.data.dataremote.model.request.PostUserRequestDto
import com.kuit.findu.data.dataremote.model.response.CheckNicknameResponseDto
import com.kuit.findu.data.dataremote.model.response.auth.GuestLoginResponseDto
import com.kuit.findu.data.dataremote.model.response.auth.LoginResponseDto
import com.kuit.findu.data.dataremote.model.response.auth.UserInfoDto
import com.kuit.findu.data.dataremote.service.AuthService
import com.kuit.findu.data.mapper.torequest.toImageMultipart
import com.kuit.findu.data.mapper.torequest.toPlainTextRequestBody
import java.io.File
import javax.inject.Inject

class AuthRemoteDataSourceImpl @Inject constructor(
private val authService: AuthService
private val authService: AuthService,
) : AuthRemoteDataSource {
override suspend fun postLogin(loginRequestDto: LoginRequestDto): NullableBaseResponse<LoginResponseDto> =
authService.postLogin(loginRequestDto=loginRequestDto)
authService.postLogin(loginRequestDto = loginRequestDto)

override suspend fun postGuestLogin(guestLoginRequestDto: GuestLoginRequestDto): NullableBaseResponse<GuestLoginResponseDto> =
authService.postGuestLogin(guestLoginRequestDto=guestLoginRequestDto)
authService.postGuestLogin(guestLoginRequestDto = guestLoginRequestDto)

override suspend fun postCheckNickname(nickname: String): BaseResponse<CheckNicknameResponseDto> =
authService.postCheckNickname(CheckNicknameRequestDto(nickname))
Expand All @@ -33,12 +32,8 @@ class AuthRemoteDataSourceImpl @Inject constructor(
defaultImageName: String?,
nickname: String,
kakaoId: Long,
deviceId: String
deviceId: String,
): NullableBaseResponse<UserInfoDto> = authService.postSignup(
profileImage = profileImageFile?.toImageMultipart("profileImage"),
defaultImageName = defaultImageName?.toPlainTextRequestBody(),
nickname = nickname.toPlainTextRequestBody(),
kakaoId = kakaoId.toString().toPlainTextRequestBody(),
deviceId = deviceId.toPlainTextRequestBody()
PostUserRequestDto(nickname, kakaoId, deviceId)
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.kuit.findu.data.dataremote.exception

class ApiNotFoundException(
message: String,
) : Exception(message)
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.kuit.findu.data.dataremote.model.request

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class PostUserRequestDto(
@SerialName("nickname")
val nickname: String,
@SerialName("kakaoId")
val kakaoId: Long,
@SerialName("deviceId")
val deviceId: String,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.kuit.findu.data.dataremote.model.request

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class TokenReissueRequestDto(
@SerialName("refreshToken")
val refreshToken: String,
)
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,7 @@ data class GuestLoginResponseDto(
@SerialName("userId")
val userId: Long,
@SerialName("accessToken")
val accessToken: String
val accessToken: String,
@SerialName("refreshToken")
val refreshToken: String
)
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,7 @@ data class UserInfoDto(
@SerialName("nickname")
val nickname: String,
@SerialName("accessToken")
val accessToken: String
val accessToken: String,
@SerialName("refreshToken")
val refreshToken: String,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.kuit.findu.data.dataremote.model.response.auth

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class TokenReissueResponseDto(
@SerialName("accessToken")
val accessToken: String,
@SerialName("refreshToken")
val refreshToken: String,
)
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ data class MyNickNameResponseDto(
@SerialName("nickname")
val nickname: String,
@SerialName("profileImage")
val profileImage : String,
val profileImage : String? = null,
)
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ data class DetailMissingResponseDto(
@SerialName("significant") val significant: String,
@SerialName("missingLocation") val missingLocation: String,
@SerialName("missingAddress") val missingAddress: String,
@SerialName("latitude") val latitude: Double,
@SerialName("longitude") val longitude: Double,
@SerialName("latitude") val latitude: Double?,
@SerialName("longitude") val longitude: Double?,
@SerialName("reporterName") val reporterName: String,
@SerialName("reporterTel") val reporterTel: String,
@SerialName("interest") val interest: Boolean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ data class DetailProtectResponseDto(
@SerialName("careAddr")
val careAddr: String,
@SerialName("latitude")
val latitude: Double,
val latitude: Double?,
@SerialName("longitude")
val longitude: Double,
val longitude: Double?,
@SerialName("careTel")
val careTel: String,
@SerialName("foundDate")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ data class DetailWitnessResponseDto(
@SerialName("significant") val significant: String,
@SerialName("witnessLocation") val witnessLocation: String,
@SerialName("witnessAddress") val witnessAddress: String,
@SerialName("latitude") val latitude: Double,
@SerialName("longitude") val longitude: Double,
@SerialName("latitude") val latitude: Double?,
@SerialName("longitude") val longitude: Double?,
@SerialName("reporterInfo") val reporterInfo: String,
@SerialName("witnessDate") val witnessDate: String,
@SerialName("interest") val interest: Boolean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ data class SearchResponseDto(
@SerialName("cards")
val cards: List<SearchAnimalCard>,
@SerialName("lastId")
val lastId : Long?,
val lastId: Long?,
@SerialName("isLast")
val isLast : Boolean
val isLast: Boolean,
)

@Serializable
Expand All @@ -28,5 +28,7 @@ data class SearchAnimalCard(
@SerialName("location")
val location: String,
@SerialName("interest")
val interest: Boolean = false
val interest: Boolean = false,
@SerialName("createdAt")
val createdAt: String,
)
Original file line number Diff line number Diff line change
Expand Up @@ -5,43 +5,36 @@ import com.kuit.findu.data.dataremote.model.base.NullableBaseResponse
import com.kuit.findu.data.dataremote.model.request.CheckNicknameRequestDto
import com.kuit.findu.data.dataremote.model.request.GuestLoginRequestDto
import com.kuit.findu.data.dataremote.model.request.LoginRequestDto
import com.kuit.findu.data.dataremote.model.request.PostUserRequestDto
import com.kuit.findu.data.dataremote.model.response.CheckNicknameResponseDto
import com.kuit.findu.data.dataremote.model.response.auth.GuestLoginResponseDto
import com.kuit.findu.data.dataremote.model.response.auth.LoginResponseDto
import com.kuit.findu.data.dataremote.model.response.auth.UserInfoDto
import com.kuit.findu.data.dataremote.util.ApiConstraints.API
import com.kuit.findu.data.dataremote.util.ApiConstraints.AUTH
import com.kuit.findu.data.dataremote.util.ApiConstraints.VERSION
import okhttp3.MultipartBody
import okhttp3.RequestBody
import retrofit2.http.Body
import retrofit2.http.Multipart
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

사용되지 않는 import 제거 필요

@Multipart 어노테이션 import가 더 이상 사용되지 않습니다. postSignup@Body로 변경되면서 불필요해졌네요.

🧹 수정 제안
-import retrofit2.http.Multipart
📝 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
import retrofit2.http.Multipart
🤖 Prompt for AI Agents
In @app/src/main/java/com/kuit/findu/data/dataremote/service/AuthService.kt at
line 17, Remove the now-unused import retrofit2.http.Multipart from
AuthService.kt because postSignup was converted to use @Body (the @Multipart
annotation is no longer applied); delete the import and run an
auto-organize-imports or rebuild to ensure no other references to Multipart
remain, checking the postSignup method signature to confirm it uses @Body only.

import retrofit2.http.POST
import retrofit2.http.Part

interface AuthService {
@POST("/$API/$VERSION/$AUTH/login/kakao")
suspend fun postLogin(
@Body loginRequestDto: LoginRequestDto
@Body loginRequestDto: LoginRequestDto,
): NullableBaseResponse<LoginResponseDto>

@POST("/$API/$VERSION/$AUTH/login/guest")
suspend fun postGuestLogin(
@Body guestLoginRequestDto: GuestLoginRequestDto
@Body guestLoginRequestDto: GuestLoginRequestDto,
): NullableBaseResponse<GuestLoginResponseDto>

@POST("/$API/$VERSION/users/check/duplicate-nickname")
suspend fun postCheckNickname(
@Body checkNicknameRequestDto: CheckNicknameRequestDto
@Body checkNicknameRequestDto: CheckNicknameRequestDto,
): BaseResponse<CheckNicknameResponseDto>

@Multipart
@POST("/$API/$VERSION/users")
suspend fun postSignup(
@Part profileImage: MultipartBody.Part?,
@Part("defaultProfileImageName") defaultImageName: RequestBody?,
@Part("nickname") nickname: RequestBody,
@Part("kakaoId") kakaoId: RequestBody,
@Part("deviceId") deviceId: RequestBody
@Body postUserRequestDto: PostUserRequestDto,
): NullableBaseResponse<UserInfoDto>
Comment on lines 36 to 39
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find PostUserRequestDto.kt
fd -t f "PostUserRequestDto.kt" -x cat {}

Repository: FindYou-Kuit/FindYou-Android

Length of output: 200


🏁 Script executed:

#!/bin/bash
# Check postSignup usage and AuthRemoteDataSourceImpl
rg -n -A 5 "postSignup" --type kotlin

Repository: FindYou-Kuit/FindYou-Android

Length of output: 7469


🏁 Script executed:

#!/bin/bash
# Check AuthService.kt to see the current state
fd -t f "AuthService.kt" -x head -50 {}

Repository: FindYou-Kuit/FindYou-Android

Length of output: 1864


🏁 Script executed:

#!/bin/bash
# Find and examine PostUserRequestDto
fd -t f "PostUserRequestDto.kt" -x cat {}

Repository: FindYou-Kuit/FindYou-Android

Length of output: 413


🏁 Script executed:

#!/bin/bash
# Check if profile image is handled elsewhere in signup flow
rg -n "profileImage|profileImageFile" --type kotlin -i

Repository: FindYou-Kuit/FindYou-Android

Length of output: 11794


회원가입 API JSON 형식 변경 깔끔하게 처리됨

Multipart에서 JSON Body로 변경된 부분이 잘 정리되어 있습니다. PostUserRequestDto는 nickname, kakaoId, deviceId만 담고 있으며, AuthService.postSignup에서 @Body로 깔끔하게 처리되고 있네요.

다만 한 가지 주의할 점이 있습니다: PostSignupUseCase → AuthRepository → AuthRepositoryImpl → AuthRemoteDataSource → AuthRemoteDataSourceImpl으로 이어지는 체인 전체에서 profileImageFile과 defaultImageName 파라미터가 계속 전달되고 있지만, 실제로는 AuthRemoteDataSourceImpl에서 이들을 사용하지 않고 있습니다. 프로필 이미지는 회원가입 후 PatchProfileImageUseCase를 통해 별도로 처리되고 있으므로, 불필요한 파라미터들은 정리하는 것을 고려해보세요.

🤖 Prompt for AI Agents
In @app/src/main/java/com/kuit/findu/data/dataremote/service/AuthService.kt
around lines 36 - 39, The chain passes unused profileImageFile and
defaultImageName parameters all the way to AuthRemoteDataSourceImpl; remove
these unused parameters from signatures and calls across PostSignupUseCase,
AuthRepository, AuthRepositoryImpl, AuthRemoteDataSource, and
AuthRemoteDataSourceImpl, updating method signatures and call sites to only take
the necessary PostUserRequestDto (nickname, kakaoId, deviceId); ensure any
interface implementations match the updated AuthRepository/AuthRemoteDataSource
signatures and run tests to catch any remaining call sites.

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.kuit.findu.data.dataremote.service

import com.kuit.findu.data.dataremote.model.base.BaseResponse
import com.kuit.findu.data.dataremote.model.request.TokenReissueRequestDto
import com.kuit.findu.data.dataremote.model.response.auth.TokenReissueResponseDto
import com.kuit.findu.data.dataremote.util.ApiConstraints.API
import com.kuit.findu.data.dataremote.util.ApiConstraints.AUTH
import com.kuit.findu.data.dataremote.util.ApiConstraints.VERSION
import retrofit2.http.Body
import retrofit2.http.POST

interface ReissueService {

@POST("/$API/$VERSION/$AUTH/reissue/token")
suspend fun postReissueToken(
@Body tokenReissueRequestDto: TokenReissueRequestDto,
): BaseResponse<TokenReissueResponseDto>
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.kuit.findu.data.dataremote.util

import com.kuit.findu.data.dataremote.exception.ApiNotFoundException
import com.kuit.findu.data.dataremote.model.base.BaseResponse
import com.kuit.findu.data.dataremote.model.base.NullableBaseResponse

Expand Down Expand Up @@ -28,8 +29,13 @@ fun <T> NullableBaseResponse<T>.handleBaseResponse(): Result<T?> =
Result.success(this.data)
}


in 400..499 -> { // 클라이언트 에러
Result.failure(Exception("Client error : ${this.message}"))
if (this.code == 404) {
Result.failure(ApiNotFoundException("Client error : ${this.message}"))
} else {
Result.failure(Exception("Client error : ${this.message}"))
}
}

in 500..599 -> { // 서버 에러
Expand Down
Original file line number Diff line number Diff line change
@@ -1,34 +1,53 @@
package com.kuit.findu.data.dataremote.util

import android.content.Context
import android.content.Intent
import com.kuit.findu.data.datalocal.datasource.TokenLocalDataSource
import com.kuit.findu.presentation.ui.login.LoginActivity
import dagger.hilt.android.qualifiers.ApplicationContext
import okhttp3.Interceptor
import com.kuit.findu.data.dataremote.model.request.TokenReissueRequestDto
import com.kuit.findu.data.dataremote.service.ReissueService
import kotlinx.coroutines.runBlocking
import okhttp3.Authenticator
import okhttp3.Request
import okhttp3.Response
import okhttp3.Route
import javax.inject.Inject

class AuthAuthenticator @Inject constructor(
private val tokenLocalDataSource: TokenLocalDataSource,
@ApplicationContext private val context: Context
) : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
val response = chain.proceed(request)

private val reissueService: ReissueService,
) : Authenticator {
override fun authenticate(route: Route?, response: Response): Request? {
// 401 Unauthorized 에러 감지
if (response.code == 401) {
// 토큰 삭제
tokenLocalDataSource.clearToken()
return try {
val refreshToken = tokenLocalDataSource.refreshToken

// 토큰 재발급 요청
val reissueResponse = runBlocking {
reissueService.postReissueToken(
TokenReissueRequestDto(refreshToken)
)
}

if (reissueResponse.success) {
// 새로운 토큰으로 저장
tokenLocalDataSource.accessToken = reissueResponse.data.accessToken
tokenLocalDataSource.refreshToken = reissueResponse.data.refreshToken

// 로그인 화면으로 이동
val intent = Intent(context, LoginActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
// 새로운 토큰으로 원래 요청 재시도
response.request.newBuilder()
.header("Authorization", "Bearer ${reissueResponse.data.accessToken}")
.build()
} else {
// 토큰 재발급 실패 - 로그인 화면으로 이동
tokenLocalDataSource.clearToken()
null
}
} catch (e: Exception) {
// 토큰 재발급 중 오류 발생 - 로그인 화면으로 이동
tokenLocalDataSource.clearToken()
null
}
context.startActivity(intent)
}

return response
return null
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class ErrorTrackingInterceptor @Inject constructor(
key("api_status", code)
}

if (code in 500..599) {
if (code in 400..599) {
CoroutineScope(Dispatchers.IO).launch {
discordLogger.logServerError(
code = code,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ import com.kuit.findu.domain.model.GuestLoginData
fun GuestLoginResponseDto.toDomain(): GuestLoginData =
GuestLoginData(
userId = this.userId,
accessToken = this.accessToken
accessToken = this.accessToken,
refreshToken = this.refreshToken
)
Loading
Loading