Skip to content

부품 조회화면 구현#16

Merged
Sangyoon98 merged 6 commits into
devfrom
SPM-99
Oct 18, 2025
Merged

부품 조회화면 구현#16
Sangyoon98 merged 6 commits into
devfrom
SPM-99

Conversation

@Sangyoon98
Copy link
Copy Markdown
Member

@Sangyoon98 Sangyoon98 commented Oct 18, 2025

📝 Summary

부품 조회화면 구현

🙏 Question & PR point

📬 Reference

Summary by CodeRabbit

  • 새로운 기능

    • 부품 조회 흐름 추가: 카테고리 → 그룹 → 부품 계층 탐색 및 부품 목록 화면 추가
    • 빈 화면·오류 화면용 공통 컴포저블 추가
  • 개선사항

    • 테마 색상 팔레트 및 라이트/다크·대비 변형 확장
    • 다수 아이콘·벡터 자산 추가 및 색상 리소스화
    • 인증 API 경로 정비
  • 버그 수정 / 안정성

    • 로그인 화면 상태를 수명주기 인식 방식으로 전환하여 상태 처리 안정화

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Oct 18, 2025

Walkthrough

네비게이션에 부품 목록 라우트를 추가하고, 부품 도메인을 카테고리/그룹/부품 계층으로 재설계했습니다. API 경로·DTO·매퍼·저장소·유스케이스·뷰모델·UI가 계층 구조에 맞게 변경되었고, 테마 색상 토큰이 대폭 확장되었으며 인증 엔드포인트 경로가 갱신되었습니다.

Changes

