Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions app/src/main/java/com/yapp/twix/di/InitKoin.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.yapp.twix.di

import android.content.Context
import com.twix.data.di.dataModule
import com.twix.network.di.networkModule
import com.twix.ui.di.uiModule
import org.koin.android.ext.koin.androidContext
Expand All @@ -19,6 +20,7 @@ fun initKoin(
addAll(extraModules)
addAll(featureModules)
addAll(networkModule)
addAll(dataModule)
add(uiModule)
},
)
Expand Down

This file was deleted.

1 change: 1 addition & 0 deletions core/network/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,5 @@ android {
dependencies {
implementation(libs.bundles.ktor)
implementation(libs.ktorfit.lib)
ksp(libs.ktorfit.ksp)
Copy link
Member Author

@chanho0908 chanho0908 Jan 22, 2026

Choose a reason for hiding this comment

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

이 설정이 있어야 createOnboardingService 처럼 Ktrofit이 서비스 인터페이스 프록시를 만들기 때문에 추가했어 !

single<OnboardingService> {
    get<Ktorfit>().createOnboardingService()
}

}
15 changes: 15 additions & 0 deletions core/network/src/main/java/com/twix/network/HttpClientProvider.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import io.ktor.client.HttpClientConfig
import io.ktor.client.plugins.HttpTimeout
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
import io.ktor.client.plugins.defaultRequest
import io.ktor.client.plugins.logging.ANDROID
import io.ktor.client.plugins.logging.LogLevel
import io.ktor.client.plugins.logging.Logger
import io.ktor.client.plugins.logging.Logging
import io.ktor.http.ContentType
import io.ktor.http.contentType
Expand All @@ -24,6 +26,18 @@ internal object HttpClientProvider {
configureLogging(isDebug)
configureTimeout()
configureDefaultRequest(baseUrl)

// TODO : 토큰 관련 기능 구현 후 적용
// install(Auth) {
// bearer {
// loadTokens {
// BearerTokens(
// accessToken = "",
// refreshToken = "",
// )
// }
// }
// }
}

private fun HttpClientConfig<*>.configureContentNegotiation(isDebug: Boolean) {
Expand All @@ -46,6 +60,7 @@ internal object HttpClientProvider {
} else {
LogLevel.NONE
}
logger = Logger.ANDROID
Copy link
Member Author

Choose a reason for hiding this comment

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

이 설정을 추가하지 않으니까 Logcat에서 로그가 안찍히더라구 !
로그캣과 연동해서 로그가 출력되는걸 확인했는데 혹시 다른 의견 있으면 남겨줘 !

Image

Copy link
Member

Choose a reason for hiding this comment

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

Logger.ANDROID 그대로 쓰면 될 것 같아요!


sanitizeHeader { header -> header == SANITIZE_HEADER }
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
package com.twix.network.di

import com.twix.network.service.OnboardingService
import com.twix.network.service.createOnboardingService
import de.jensklingenberg.ktorfit.Ktorfit
import org.koin.dsl.module

internal val apiServiceModule =
module {
single<OnboardingService> {
get<Ktorfit>().createOnboardingService()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ internal val httpClientModule =
)
}

single {
single<Ktorfit> {
Ktorfit
.Builder()
.baseUrl(BuildConfig.BASE_URL)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ package com.twix.network.di
val networkModule =
listOf(
httpClientModule,
apiServiceModule,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.twix.network.model.request

import kotlinx.serialization.Serializable

@Serializable
data class AnniversaryRequest(
val anniversaryDate: String,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.twix.network.model.request

import kotlinx.serialization.Serializable

@Serializable
data class CoupleConnectionRequest(
val inviteCode: String,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.twix.network.model.request

import kotlinx.serialization.Serializable

@Serializable
data class ProfileRequest(
val nickname: String,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.twix.network.model.response.onboarding

import kotlinx.serialization.Serializable

@Serializable
data class InviteCodeResponse(
val inviteCode: String,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.twix.network.model.response.onboarding

import kotlinx.serialization.Serializable

@Serializable
data class OnBoardingStatusResponse(
val status: String,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.twix.network.service

import com.twix.network.model.request.AnniversaryRequest
import com.twix.network.model.request.CoupleConnectionRequest
import com.twix.network.model.request.ProfileRequest
import com.twix.network.model.response.onboarding.InviteCodeResponse
import com.twix.network.model.response.onboarding.OnBoardingStatusResponse
import de.jensklingenberg.ktorfit.http.Body
import de.jensklingenberg.ktorfit.http.GET
import de.jensklingenberg.ktorfit.http.POST

interface OnboardingService {
@POST("onboarding/anniversary")
suspend fun anniversarySetup(
@Body request: AnniversaryRequest,
)
Comment on lines 13 to 16
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

rg -n "Anniversary" --type=kotlin -g '!**/build/**'

Repository: YAPP-Github/Twix-Android

Length of output: 50


🏁 Script executed:

cat core/network/src/main/java/com/twix/network/service/OnboardingService.kt

Repository: YAPP-Github/Twix-Android

Length of output: 1057


🏁 Script executed:

# Search for request/response models in the same directory as OnboardingService
fd -e "kt" core/network/src/main/java/com/twix/network/ | head -20

Repository: YAPP-Github/Twix-Android

Length of output: 549


🏁 Script executed:

# List all request models to see the pattern
fd -e "Request.kt" core/network/src/main/java/com/twix/network/model/request/

Repository: YAPP-Github/Twix-Android

Length of output: 605


🏁 Script executed:

# Check if there's an AnniversarySetupRequest or similar already defined
rg "AnniversarySetup|AnniversaryRequest" --type=kotlin

Repository: YAPP-Github/Twix-Android

Length of output: 50


🏁 Script executed:

# Look at some example request DTOs to understand the pattern
cat core/network/src/main/java/com/twix/network/model/request/CoupleConnectionRequest.kt

Repository: YAPP-Github/Twix-Android

Length of output: 230


🏁 Script executed:

fd . 'core/network/src/main/java/com/twix/network/model/request/' --extension kt

Repository: YAPP-Github/Twix-Android

Length of output: 228


🏁 Script executed:

cat core/network/src/main/java/com/twix/network/model/request/ProfileRequest.kt

Repository: YAPP-Github/Twix-Android

Length of output: 219


🏁 Script executed:

# Search for other `@Body` request: String patterns in the codebase
rg "@Body.*String" --type=kotlin

Repository: YAPP-Github/Twix-Android

Length of output: 171


anniversarySetup도 전용 Request DTO를 사용해야 합니다.

coupleConnectionprofileSetup은 각각 CoupleConnectionRequest, ProfileRequest 같은 데이터 클래스를 사용하고 있는데, anniversarySetup@Body request: String으로 되어 있습니다.

왜 문제가 되나요?

  • 타입 안정성 부족: 단순 String으로는 요청 데이터가 무엇인지 명확하지 않습니다
  • Swagger 문서화 어려움: DTO가 없으면 API 스펙이 정확하게 생성되지 않습니다
  • 일관성 깨짐: 같은 패턴의 엔드포인트들이 다르게 구현되어 유지보수가 어렵습니다
  • 직렬화 검증 불가: 데이터 유효성 검증을 위해 @Serializable 데코레이터를 적용할 수 없습니다

개선 방법:
AnniversarySetupRequest 데이터 클래스를 만들어서 사용하세요:

// com.twix.network.model.request 패키지에 추가
`@Serializable`
data class AnniversarySetupRequest(
    val month: Int,
    val day: Int,
    // 실제 필요한 필드들...
)

// OnboardingService에서
suspend fun anniversarySetup(
    `@Body` request: AnniversarySetupRequest,
)

API 문서나 백엔드 스펙을 확인해서 anniversary 엔드포인트가 어떤 필드를 요구하는지 알려주실 수 있나요?

🤖 Prompt for AI Agents
In `@core/network/src/main/java/com/twix/network/service/OnboardingService.kt`
around lines 12 - 15, The anniversarySetup API currently accepts a raw String;
create a typed request DTO (e.g.,
com.twix.network.model.request.AnniversarySetupRequest annotated with
`@Serializable` containing fields like month: Int, day: Int and any other required
properties) and change OnboardingService.anniversarySetup to accept `@Body`
request: AnniversarySetupRequest instead of String; confirm the exact fields
against the API/back-end spec and add any missing properties and validation
annotations.

Comment on lines 14 to 16
Copy link
Member

Choose a reason for hiding this comment

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

이 부분도 요청 DTO 만들어서 수정해주세요!

Copy link
Member Author

Choose a reason for hiding this comment

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

에고... 꼼꼼하게 봐줘서 고마워 !

리뷰 반영 커밋 : 3216d74


@POST("onboarding/couple-connection")
suspend fun coupleConnection(
@Body request: CoupleConnectionRequest,
)

@POST("onboarding/profile")
suspend fun profileSetup(
@Body request: ProfileRequest,
)
Comment on lines 13 to 26
Copy link
Member

Choose a reason for hiding this comment

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

Swagger상 request body가 JSON인데 지금은 문자열 그대로 보내고 있어서 통신이 안될 가능성이 높아 보여요. Request DTO 만들어서 @Body로 보내는 형태로 수정해주세요!

Copy link
Member Author

@chanho0908 chanho0908 Jan 26, 2026

Choose a reason for hiding this comment

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

리뷰 반영 완료 !

리뷰 반영 커밋 e97f63b


@GET("onboarding/invite-code")
suspend fun fetchInviteCode(): InviteCodeResponse

@GET("onboarding/status")
suspend fun fetchOnBoardingStatus(): OnBoardingStatusResponse
}
1 change: 0 additions & 1 deletion data/src/main/java/com/twix/data/.gitkeep

This file was deleted.

6 changes: 6 additions & 0 deletions data/src/main/java/com/twix/data/di/DataModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.twix.data.di

val dataModule =
listOf(
repositoryModule,
)
12 changes: 12 additions & 0 deletions data/src/main/java/com/twix/data/di/RepositoryModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.twix.data.di

import com.twix.data.repository.DefaultOnboardingRepository
import com.twix.domain.repository.OnBoardingRepository
import org.koin.dsl.module

internal val repositoryModule =
module {
single<OnBoardingRepository> {
DefaultOnboardingRepository(get())
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.twix.data.repository

import com.twix.domain.model.InviteCode
import com.twix.domain.model.OnboardingStatus
import com.twix.domain.repository.OnBoardingRepository
import com.twix.network.model.request.AnniversaryRequest
import com.twix.network.model.request.CoupleConnectionRequest
import com.twix.network.model.request.ProfileRequest
import com.twix.network.service.OnboardingService

class DefaultOnboardingRepository(
private val service: OnboardingService,
) : OnBoardingRepository {
override suspend fun fetchInviteCode(): InviteCode {
val response = service.fetchInviteCode()
return InviteCode(response.inviteCode)
}
Comment on lines +11 to +17
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Find other Repository implementations to check error handling patterns
fd -e kt -path '*repository*' -type f | head -20

Repository: YAPP-Github/Twix-Android

Length of output: 236


🏁 Script executed:

# Search for error handling patterns in repository classes
rg -n "runCatching|try\s*\{|Result<|catch\s*\(" --type=kotlin -g '*Repository*' -A 2

Repository: YAPP-Github/Twix-Android

Length of output: 50


🏁 Script executed:

# Look for domain error model definitions
fd -e kt -type f | xargs grep -l "sealed.*Error\|sealed.*class.*Error\|object.*Error" | head -20

Repository: YAPP-Github/Twix-Android

Length of output: 238


🏁 Script executed:

# Check the full DefaultOnboardingRepository implementation
fd -e kt -path '*DefaultOnboardingRepository*' -type f

Repository: YAPP-Github/Twix-Android

Length of output: 236


🏁 Script executed:

# Find repository files
find . -name "*Repository.kt" | head -20

Repository: YAPP-Github/Twix-Android

Length of output: 218


🏁 Script executed:

# Search for error handling patterns in kotlin files
rg "runCatching|try\s*\{|Result<|catch\s*\(" -A 2 | head -100

Repository: YAPP-Github/Twix-Android

Length of output: 50


🏁 Script executed:

# Look for domain error model definitions
rg "sealed.*class|object.*Error|sealed.*Error" --type kotlin | head -30

Repository: YAPP-Github/Twix-Android

Length of output: 276


🏁 Script executed:

# Get the full DefaultOnboardingRepository implementation
cat data/src/main/java/com/twix/data/repository/DefaultOnboardingRepository.kt

Repository: YAPP-Github/Twix-Android

Length of output: 1067


🏁 Script executed:

# Find all Repository implementations to check patterns
find . -name "*Repository.kt" -not -path "*/build/*" | xargs grep -l "class.*Repository"

Repository: YAPP-Github/Twix-Android

Length of output: 144


🏁 Script executed:

# Check the domain repository interface
cat domain/src/main/java/com/twix/domain/repository/OnBoardingRepository.kt

Repository: YAPP-Github/Twix-Android

Length of output: 479


🏁 Script executed:

# Search for Result types and error handling utilities
find . -name "*.kt" -not -path "*/build/*" | xargs grep -l "sealed class Result\|Result<" | head -10

Repository: YAPP-Github/Twix-Android

Length of output: 50


🏁 Script executed:

# Look for any error/exception models
find . -name "*Error.kt" -o -name "*Exception.kt" | head -20

Repository: YAPP-Github/Twix-Android

Length of output: 50


🏁 Script executed:

# Search for OnboardingService implementation
find . -name "*OnboardingService*" -o -name "*Service.kt" | head -20

Repository: YAPP-Github/Twix-Android

Length of output: 142


🏁 Script executed:

# Check ViewModel or UseCase error handling
find . -name "*ViewModel.kt" -o -name "*UseCase.kt" | xargs grep -l "try\|catch\|error\|Error" | head -10

Repository: YAPP-Github/Twix-Android

Length of output: 50


🏁 Script executed:

# Look at network layer for error handling
find . -path "*network*" -name "*.kt" | xargs grep -l "Exception\|error\|catch" | head -10

Repository: YAPP-Github/Twix-Android

Length of output: 50


🏁 Script executed:

# Check if there are any other data layer operations with error handling
find . -path "*data*" -name "*.kt" | xargs grep -n "try\s*\{" | head -30

Repository: YAPP-Github/Twix-Android

Length of output: 86


🏁 Script executed:

# Check OnboardingService implementation
cat core/network/src/main/java/com/twix/network/service/OnboardingService.kt

Repository: YAPP-Github/Twix-Android

Length of output: 917


🏁 Script executed:

# Search for error handling in data layer more broadly
find . -path "*data*" -name "*.kt" | xargs grep -n "try" | head -30

Repository: YAPP-Github/Twix-Android

Length of output: 50


🏁 Script executed:

# Check for error handling in all layers
find . -name "*.kt" -not -path "*/build/*" | xargs grep -n "catch" | head -30

Repository: YAPP-Github/Twix-Android

Length of output: 50


🏁 Script executed:

# Look for network error handling or exception handling
find . -path "*network*" -name "*.kt" | xargs cat | head -100

Repository: YAPP-Github/Twix-Android

Length of output: 2898


네트워크 예외 처리가 필요합니다.

현재 구현에서 OnboardingService를 통한 네트워크 호출 시 발생하는 예외가 그대로 상위로 전파됩니다. HttpClientexpectSuccess = true로 설정되어 있기 때문에 4xx, 5xx 상태 코드에서 예외가 발생합니다.

코딩 가이드라인에서 "에러가 도메인 레벨로 적절히 변환되는가?"를 확인하도록 되어 있는데, 현재는 기술 계층의 예외가 도메인 계층으로 올라가고 있습니다.

프로젝트에서 사용 중인 에러 처리 패턴이 있다면 그에 맞춰 적용하면 됩니다. 예를 들어:

  • 도메인 레벨의 정의된 예외로 변환
  • Result<T> 또는 유사한 래퍼 타입 사용
  • 예외별로 구분된 처리 로직

UI 레이어에서 일관되게 에러를 처리하려면 어디서 예외를 캐치하고 도메인 계층으로 변환할 계획인지 논의해 주세요.

🤖 Prompt for AI Agents
In `@data/src/main/java/com/twix/data/repository/DefaultOnboardingRepository.kt`
around lines 8 - 14, DefaultOnboardingRepository::fetchInviteCode currently lets
network exceptions from OnboardingService bubble up; wrap the call to
service.fetchInviteCode() in a try/catch and convert technical exceptions into a
domain-friendly result (e.g. return a Result<InviteCode, DomainError> or throw a
specific domain exception) so callers (UI) can handle errors consistently;
specifically catch Ktor
ResponseException/ClientRequestException/ServerResponseException (or a generic
Exception as fallback), map them to a DomainError (or Result.failure with mapped
error), and only on success construct and return InviteCode(response.inviteCode)
so the repository surface (DefaultOnboardingRepository, fetchInviteCode,
OnBoardingRepository, InviteCode) exposes domain-level errors instead of raw
HTTP exceptions.


override suspend fun fetchOnboardingStatus(): OnboardingStatus {
val response = service.fetchOnBoardingStatus()
return OnboardingStatus.from(response.status)
}
Comment on lines +19 to +22
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

🏁 Script executed:

fd -type f -name "*.kt" | xargs rg "class OnboardingStatus|sealed class OnboardingStatus|enum class OnboardingStatus" -l

Repository: YAPP-Github/Twix-Android

Length of output: 385


🏁 Script executed:

fd -type f -name "*OnboardingStatus*"

Repository: YAPP-Github/Twix-Android

Length of output: 238


🏁 Script executed:

rg -n "OnboardingStatus" data/ --type kt -l | head -20

Repository: YAPP-Github/Twix-Android

Length of output: 94


🏁 Script executed:

cat -n domain/src/main/java/com/twix/domain/model/OnboardingStatus.kt

Repository: YAPP-Github/Twix-Android

Length of output: 699


🏁 Script executed:

cat -n domain/src/main/java/com/twix/domain/model/OnboardingStatusTest.kt

Repository: YAPP-Github/Twix-Android

Length of output: 166


🏁 Script executed:

cat -n data/src/main/java/com/twix/data/repository/DefaultOnboardingRepository.kt

Repository: YAPP-Github/Twix-Android

Length of output: 1545


OnboardingStatus.from()의 미정의 값 처리를 개선해 주세요.

왜 문제가 되나: OnboardingStatus.from()은 알 수 없는 상태값을 받으면 IllegalArgumentException을 던지는데, 현재 Repository에서 이를 catch하지 않아 미처리 예외로 인한 앱 크래시가 발생합니다.

어떻게 개선하나:

  • OnboardingStatus enum에 UNKNOWN 값을 추가하고 from()이 이를 반환하도록 변경, 또는
  • Repository에서 runCatching으로 감싸서 예외를 catch하고 안전한 기본값으로 처리

어느 방식이 더 적절할까요? 서버로부터 예상치 못한 상태값이 올 수 있는 상황에서는 Unknown 상태를 명시적으로 처리하는 것이 권장됩니다.

🤖 Prompt for AI Agents
In `@data/src/main/java/com/twix/data/repository/DefaultOnboardingRepository.kt`
around lines 19 - 22, DefaultOnboardingRepository.fetchOnboardingStatus
currently calls OnboardingStatus.from(response.status) which can throw
IllegalArgumentException for unknown values; add an UNKNOWN enum constant to
OnboardingStatus and update OnboardingStatus.from(String) to return UNKNOWN for
unrecognized inputs, and also wrap the call in
DefaultOnboardingRepository.fetchOnboardingStatus with runCatching { ...
}.getOrDefault(OnboardingStatus.UNKNOWN) so any unexpected exception still
yields a safe UNKNOWN default; reference OnboardingStatus.from and
DefaultOnboardingRepository.fetchOnboardingStatus when making these changes.


override suspend fun anniversarySetup(request: String) {
service.anniversarySetup(AnniversaryRequest(request))
}

override suspend fun coupleConnection(request: String) {
service.coupleConnection(CoupleConnectionRequest(request))
}

override suspend fun profileSetup(request: String) {
service.profileSetup(ProfileRequest(request))
}
}
1 change: 0 additions & 1 deletion domain/src/main/java/com/twix/domain/.gitkeep

This file was deleted.

18 changes: 18 additions & 0 deletions domain/src/main/java/com/twix/domain/model/InviteCode.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.twix.domain.model

@JvmInline
value class InviteCode(
val value: String,
) {
init {
require(value.length == INVITE_CODE_LENGTH) { INVALID_INVITE_CODE_EXCEPTION }
require(INVITE_CODE_REGEX.matches(value)) { INVALID_INVITE_CODE_EXCEPTION }
}

companion object {
private val INVITE_CODE_REGEX = Regex("^[A-Z0-9]+$")
private const val INVITE_CODE_LENGTH = 8
private const val INVALID_INVITE_CODE_EXCEPTION =
"InviteCode must be 8 characters of uppercase letters and digits"
}
}
Comment on lines +3 to +18
Copy link
Member

Choose a reason for hiding this comment

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

커플을 연결할 때 유저가 입력하는 UI 값을 이 클래스로 변환해서 서버로 전송한다고 하면, 잘못된 값을 입력했을 때 require로 인해서 앱이 죽어버릴 수도 있을 거 같거든요. 그래서 유효성 체크하는 부분을 보완하면 좋을 거 같아요.

예를 들면 유효성 검사에 실패했을 때 Result로 래핑해서 BaseViewModel에서 처리하고 경고 메시지를 보여주거나 이런식으로 개선하는 것도 괜찮지 않을까 싶습니다! 다른 방법을 생각하고 계신 게 있으면 말씀해주세요

Copy link
Member Author

Choose a reason for hiding this comment

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

앗 이 부분을 미리 말을 못했구나 에러처리 관련한 부분은 우리가 아직 논의가 안돼서 임시로 구현해놨어 ! 😅

나도 현수가 말한 것 처럼 InvalidInviteCodeException같은 특정 에러 상태를 나타내는 클래스를 만들고
이 에러 상태에 따른 적절한 string Resource를 매핑하는 객체를 만들어 처리하는 방법을 사용했었는데,

요건 우리가 추후 에러 처리를 논의할 때 딥하게 논의해보면 좋을 것 같아 !

20 changes: 20 additions & 0 deletions domain/src/main/java/com/twix/domain/model/OnboardingStatus.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.twix.domain.model

enum class OnboardingStatus {
COUPLE_CONNECTION,
PROFILE_SETUP,
ANNIVERSARY_SETUP,
COMPLETED,
;

companion object {
fun from(status: String): OnboardingStatus =
runCatching {
valueOf(status.trim().uppercase())
}.getOrElse {
throw IllegalArgumentException(UNKNOWN_STATUS.format(status))
}

private const val UNKNOWN_STATUS = "UNKNOWN_STATUS: %s"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.twix.domain.repository

import com.twix.domain.model.InviteCode
import com.twix.domain.model.OnboardingStatus

interface OnBoardingRepository {
suspend fun anniversarySetup(request: String)

suspend fun coupleConnection(request: String)

suspend fun profileSetup(request: String)

suspend fun fetchInviteCode(): InviteCode

suspend fun fetchOnboardingStatus(): OnboardingStatus
}
43 changes: 43 additions & 0 deletions domain/src/test/java/com/twix/domain/model/InviteCodeTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.twix.domain.model

import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatThrownBy
import org.junit.jupiter.api.Test
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.ValueSource

class InviteCodeTest {
@Test
fun `유효한 초대 코드는 정상적으로 생성된다`() {
val inviteCode = InviteCode("AB12CD34")

assertThat(inviteCode.value).isEqualTo("AB12CD34")
}

@ParameterizedTest
@ValueSource(
strings = [
"ab12CD34",
"AB12CD3!",
" ",
],
)
fun `규칙에 맞지 않는 초대 코드는 예외가 발생한다`(invalidCode: String) {
assertThatThrownBy { InviteCode(invalidCode) }
.isInstanceOf(IllegalArgumentException::class.java)
.hasMessage("InviteCode must be 8 characters of uppercase letters and digits")
Comment on lines +27 to +28
Copy link
Member

Choose a reason for hiding this comment

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

이 부분을 InvalidInviteCodeException이라는 걸 만들어서 관리하는 건 어떠신가요?

}

@ParameterizedTest
@ValueSource(
strings = [
"ABC123",
"AB12CD345",
],
)
fun `8자리가 아닌 초대 코드는 예외가 발생한다`(invalidLengthCode: String) {
assertThatThrownBy { InviteCode(invalidLengthCode) }
.isInstanceOf(IllegalArgumentException::class.java)
.hasMessage("InviteCode must be 8 characters of uppercase letters and digits")
}
Comment on lines +31 to +42
Copy link
Member

Choose a reason for hiding this comment

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

InvalidInviteCodeException를 따로 만들면 규칙에 맞지 않는 초대 코드는 예외가 발생한다, 8자리가 아닌 초대 코드는 예외가 발생한다 이 두 테스트를 하나로 묶는 것도 가능할 것 같아요

}
41 changes: 41 additions & 0 deletions domain/src/test/java/com/twix/domain/model/OnboardingStatusTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.twix.domain.model

import org.assertj.core.api.Assertions.assertThatThrownBy
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.CsvSource
import kotlin.test.assertEquals

class OnboardingStatusTest {
@ParameterizedTest
@CsvSource(
"COUPLE_CONNECTION,COUPLE_CONNECTION",
"PROFILE_SETUP,PROFILE_SETUP",
"ANNIVERSARY_SETUP,ANNIVERSARY_SETUP",
"COMPLETED,COMPLETED",
)
@DisplayName("올바른 OnboardingStatus enum을 반환한다")
fun `유효한 상태 문자열이 주어지면 올바른 OnboardingStatus enum을 반환한다`(
input: String,
expected: OnboardingStatus,
) {
// when
val result = OnboardingStatus.from(input)

// then
assertEquals(result, expected)
}

@Test
fun `유효하지 않은 상태 문자열이 주어지면 IllegalArgumentException을 던진다`() {
// given
val invalidStatus = "UNKNOWN"

// when
assertThatThrownBy { OnboardingStatus.from(invalidStatus) }
// then
.isInstanceOf(IllegalArgumentException::class.java)
.hasMessage("UNKNOWN_STATUS: $invalidStatus")
}
}