코호트 / 파일(들) 변경 요약
네비게이션
app/src/main/java/com/sampoom/android/app/navigation/AppNavHost.kt
ROUTE_PART_LIST 상수 및 routePartList(agencyId, groupId) 추가; PartListScreen 목적지 연결; PartScreen에 네비게이션 콜백 연결.
테마/색상
app/src/main/java/com/sampoom/android/core/ui/theme/Color.kt, app/src/main/java/com/sampoom/android/core/ui/theme/Theme.kt
라이트/다크 및 대비 변형을 포함한 다수의 색상 상수와 composable 헬퍼 추가; SampoomManagementThemedynamicColor 기본값을 false로 변경.
인증 API
app/src/main/java/com/sampoom/android/feature/auth/data/remote/api/AuthApi.kt
Retrofit 경로 변경: @POST("login")@POST("auth/login"), @POST("signup")@POST("auth/signup").
인증 UI/VM
app/src/main/java/com/sampoom/android/feature/auth/ui/LoginScreen.kt, .../LoginViewModel.kt, .../SignUpScreen.kt
상태 흐름명 stateuiState로 변경, lifecycle-aware 수집 적용(collectAsStateWithLifecycle); SignUp에 배경 관련 import 추가.
원격 DTO / API (부품)
app/src/main/java/com/sampoom/android/feature/part/data/remote/dto/CategoryDto.kt, GroupDto.kt, PartDto.kt, .../api/PartApi.kt
CategoryDto, GroupDto 추가; PartDto 필드 변경(partId, code, name, quantity); API가 계층화됨 — getCategoryList(), getGroupList(categoryId), getPartList(groupId) 추가(기존 단일 getPartList 제거).
도메인 모델 (부품)
app/src/main/java/com/sampoom/android/feature/part/domain/model/*.kt
Category, CategoryList, Group, GroupList 추가; Part 모델 변경(id/count → partId/code/quantity).
매퍼 / 저장소 / 유스케이스
app/src/main/java/com/sampoom/android/feature/part/data/mapper/PartMappers.kt, .../data/repository/PartRepositoryImpl.kt, .../domain/repository/PartRepository.kt, .../domain/usecase/*
DTO→모델 매퍼 추가/수정; 저장소 인터페이스·구현을 카테고리/그룹/부품 호출로 재구성; GetCategoryUseCase, GetGroupUseCase 추가; GetPartUseCase 시그니처 변경.
Part UI 및 ViewModel
app/src/main/java/com/sampoom/android/feature/part/ui/*.kt
PartScreen을 카테고리 선택 → 그룹 목록 흐름으로 재설계; PartListScreen, PartListViewModel, 관련 UiState/UiEvent 신규 추가; PartViewModel이 이벤트 기반 로직으로 대체.
공통 UI 컴포넌트
app/src/main/java/com/sampoom/android/core/ui/component/EmptyContent.kt, ErrorContent.kt
EmptyContent 및 ErrorContent 신규 composable 추가.
드로어블 리소스
app/src/main/res/drawable/*.xml
여러 벡터 드로어블에서 하드코딩 색상 → @color/text 참조로 변경; body, chassis, electric, engine, transmission, trim, chevron_right 등 아이콘 추가.
문자열 리소스
app/src/main/res/values/strings.xml
part_title 값 변경("부품 목록"→"부품조회"), 부품 관련 검색/카테고리/빈 상태 문자열 추가, part_empty 제거, common_detail 추가.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant UI as PartScreen
    participant VM as PartViewModel
    participant GetCat as GetCategoryUseCase
    participant GetGroup as GetGroupUseCase
    participant Repo as PartRepository

    User->>UI: 화면 진입
    UI->>VM: onEvent(LoadCategories)
    VM->>GetCat: invoke()
    GetCat->>Repo: getCategoryList()
    Repo-->>GetCat: CategoryList
    GetCat-->>VM: CategoryList
    VM-->>UI: uiState(categoryList)

    User->>UI: 카테고리 선택
    UI->>VM: onEvent(CategorySelected)
    VM->>GetGroup: invoke(categoryId)
    GetGroup->>Repo: getGroupList(categoryId)
    Repo-->>GetGroup: GroupList
    GetGroup-->>VM: GroupList
    VM-->>UI: uiState(groupList)

    User->>UI: 그룹 클릭
    UI->>UI: onNavigatePartList(group)
    UI->>AppNavHost: navigate(routePartList(...))
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • Lee-Jong-Jin
  • CHOOSLA
  • yangjiseonn
  • vivivim

Poem

🐰 당근 한 움큼 톡! 기능이 쑥,
카테고리 줄지어, 그룹이 빛나쑥.
API 길 닦이고 색들 늘어나,
네비게이션은 탁! 부품목록 짜잔.
토끼가 토닥—축하해요, 홧팅! 🥕🎉

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed PR 제목 "부품 조회화면 구현"은 변경 사항의 주요 목표를 정확하게 반영합니다. 광범위한 변경 중에서 PartListScreen, PartListViewModel, 계층적 데이터 모델(Category, Group 추가) 등이 부품 조회 기능의 핵심이며, 문자열 리소스 업데이트("부품조회")도 이를 뒷받침합니다. 인증, 테마, 네비게이션 관련 변경사항도 포함되어 있지만, 이들은 부품 조회 기능 구현을 지원하는 보조적 성격입니다. 제목은 간결하고 명확하여 팀이 변경 사항의 주요 의도를 쉽게 파악할 수 있습니다.
✨ 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 SPM-99

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2d76062 and 9e73aac.

📒 Files selected for processing (2)
  • app/src/main/java/com/sampoom/android/core/ui/component/EmptyContent.kt (1 hunks)
  • app/src/main/java/com/sampoom/android/core/ui/component/ErrorContent.kt (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • app/src/main/java/com/sampoom/android/core/ui/component/ErrorContent.kt
  • app/src/main/java/com/sampoom/android/core/ui/component/EmptyContent.kt

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

Copy link
Copy Markdown

@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: 9

🧹 Nitpick comments (23)
app/src/main/res/drawable/body.xml (1)

2-5: 아이콘 크기·틴팅·호환성 점검

  • 머티리얼 아이콘 기준 24dp가 기본입니다. 25dp는 정렬 이슈를 유발할 수 있어 24dp로 권장합니다.
  • 고정 색(@color/text) 대신 테마 틴트 사용을 고려해 주세요(Compose에서 tint 적용 또는 벡터에 ?attr/colorOnSurface 등). 다크/라이트에서 대비 확보에 유리합니다.
  • clip-path 사용은 하위 API/VectorDrawableCompat에서 제약이 있을 수 있습니다. 프로젝트 minSdk가 해당 기능을 충분히 커버하는지 확인 부탁드립니다.

Also applies to: 10-17

app/src/main/res/values/strings.xml (1)

41-48: 라벨 표기·톤앤매너 정리

  • "부품조회"는 일반적으로 띄어쓰기 "부품 조회"가 자연스럽습니다. part_title을 "부품 조회"로 제안합니다.
  • 비어있는 상태 문구들은 모두 종결부호로 일관되어 좋습니다. 추후 검색 placeholder 톤도 다른 화면과 통일(예: "~ 입력" vs "~으로 검색")되었는지 한번 더 점검해 주세요.

Also applies to: 54-54

app/src/main/java/com/sampoom/android/feature/auth/ui/SignUpScreen.kt (1)

4-4: 불필요한 import 제거 필요

검증 결과, androidx.compose.foundation.background(4줄)과 com.sampoom.android.core.ui.theme.backgroundColor(45줄) 두 import 모두 코드에서 실제로 사용되지 않습니다. 파일 전체에서 .background( 또는 backgroundColor() 호출이 없습니다. 이 두 import를 제거하세요.

app/src/main/java/com/sampoom/android/feature/part/ui/PartListUiEvent.kt (1)

3-6: UI 이벤트 구조가 명확합니다.

Sealed interface 패턴이 적절하게 사용되었습니다. 선택적으로, 더 나은 디버깅을 위해 object 대신 data object를 사용할 수 있습니다.

선택적 개선안:

 sealed interface PartListUiEvent {
-    object LoadPartList : PartListUiEvent
-    object RetryPartList : PartListUiEvent
+    data object LoadPartList : PartListUiEvent
+    data object RetryPartList : PartListUiEvent
 }
app/src/main/java/com/sampoom/android/feature/part/domain/usecase/GetCategoryUseCase.kt (1)

7-11: 심플한 위임 형태, OK. 다만 이름/KDoc 보완 제안

현재 구현은 깨끗합니다. 향후 검색·필터 옵션이 추가될 가능성을 고려하면 함수/클래스명을 GetCategoriesUseCase 또는 FetchCategoryListUseCase로 명확히 하거나 KDoc로 반환/예외 정책을 명시해 주세요.

app/src/main/java/com/sampoom/android/feature/part/ui/PartListUiState.kt (1)

5-9: UI 상태 불변성/일관성 강화 제안

  • 불일치 상태(동시에 loading=true와 error!=null 등)를 원천 차단하려면 sealed 상태로 모델링해 보세요(Loading/Success/Empty/Error). 또는 현재 구조를 유지한다면 @immutable로 Compose 안정성을 높이는 것을 권장합니다.

예시(선호):

sealed interface PartListState {
  data object Loading : PartListState
  data class Success(val items: List<Part>) : PartListState
  data class Error(val message: String) : PartListState
  data object Empty : PartListState
}

대안(@immutable 부여):

+import androidx.compose.runtime.Immutable
- data class PartListUiState(
+@Immutable
+data class PartListUiState(
     val partList: List<Part> = emptyList(),
     val partListLoading: Boolean = false,
     val partListError: String? = null
 )
app/src/main/java/com/sampoom/android/feature/part/domain/model/CategoryList.kt (1)

3-11: 파생 속성은 보관보다 계산 프로퍼티가 안전합니다

totalCount/isEmpty를 생성 시 값으로 보관하면 items가 외부에서 변경될 경우(읽기전용 List이더라도 실제 구현이 가변일 수 있음) 드리프트가 발생할 수 있습니다. 계산 프로퍼티로 전환하고, 방어적 복사로 불변성을 강화하는 것을 권장합니다. 또한 굳이 Companion 이름을 명시할 필요는 없습니다.

 data class CategoryList(
-    val items: List<Category>,
-    val totalCount: Int = items.size,
-    val isEmpty: Boolean = items.isEmpty()
-) {
-    companion object Companion {
-        fun empty() = CategoryList(emptyList())
-    }
-}
+    val items: List<Category>
+) {
+    val totalCount: Int get() = items.size
+    val isEmpty: Boolean get() = items.isEmpty()
+
+    companion object {
+        fun empty() = CategoryList(emptyList())
+    }
+}

추가로, 가능하면 생성자에서 items.toList()로 방어적 복사를 적용해 외부 변이로부터 보호하는 것도 고려해 주세요.

app/src/main/java/com/sampoom/android/feature/part/domain/repository/PartRepository.kt (1)

7-10: ID 타입 명확화 및 계약 문서화 제안

  • Long 대신 의미 있는 별칭을 두면 오용을 줄일 수 있습니다(예: typealias CategoryId = Long, typealias GroupId = Long).
  • 각 메서드의 페이징/정렬/에러 정책을 KDoc로 명시해 호출측 계약을 분명히 해 주세요.
app/src/main/java/com/sampoom/android/feature/part/ui/PartListScreen.kt (5)

115-118: LazyColumn에 안정 키 지정으로 성능/재사용 개선

목록 항목에 고유 키를 부여해 스크롤/애니메이션/재조합 효율을 높이세요.

-                    items(uiState.partList) { part ->
-                        PartListItemCard(part = part)
-                    }
+                    items(
+                        items = uiState.partList,
+                        key = { it.partId }
+                    ) { part ->
+                        PartListItemCard(part = part)
+                    }

124-131: 상세 진입 UX: Card를 클릭 가능하게

chevron_right 아이콘을 노출하지만 카드가 클릭 불가여서 사용자가 혼동할 수 있습니다. 기본 onClick을 추가해 향후 상세 화면 연계를 쉽게 하세요(호출부 변경 없이 디폴트 람다 제공).

-private fun PartListItemCard(
-    part: Part
-) {
+private fun PartListItemCard(
+    part: Part,
+    onClick: () -> Unit = {}
+) {
     Card(
-        modifier = Modifier.fillMaxWidth(),
+        modifier = Modifier.fillMaxWidth(),
+        onClick = onClick,
         colors = CardDefaults.cardColors(containerColor = backgroundCardColor())
     ) {

호출부는 유지 가능합니다(현재는 PartListItemCard(part = part) 그대로 사용).

Also applies to: 115-117


49-51: LaunchedEffect 키 안정화

리소스 문자열 변화(로케일 전환) 때마다 bindLabel이 재호출됩니다. 의도가 1회 바인딩이라면 LaunchedEffect(Unit)이 안전합니다.

-    LaunchedEffect(errorLabel) {
+    LaunchedEffect(Unit) {
         viewModel.bindLabel(errorLabel)
     }

87-91: 고정 높이(modifier.height(200.dp)) 제거 권장

이미 Box(Modifier.fillMaxSize(), contentAlignment = Center)로 감싸므로 내부 컨텐츠에 고정 높이를 줄 필요가 없습니다. 다양한 화면 크기에서 레이아웃 제약을 피하려면 생략하세요.

-                    ErrorContent(
-                        onRetry = { viewModel.onEvent(PartListUiEvent.RetryPartList) },
-                        modifier = Modifier.height(200.dp)
-                    )
+                    ErrorContent(
+                        onRetry = { viewModel.onEvent(PartListUiEvent.RetryPartList) }
+                    )
-                    EmptyContent(
-                        message = stringResource(R.string.part_empty_part),
-                        modifier = Modifier.height(200.dp)
-                    )
+                    EmptyContent(
+                        message = stringResource(R.string.part_empty_part)
+                    )

Also applies to: 100-103


161-165: Icon 오버로드 변화에 안전하도록 인자명 명시

Compose 버전에 따른 Icon 오버로드 변화에 덜 취약하도록 파라미터명을 명시하세요.

-            Icon(
-                painterResource(R.drawable.chevron_right),
-                contentDescription = stringResource(R.string.common_detail),
-                tint = textSecondaryColor()
-            )
+            Icon(
+                painter = painterResource(id = R.drawable.chevron_right),
+                contentDescription = stringResource(R.string.common_detail),
+                tint = textSecondaryColor()
+            )
app/src/main/java/com/sampoom/android/app/navigation/AppNavHost.kt (1)

171-184: BottomNavigation 선택 상태는 hierarchy 기반 비교가 안전합니다.

중첩 네비게이션 시 currentDestination?.route == item.route는 실패할 수 있습니다. hierarchy를 사용하세요.

- selected = currentDestination?.route == item.route,
+ selected = currentDestination?.hierarchy?.any { it.route == item.route } == true,
app/src/main/java/com/sampoom/android/feature/part/data/mapper/PartMappers.kt (1)

10-12: DTO nullability 확인 및 방어적 매핑 고려.

현재 DTO 필드가 null 가능이면 NPE 위험이 있습니다. 스키마가 non-null이 보장되지 않는 한, requireNotNull/기본값으로 방어하세요.

예시:

-fun PartDto.toModel(): Part = Part(partId, code, name, quantity)
+fun PartDto.toModel(): Part = Part(
+    partId = requireNotNull(partId) { "partId is null" },
+    code = code.orEmpty(),
+    name = name.orEmpty(),
+    quantity = quantity ?: 0L
+)

DTO 정의의 nullability를 확인해 주세요(파일: CategoryDto.kt, GroupDto.kt, PartDto.kt).

app/src/main/java/com/sampoom/android/feature/part/ui/PartListViewModel.kt (2)

24-27: SavedState로 받은 agencyId가 미사용입니다. 시그니처/호출을 정리하세요.

현재 agencyId를 읽지만 사용하지 않습니다. API가 agency를 요구한다면 유스케이스/리포지토리까지 전달하세요. 요구하지 않는다면 라우트와 SavedState에서 제거해 일관성을 맞추세요.

라우트 정의(AppNavHost.kt Lines 104-115)와 맞춰야 합니다.


45-69: 유스케이스 인자 확장 대비 여지 남기기(agencyId 포함 시).

API가 agencyId를 요구하도록 정리되면 아래 호출부도 갱신 필요합니다.

- runCatching { getPartUseCase(groupId) }
+ runCatching { getPartUseCase(/* agencyId = */ agencyId, groupId) }
app/src/main/java/com/sampoom/android/feature/part/ui/PartUiState.kt (1)

15-19: 구조 적절. 카테고리/그룹의 로딩·에러 분리로 UI 처리 용이합니다.

현재 상태 분리는 합리적이며 확장성 있습니다. 추후 검색어 등 필드를 추가할 때도 이 패턴 유지 추천합니다.

app/src/main/java/com/sampoom/android/feature/part/ui/PartViewModel.kt (1)

23-24: StateFlow 노출 방식 개선(읽기 전용 보장).

외부엔 읽기 전용을 강제하는 관례대로 asStateFlow()로 노출해 주세요. 유지보수성과 의도 전달에 유리합니다.

 import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow

 ...
-    val uiState: StateFlow<PartUiState> = _uiState
+    val uiState: StateFlow<PartUiState> = _uiState.asStateFlow()
app/src/main/java/com/sampoom/android/feature/part/ui/PartScreen.kt (3)

229-241: 긴 그룹 목록은 LazyColumn으로 전환(성능/메모리).

Column+verticalScroll은 아이템 전부를 측정/배치하여 목록이 길면 성능 저하가 큽니다. LazyColumn으로 변경하고 key를 지정하세요.

-                    else -> {
-                        Column(
-                            Modifier.fillMaxWidth(),
-                            verticalArrangement = Arrangement.spacedBy(8.dp)
-                        ) {
-                            uiState.groupList.forEach { group ->
-                                PartItemCard(
-                                    group = group,
-                                    onClick = { onNavigatePartList(group) }
-                                )
-                            }
-                        }
-                    }
+                    else -> {
+                        LazyColumn(
+                            modifier = Modifier.fillMaxWidth(),
+                            verticalArrangement = Arrangement.spacedBy(8.dp)
+                        ) {
+                            items(
+                                items = uiState.groupList,
+                                key = { it.id }
+                            ) { group ->
+                                PartItemCard(
+                                    group = group,
+                                    onClick = { onNavigatePartList(group) }
+                                )
+                            }
+                        }
+                    }

33-34: 동일 이름의 로컬 Composable과 import 충돌(가독성 저하).

파일 하단에 private fun PartItemCard(...)가 있어 import된 PartItemCard와 이름이 겹칩니다. 혼동 방지를 위해 import를 제거하세요.

-import com.sampoom.android.feature.part.ui.PartItemCard

78-85: 하드코딩 문자열의 다국어 리소스화.

"부품명으로 검색", "검색"은 stringResource로 분리하여 i18n을 보장하세요. 위 검색창 수정 diff에 포함했습니다.

app/src/main/java/com/sampoom/android/core/ui/theme/Color.kt (1)

250-263: 컬러 헬퍼는 읽기 전용임을 명시하면 좋습니다.

isSystemInDarkTheme() 조회만 수행하므로 @ReadOnlyComposable로 어노테이트하면 의도가 명확합니다.

-import androidx.compose.foundation.isSystemInDarkTheme
-import androidx.compose.runtime.Composable
+import androidx.compose.foundation.isSystemInDarkTheme
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.ReadOnlyComposable

 @Composable
-fun backgroundColor() = if (isSystemInDarkTheme()) BgBlack else BgWhite
+@ReadOnlyComposable
+fun backgroundColor() = if (isSystemInDarkTheme()) BgBlack else BgWhite

 @Composable
-fun backgroundCardColor() = if (isSystemInDarkTheme()) BgCardBlack else BgCardWhite
+@ReadOnlyComposable
+fun backgroundCardColor() = if (isSystemInDarkTheme()) BgCardBlack else BgCardWhite

 @Composable
-fun textColor() = if (isSystemInDarkTheme()) BgWhite else BgCardBlack
+@ReadOnlyComposable
+fun textColor() = if (isSystemInDarkTheme()) BgWhite else BgCardBlack

 @Composable
-fun textSecondaryColor() = if (isSystemInDarkTheme()) Grey200 else Grey300
+@ReadOnlyComposable
+fun textSecondaryColor() = if (isSystemInDarkTheme()) Grey200 else Grey300

 @Composable
-fun disableColor() = if (isSystemInDarkTheme()) Grey400 else Grey100
+@ReadOnlyComposable
+fun disableColor() = if (isSystemInDarkTheme()) Grey400 else Grey100
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cf46158 and 08b589b.

📒 Files selected for processing (44)
  • app/src/main/java/com/sampoom/android/app/navigation/AppNavHost.kt (7 hunks)
  • app/src/main/java/com/sampoom/android/core/ui/theme/Color.kt (1 hunks)
  • app/src/main/java/com/sampoom/android/core/ui/theme/Theme.kt (1 hunks)
  • app/src/main/java/com/sampoom/android/feature/auth/data/remote/api/AuthApi.kt (1 hunks)
  • app/src/main/java/com/sampoom/android/feature/auth/ui/LoginScreen.kt (3 hunks)
  • app/src/main/java/com/sampoom/android/feature/auth/ui/LoginViewModel.kt (3 hunks)
  • app/src/main/java/com/sampoom/android/feature/auth/ui/SignUpScreen.kt (2 hunks)
  • app/src/main/java/com/sampoom/android/feature/part/data/mapper/PartMappers.kt (1 hunks)
  • app/src/main/java/com/sampoom/android/feature/part/data/remote/api/PartApi.kt (1 hunks)
  • app/src/main/java/com/sampoom/android/feature/part/data/remote/dto/CategoryDto.kt (1 hunks)
  • app/src/main/java/com/sampoom/android/feature/part/data/remote/dto/GroupDto.kt (1 hunks)
  • app/src/main/java/com/sampoom/android/feature/part/data/remote/dto/PartDto.kt (1 hunks)
  • app/src/main/java/com/sampoom/android/feature/part/data/repository/PartRepositoryImpl.kt (1 hunks)
  • app/src/main/java/com/sampoom/android/feature/part/domain/model/Category.kt (1 hunks)
  • app/src/main/java/com/sampoom/android/feature/part/domain/model/CategoryList.kt (1 hunks)
  • app/src/main/java/com/sampoom/android/feature/part/domain/model/Group.kt (1 hunks)
  • app/src/main/java/com/sampoom/android/feature/part/domain/model/GroupList.kt (1 hunks)
  • app/src/main/java/com/sampoom/android/feature/part/domain/model/Part.kt (1 hunks)
  • app/src/main/java/com/sampoom/android/feature/part/domain/repository/PartRepository.kt (1 hunks)
  • app/src/main/java/com/sampoom/android/feature/part/domain/usecase/GetCategoryUseCase.kt (1 hunks)
  • app/src/main/java/com/sampoom/android/feature/part/domain/usecase/GetGroupUseCase.kt (1 hunks)
  • app/src/main/java/com/sampoom/android/feature/part/domain/usecase/GetPartUseCase.kt (1 hunks)
  • app/src/main/java/com/sampoom/android/feature/part/ui/PartListScreen.kt (1 hunks)
  • app/src/main/java/com/sampoom/android/feature/part/ui/PartListUiEvent.kt (1 hunks)
  • app/src/main/java/com/sampoom/android/feature/part/ui/PartListUiState.kt (1 hunks)
  • app/src/main/java/com/sampoom/android/feature/part/ui/PartListViewModel.kt (1 hunks)
  • app/src/main/java/com/sampoom/android/feature/part/ui/PartScreen.kt (2 hunks)
  • app/src/main/java/com/sampoom/android/feature/part/ui/PartUiEvent.kt (1 hunks)
  • app/src/main/java/com/sampoom/android/feature/part/ui/PartUiState.kt (1 hunks)
  • app/src/main/java/com/sampoom/android/feature/part/ui/PartViewModel.kt (1 hunks)
  • app/src/main/res/drawable/body.xml (1 hunks)
  • app/src/main/res/drawable/cart.xml (1 hunks)
  • app/src/main/res/drawable/chassis.xml (1 hunks)
  • app/src/main/res/drawable/chevron_right.xml (1 hunks)
  • app/src/main/res/drawable/dashboard.xml (1 hunks)
  • app/src/main/res/drawable/delivery.xml (1 hunks)
  • app/src/main/res/drawable/electric.xml (1 hunks)
  • app/src/main/res/drawable/engine.xml (1 hunks)
  • app/src/main/res/drawable/orders.xml (1 hunks)
  • app/src/main/res/drawable/parts.xml (1 hunks)
  • app/src/main/res/drawable/search.xml (1 hunks)
  • app/src/main/res/drawable/transmission.xml (1 hunks)
  • app/src/main/res/drawable/trim.xml (1 hunks)
  • app/src/main/res/values/strings.xml (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (5)
app/src/main/java/com/sampoom/android/feature/auth/ui/LoginViewModel.kt (2)
app/src/main/java/com/sampoom/android/feature/auth/domain/AuthValidator.kt (2)
  • validateEmail (7-18)
  • validatePassword (21-43)
app/src/main/java/com/sampoom/android/feature/auth/ui/SignUpViewModel.kt (3)
  • validateEmail (92-97)
  • validatePassword (99-104)
  • submit (121-151)
app/src/main/java/com/sampoom/android/feature/auth/ui/LoginScreen.kt (2)
app/src/main/java/com/sampoom/android/core/ui/component/CommonSnackBar.kt (2)
  • rememberCommonSnackBarHostState (36-37)
  • ShowErrorSnackBar (39-61)
app/src/main/java/com/sampoom/android/core/ui/component/CommonTextField.kt (1)
  • CommonTextField (29-138)
app/src/main/java/com/sampoom/android/feature/part/ui/PartListScreen.kt (3)
app/src/main/java/com/sampoom/android/feature/part/ui/PartScreen.kt (2)
  • ErrorContent (329-348)
  • EmptyContent (350-361)
app/src/main/java/com/sampoom/android/feature/part/domain/model/PartList.kt (1)
  • items (3-11)
app/src/main/java/com/sampoom/android/core/ui/theme/Color.kt (3)
  • backgroundCardColor (253-254)
  • textColor (256-257)
  • textSecondaryColor (259-260)
app/src/main/java/com/sampoom/android/app/navigation/AppNavHost.kt (2)
app/src/main/java/com/sampoom/android/feature/part/ui/PartScreen.kt (1)
  • PartScreen (36-248)
app/src/main/java/com/sampoom/android/feature/part/ui/PartListScreen.kt (1)
  • PartListScreen (41-122)
app/src/main/java/com/sampoom/android/feature/part/ui/PartScreen.kt (1)
app/src/main/java/com/sampoom/android/core/ui/theme/Color.kt (3)
  • textSecondaryColor (259-260)
  • backgroundCardColor (253-254)
  • textColor (256-257)
🔇 Additional comments (30)
app/src/main/java/com/sampoom/android/feature/part/domain/model/Category.kt (1)

3-7: 단순 모델 도입 LGTM

도메인 계층의 얇은 data class로 적절합니다. 후속으로 CategoryDto → Category 매핑에서 필드명과 타입 일치 여부만 확인해 주세요.

app/src/main/java/com/sampoom/android/core/ui/theme/Theme.kt (2)

15-48: 컬러 토큰 확장 LGTM

Material3 ColorScheme 전반(variant/containers/outline 등) 채워 넣은 점 좋습니다. Color.kt의 대비와 의미 매핑만 유지되는지 확인되면 충분합니다.

Also applies to: 53-86


92-92: 동적 컬러 기본값 변경(true → false) 확인됨 — 명시적 오버라이드 필요 검토

앱 진입점(MainActivity.kt:17)에서 SampoomManagementTheme을 호출할 때 dynamicColor 파라미터를 명시적으로 전달하지 않고 있습니다. 기본값이 false로 변경되었으므로 Android 12+ 기기에서 Monet 동적 컬러가 비활성화됩니다.

동적 컬러 유지가 의도라면:

  • MainActivity.kt:17에서 SampoomManagementTheme(dynamicColor = true) 명시 필요
app/src/main/java/com/sampoom/android/feature/part/data/remote/dto/PartDto.kt (1)

4-7: 서버 API 응답 형식 확인 필요

검증 결과, Gson이 직렬화 라이브러리로 사용되고 있으며 현재 PartDto에는 @SerializedName 어노테이션이 없습니다. 다만 역직렬화 문제 여부는 서버가 실제로 보내는 JSON 필드명에 따라 결정됩니다:

  • ✓ 서버가 partId, code, name, quantity를 보내면 → 현재 코드 정상 작동
  • ✗ 서버가 id, code, name, count를 보내면 → Gson 매핑 실패, 어노테이션 필수

필수 확인 사항:

  1. 서버 API 문서에서 실제 JSON 필드명 확인
  2. API 응답 예시 또는 네트워크 로그에서 필드명 검증
  3. 이전 버전 PartDto와 비교해 필드명이 변경되었는지 확인

필드명이 서버 JSON과 불일치하면 review comment의 옵션 B 중 Gson @SerializedName 어노테이션 적용이 필요합니다.

app/src/main/res/drawable/chevron_right.xml (1)

1-5: 벡터 드로어블 리소스가 올바르게 정의되었습니다.

새로운 chevron_right 아이콘이 @color/text를 사용하여 테마 시스템과 일관성 있게 구현되었으며, autoMirrored 속성도 적절히 설정되어 RTL 레이아웃을 지원합니다.

app/src/main/res/drawable/dashboard.xml (1)

8-8: 색상 리소스 참조로의 전환이 적절합니다.

하드코딩된 색상 값을 @color/text로 변경하여 중앙 집중식 테마 관리가 가능해졌습니다. 이는 다크 모드 지원 및 일관된 UI 스타일링에 유리합니다.

app/src/main/res/drawable/transmission.xml (1)

1-9: 새로운 transmission 아이콘이 올바르게 추가되었습니다.

벡터 드로어블이 @color/text를 사용하여 프로젝트의 테마 시스템과 일관성 있게 구현되었습니다.

app/src/main/res/drawable/orders.xml (1)

8-8: 테마 색상 적용이 적절합니다.

하드코딩된 색상을 색상 리소스로 전환하여 테마 일관성이 향상되었습니다.

app/src/main/res/drawable/parts.xml (1)

8-8: 색상 리소스 마이그레이션이 올바릅니다.

@color/text 사용으로 테마 시스템과의 통합이 개선되었습니다.

app/src/main/res/drawable/cart.xml (1)

11-11: 색상 리소스 전환이 적절합니다.

하드코딩된 색상 값을 @color/text로 변경하여 테마 관리 일관성이 향상되었습니다.

app/src/main/java/com/sampoom/android/feature/part/ui/PartUiEvent.kt (1)

5-10: UI 이벤트 인터페이스가 잘 설계되었습니다.

sealed interface를 사용한 이벤트 정의가 적절하며, 데이터가 없는 이벤트는 object로, 데이터를 포함하는 이벤트는 data class로 구현하여 Kotlin의 best practice를 따르고 있습니다. 카테고리 로딩, 선택, 재시도 플로우를 명확하게 표현합니다.

app/src/main/res/drawable/delivery.xml (1)

11-11: 색상 리소스 중앙화가 잘 적용되었습니다.

하드코딩된 색상 값을 @color/text 리소스로 변경하여 테마 지원이 가능해졌습니다. 이는 라이트/다크 모드 및 동적 테마 지원에 적합한 접근 방식입니다.

app/src/main/res/drawable/chassis.xml (1)

1-22: 새로운 섀시 아이콘이 잘 구현되었습니다.

벡터 드로어블이 올바르게 정의되어 있으며, 중앙화된 @color/text 리소스를 일관되게 사용하여 테마 지원이 적절히 적용되었습니다.

app/src/main/res/drawable/electric.xml (1)

1-13: 전기 부품 아이콘이 적절하게 추가되었습니다.

벡터 드로어블이 올바른 구조를 가지고 있으며, 테마 색상 리소스를 사용하여 일관된 UI를 제공합니다.

app/src/main/res/drawable/search.xml (1)

11-11: 검색 아이콘의 색상 리소스 마이그레이션이 완료되었습니다.

strokeColor를 중앙화된 색상 리소스로 변경하여 다른 아이콘들과 일관된 테마 적용이 가능합니다.

app/src/main/res/drawable/engine.xml (1)

1-13: 엔진 부품 아이콘이 잘 구현되었습니다.

복잡한 경로 데이터를 포함한 벡터 드로어블이 올바르게 정의되어 있으며, 중앙화된 색상 리소스를 사용하여 테마 일관성을 유지합니다.

app/src/main/res/drawable/trim.xml (1)

1-13: 트림 부품 아이콘이 적절하게 추가되었습니다.

벡터 드로어블이 올바르게 구현되어 있으며, 중앙화된 색상 리소스를 사용합니다. 다른 아이콘들과 달리 너비가 26dp인 점은 아이콘의 가로세로 비율을 고려한 의도적인 설정으로 보입니다.

app/src/main/java/com/sampoom/android/feature/part/domain/model/Group.kt (1)

3-8: 도메인 모델이 적절하게 정의되었습니다.

Group 데이터 클래스가 명확한 구조를 가지고 있으며, 필요한 속성들(id, code, name, categoryId)이 모두 포함되어 있습니다. 카테고리와의 관계를 나타내는 categoryId가 적절히 포함되어 있습니다.

app/src/main/java/com/sampoom/android/feature/part/data/remote/dto/CategoryDto.kt (1)

3-7: 직렬화 어노테이션은 필요하지 않습니다.

프로젝트의 Gson 설정을 확인한 결과, NetworkModule.kt에서 GsonBuilderFieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES로 구성되어 있습니다. 모든 기존 DTO(LoginRequestDto, LoginResponseDto, SignUpRequestDto, SignUpResponseDto)에서 어노테이션을 사용하지 않으며, CategoryDto도 이와 동일한 패턴을 따르고 있으므로 추가 어노테이션 없이 정상 작동합니다.

app/src/main/java/com/sampoom/android/feature/part/domain/usecase/GetGroupUseCase.kt (1)

7-11: 구현이 깔끔합니다.

Use Case 패턴이 올바르게 적용되었고, repository로의 단순 위임 구조가 적절합니다.

app/src/main/java/com/sampoom/android/feature/part/data/remote/dto/GroupDto.kt (1)

3-8: DTO 구조가 적절합니다.

필드 타입과 명명이 명확하고, API 응답 매핑에 적합한 구조입니다.

app/src/main/java/com/sampoom/android/feature/auth/ui/LoginScreen.kt (2)

34-34: 좋은 개선입니다.

collectAsStateWithLifecycle() 사용으로 lifecycle-aware한 상태 수집이 구현되었습니다.


58-127: 상태 참조가 일관되게 업데이트되었습니다.

모든 state 참조가 uiState로 올바르게 변경되었고, 로직이 정상적으로 유지됩니다.

app/src/main/java/com/sampoom/android/feature/part/domain/model/GroupList.kt (1)

3-11: 도메인 모델이 잘 설계되었습니다.

파생 속성(totalCount, isEmpty)이 적절하게 기본값으로 계산되고, empty() 팩토리 메서드가 편리한 빈 상태 생성을 제공합니다.

app/src/main/java/com/sampoom/android/feature/auth/ui/LoginViewModel.kt (1)

23-24: 네이밍 변경이 일관되게 적용되었습니다.

state에서 uiState로의 리네이밍이 파일 전체에 걸쳐 일관되게 적용되었고, LoginScreen의 변경 사항과 잘 연동됩니다.

app/src/main/java/com/sampoom/android/feature/part/domain/model/Part.kt (1)

4-8: 모델 구조가 개선되었습니다.

필드명이 더 명확해졌고(partId, quantity, code 추가), 타입도 Long으로 확장되어 더 큰 값을 처리할 수 있습니다. 계층적 카테고리->그룹->부품 구조와 잘 맞습니다.

app/src/main/java/com/sampoom/android/feature/part/domain/usecase/GetPartUseCase.kt (1)

10-10: Use Case 시그니처가 계층적 구조를 반영합니다.

groupId 파라미터 추가로 그룹별 부품 조회가 가능해졌고, 카테고리->그룹->부품의 계층적 흐름과 잘 맞습니다.

app/src/main/java/com/sampoom/android/feature/part/data/repository/PartRepositoryImpl.kt (1)

26-30: API 경로의 하드코딩된 1 확인됨 - 설계 일관성 재검토 필요

검증 결과:

  • PartApi.kt 라인 18의 @GET("agency/1/group/{groupId}") - 하드코딩된 1 확인됨
  • ✓ 현재 메서드 시그니처들은 모두 일관됨 (모두 groupId만 사용)
  • ⚠️ 설계 패턴 불일치: getGroupListagency/category/{categoryId}로 categoryId를 파라미터화하지만, getPartList는 agencyId를 하드코딩함

현재 상태에서는 PartRepositoryImpl, GetPartUseCase, PartRepository 간 시그니처 일관성은 유지되고 있습니다. 그러나 API 경로의 하드코딩된 1은 다른 엔드포인트의 패턴과 맞지 않으므로, 설계 의도를 명확히 해야 합니다:

  • agencyId가 정말 항상 1이어야 한다면, API 설계가 의도된 것인지 확인
  • 그렇지 않다면, agencyId를 파라미터로 추가하고 모든 계층의 시그니처를 업데이트해야 합니다
app/src/main/java/com/sampoom/android/feature/part/ui/PartScreen.kt (1)

42-47: 에러 라벨 바인딩 시점과 초기 로드 순서 확인 필요.

ViewModel이 init에서 즉시 로드하면 라벨 바인딩 전 실패 시 공백 에러가 노출될 수 있습니다. ViewModel 측 폴백/가드 적용(제안 드린 diff) 후에도 문제가 남으면, 여기서 bindLabel 직후 카테고리 로드를 트리거하는 방식으로 조정해 주세요.

app/src/main/java/com/sampoom/android/core/ui/theme/Color.kt (1)

223-263: 팔레트/토큰 추가 전반은 적절합니다.

테마 확장과 토큰 구성(백그라운드/텍스트/메인 램프)이 일관적입니다. UI 변경에 활용하기 좋습니다.

Comment thread app/src/main/java/com/sampoom/android/app/navigation/AppNavHost.kt Outdated
Comment thread app/src/main/java/com/sampoom/android/app/navigation/AppNavHost.kt
Comment thread app/src/main/java/com/sampoom/android/feature/part/ui/PartScreen.kt Outdated
Comment thread app/src/main/java/com/sampoom/android/feature/part/ui/PartScreen.kt
Copy link
Copy Markdown

@taemin3 taemin3 left a comment

Choose a reason for hiding this comment

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

확인했습니다!

Copy link
Copy Markdown

@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: 4

♻️ Duplicate comments (4)
app/src/main/java/com/sampoom/android/app/navigation/AppNavHost.kt (2)

40-41: 라우트 네임스페이스 정비 완료 — 👍

ROUTE_PART_LISTparts/ 접두어를 추가해 일관성과 충돌 위험을 줄였습니다.


96-99: agencyId 하드코딩(1)으로 다기관 환경에서 오동작

현재 기관/세션 상태를 사용하도록 교체하세요. 최소한 변수로 치환 후 주입/조회로 연결 필요.

예시:

-                onNavigatePartList = { group ->
-                    navController.navigate(routePartList(1, group.id))
-                }
+                onNavigatePartList = { group ->
+                    val currentAgencyId = /* TODO: 세션/VM/DI에서 조회 */
+                    navController.navigate(routePartList(currentAgencyId, group.id))
+                }
app/src/main/java/com/sampoom/android/feature/part/ui/PartViewModel.kt (1)

73-84: 그룹 로드 경합/역전 방지 구현 반영 👍

이전 로드 취소와 최신 선택 검사로 상태 오염을 잘 방지했습니다.

Also applies to: 86-109

app/src/main/java/com/sampoom/android/feature/part/ui/PartScreen.kt (1)

70-93: 검색창 비동작/컴파일 오류: 문자열 리터럴 제거

검증 결과, app/src/main/java/com/sampoom/android/feature/part/ui/PartScreen.kt의 72-73 라인에서 문제가 확인되었습니다. valueonValueChange 파라미터가 문자열 리터럴로 감싸져 있어 동작하지 않으며, OutlinedTextField의 타입 요구사항과도 맞지 않습니다.

필수 수정:

             OutlinedTextField(
-                value = "uiState.searchQuery",
-                onValueChange = { "viewModel.onSearchQueryChanged(it)" },
+                value = uiState.searchQuery,
+                onValueChange = { viewModel.onSearchQueryChanged(it) },
                 placeholder = { Text(stringResource(R.string.part_placeholder_search)) },

유사한 패턴은 다른 파일에서 발견되지 않았습니다.

🧹 Nitpick comments (4)
app/src/main/java/com/sampoom/android/feature/part/ui/PartScreen.kt (4)

202-209: 스크롤 컨테이너 내 fillMaxSize 로딩 박스는 과도함

세로 스크롤 내에서는 고정 높이(예: 200dp) 플레이스홀더가 UX에 더 적합합니다. 카테고리 섹션과 일관되게 맞추세요.

예:

-                        Box(
-                            modifier = Modifier.fillMaxSize(),
+                        Box(
+                            modifier = Modifier
+                                .fillMaxWidth()
+                                .height(200.dp),
                             contentAlignment = Alignment.Center
                         ) {

255-256: 람다 래핑 제거

onClick = { onClick() } 대신 onClick = onClick이 간결합니다.

-        onClick = { onClick() },
+        onClick = onClick,

318-320: 장식 아이콘의 contentDescription 제거

우측 화살표는 장식용이므로 contentDescription = null이 접근성에 적합합니다(카드 전체가 클릭 대상).

-            Icon(
-                painterResource(R.drawable.chevron_right),
-                contentDescription = stringResource(R.string.common_detail)
+            Icon(
+                painterResource(R.drawable.chevron_right),
+                contentDescription = null
             )

283-292: 코드 매핑의 대소문자 견고성 확보

서버/데이터 변경에 대비해 code.uppercase() 기준으로 매핑하세요.

-private fun resourceMapper(code: String): Int {
-    return when (code) {
+private fun resourceMapper(code: String): Int {
+    return when (code.uppercase()) {
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 08b589b and 2d76062.

📒 Files selected for processing (7)
  • app/src/main/java/com/sampoom/android/app/navigation/AppNavHost.kt (6 hunks)
  • app/src/main/java/com/sampoom/android/core/ui/component/EmptyContent.kt (1 hunks)
  • app/src/main/java/com/sampoom/android/core/ui/component/ErrorContent.kt (1 hunks)
  • app/src/main/java/com/sampoom/android/feature/part/ui/PartListViewModel.kt (1 hunks)
  • app/src/main/java/com/sampoom/android/feature/part/ui/PartScreen.kt (2 hunks)
  • app/src/main/java/com/sampoom/android/feature/part/ui/PartViewModel.kt (1 hunks)
  • app/src/main/res/values/strings.xml (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
app/src/main/java/com/sampoom/android/app/navigation/AppNavHost.kt (3)
app/src/main/java/com/sampoom/android/feature/auth/ui/LoginScreen.kt (1)
  • LoginScreen (44-168)
app/src/main/java/com/sampoom/android/feature/part/ui/PartScreen.kt (1)
  • PartScreen (32-244)
app/src/main/java/com/sampoom/android/feature/part/ui/PartListScreen.kt (1)
  • PartListScreen (41-122)
app/src/main/java/com/sampoom/android/feature/part/ui/PartScreen.kt (3)
app/src/main/java/com/sampoom/android/core/ui/component/ErrorContent.kt (1)
  • ErrorContent (18-37)
app/src/main/java/com/sampoom/android/core/ui/component/EmptyContent.kt (1)
  • EmptyContent (10-21)
app/src/main/java/com/sampoom/android/core/ui/theme/Color.kt (3)
  • textSecondaryColor (259-260)
  • backgroundCardColor (253-254)
  • textColor (256-257)
🔇 Additional comments (3)
app/src/main/java/com/sampoom/android/app/navigation/AppNavHost.kt (1)

60-62: 임시 로그인 상태 하드코딩 제거 일정 확인

isLoggedIn = true는 데모 단계로 이해됩니다. Auth 저장소/세션 연동 시점 공유 부탁드립니다.

app/src/main/res/values/strings.xml (2)

40-49: 부품 조회 화면 계층구조 문자열 일관성 확인 완료

검증 결과, part_title_categorypart_title_group 모두 PartScreen.kt에서 Text 컴포저블의 제목 요소로 명확하게 사용되고 있습니다:

  • part_title_category (line 97): MaterialTheme.typography.titleMedium 스타일의 제목으로 표시
  • part_title_group (line 194): 동일하게 제목 스타일로 표시

문자열들이 카테고리 → 그룹 → 부품 계층 구조에 따라 일관되게 구성되어 있으며, 선택 프롬프트(part_select_category, part_title_group)와 빈 상태(part_empty_category, part_empty_group, part_empty_part)가 각 단계마다 대칭적으로 제공되고 있습니다. 한글 표기와 명명 규칙도 일관성 있게 유지되어 있습니다.


40-55: 부품 조회 화면 문자열 리소스 추가 확인 완료

검증 결과 모든 새로운 문자열 리소스가 PartScreen.ktPartListScreen.kt에서 실제로 사용되고 있습니다. 제거된 part_empty 문자열도 코드 어디에서도 참조되지 않으므로 안전하게 제거되었습니다. 문자열 명명 규칙과 한글 표기도 일관되게 유지되고 있습니다.

Copy link
Copy Markdown
Member

@CHOOSLA CHOOSLA left a comment

Choose a reason for hiding this comment

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

승인

Copy link
Copy Markdown

@yangjiseonn yangjiseonn left a comment

Choose a reason for hiding this comment

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

확인했습니다!

@33Auto-Bot 33Auto-Bot added the ready-to-merge 3명 이상의 리뷰어에게 승인되어 병합 준비가 완료된 PR label Oct 18, 2025
@Sangyoon98 Sangyoon98 merged commit de0a64d into dev Oct 18, 2025
5 checks passed
This was referenced Oct 19, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-to-merge 3명 이상의 리뷰어에게 승인되어 병합 준비가 완료된 PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants