Skip to content

✨ :: (#125) - 알레르기 설정 기능 추가#127

Merged
khs3994 merged 11 commits intodevelopfrom
feature/125-add-allergy
Mar 25, 2026
Merged

✨ :: (#125) - 알레르기 설정 기능 추가#127
khs3994 merged 11 commits intodevelopfrom
feature/125-add-allergy

Conversation

@khs3994
Copy link
Copy Markdown
Collaborator

@khs3994 khs3994 commented Mar 23, 2026

💡 개요

  • 알레르기 설정 기능 추가

📃 작업내용

  • 알레르기 설정 진입점 추가
  • 알레르기 설정 페이지 추가
  • 알레르기 정보 저장을 위한 Local DB 추가

🔀 변경사항

  • 급식 조회에서 알러지 정보도 함께 파싱하도록 수정
2026-03-24.12.16.28.mov

🎸 기타

Summary by CodeRabbit

  • 새로운 기능
    • 알레르기 설정 화면 추가: 앱에서 알레르기를 선택/해제할 수 있습니다.
    • 선택정보 저장 및 동기화: 선택한 알레르기 정보가 지속 저장됩니다.
    • 메인 식단에 알레르기 표시: 선택한 알레르기가 포함된 메뉴가 시각적으로 표시됩니다.
    • 설정 메뉴 연동 및 위젯 반영: 설정에서 바로 이동해 관리 가능하며 위젯에도 반영됩니다.
    • 저장 실패 시 사용자 알림(토스트) 추가.

khs3994 and others added 8 commits March 13, 2026 00:59
Co-Authored-By: Claude <noreply@anthropic.com>
기존 String 타입을 MealMenuItem(name, allergyIds)으로 변경하고
괄호 안의 알러지 번호를 파싱하는 로직 추가

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
DataStore 기반 알러지 선택 저장/조회 인프라 추가
(DataSource, Repository, UseCase, DI 바인딩)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
AllergiesViewModel 저장/로드 연동 및
MainScreen에서 알러지 음식 하이라이트 표시

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@khs3994 khs3994 self-assigned this Mar 23, 2026
@khs3994 khs3994 added the enhancement New feature or request label Mar 23, 2026
@khs3994 khs3994 linked an issue Mar 23, 2026 that may be closed by this pull request
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 23, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: b8d28c66-c0f5-4332-96b9-80f505bf10dc

📥 Commits

Reviewing files that changed from the base of the PR and between e2e4b18 and b329c90.

📒 Files selected for processing (13)
  • data/src/main/java/com/onmi/data/datasource/LocalAllergyDataSource.kt
  • data/src/main/java/com/onmi/data/datasourceimpl/LocalAllergyDataSourceImpl.kt
  • data/src/main/java/com/onmi/data/repository/AllergyRepositoryImpl.kt
  • domain/src/main/java/com/onmi/domain/repository/AllergyRepository.kt
  • domain/src/main/java/com/onmi/domain/usecase/allergy/GetSelectedAllergyIdsUseCase.kt
  • feature/allergies/src/main/java/khs/onmi/allergies/screen/AllergiesScreen.kt
  • feature/allergies/src/main/java/khs/onmi/allergies/viewmodel/AllergiesViewModel.kt
  • feature/allergies/src/main/java/khs/onmi/allergies/viewmodel/container/AllergiesState.kt
  • feature/main/src/main/java/khs/onmi/main/component/MealItem.kt
  • feature/main/src/main/java/khs/onmi/main/component/MealsSection.kt
  • feature/main/src/main/java/khs/onmi/main/viewmodel/MainViewModel.kt
  • feature/main/src/main/java/khs/onmi/main/viewmodel/container/MainState.kt
  • feature/setting/src/main/java/khs/onmi/setting/screen/SettingRoute.kt
✅ Files skipped from review due to trivial changes (1)
  • data/src/main/java/com/onmi/data/datasourceimpl/LocalAllergyDataSourceImpl.kt
🚧 Files skipped from review as they are similar to previous changes (10)
  • feature/allergies/src/main/java/khs/onmi/allergies/viewmodel/container/AllergiesState.kt
  • feature/main/src/main/java/khs/onmi/main/viewmodel/container/MainState.kt
  • data/src/main/java/com/onmi/data/datasource/LocalAllergyDataSource.kt
  • domain/src/main/java/com/onmi/domain/usecase/allergy/GetSelectedAllergyIdsUseCase.kt
  • data/src/main/java/com/onmi/data/repository/AllergyRepositoryImpl.kt
  • feature/main/src/main/java/khs/onmi/main/component/MealItem.kt
  • feature/allergies/src/main/java/khs/onmi/allergies/screen/AllergiesScreen.kt
  • feature/main/src/main/java/khs/onmi/main/viewmodel/MainViewModel.kt
  • feature/allergies/src/main/java/khs/onmi/allergies/viewmodel/AllergiesViewModel.kt
  • feature/main/src/main/java/khs/onmi/main/component/MealsSection.kt

Walkthrough

알레르기 설정 기능이 새로 추가되었습니다. DataStore 기반 로컬 선택 값 저장소와 도메인/데이터 레이어 바인딩, UI(알레르기 화면/카드) 및 메인·설정·위젯 연동이 포함되어 식단 항목에 알레르기 매핑이 적용됩니다.

Changes

Cohort / File(s) Summary
디자인시스템 UI
core/designsystem/src/main/java/khs/onmi/core/designsystem/component/Card.kt, core/designsystem/src/main/java/khs/onmi/core/designsystem/icon/AllergiesIcon.kt
AllergiesCard API 변경(아이디/이름/아이콘 리소스로 대체). AllergiesIcon.kt 전체 제거(19개 아이콘 컴포저블 삭제).
도메인 모델·저장소
domain/src/main/java/com/onmi/domain/model/meal/MealMenuItem.kt, domain/src/main/java/com/onmi/domain/model/meal/response/GetMealsResponseModel.kt, domain/src/main/java/com/onmi/domain/repository/AllergyRepository.kt, domain/src/main/java/com/onmi/domain/usecase/allergy/GetSelectedAllergyIdsUseCase.kt
새로운 MealMenuItem 모델 추가(이름, allergyIds). Meals 응답 타입을 List<String>List<MealMenuItem>으로 변경. AllergyRepository 및 조회 UseCase 추가(Flow 기반).
데이터 레이어 구현·DI·DTO
data/src/main/java/com/onmi/data/datasource/LocalAllergyDataSource.kt, data/src/main/java/com/onmi/data/datasourceimpl/LocalAllergyDataSourceImpl.kt, data/src/main/java/com/onmi/data/repository/AllergyRepositoryImpl.kt, data/src/main/java/com/onmi/data/di/DataModule.kt, data/src/main/java/com/onmi/data/di/RepositoryModule.kt, data/src/main/java/com/onmi/data/dto/meal/response/GetTodayMealsResponse.kt, data/src/main/java/com/onmi/data/datasourceimpl/MealDataSourceImpl.kt
DataStore 기반 LocalAllergyDataSourceImpl 추가 및 인터페이스 정의. AllergyRepositoryImpl 추가. Hilt 바인딩(데이터/레포지토리) 추가. Meal 파싱 로직이 MealMenuItem 추출으로 변경되고 DTO 타입 업데이트.
feature/allergies 모듈 (UI, VM, 네비, 상수)
feature/allergies/src/main/java/.../AllergyConstants.kt, .../AllergiesNavigation.kt, .../AllergiesRoute.kt, .../AllergiesScreen.kt, .../AllergiesViewModel.kt, .../container/AllergiesState.kt, .../container/AllergiesSideEffect.kt, feature/allergies/build.gradle.kts
알레르기 상수(19개) 추가. 네비그래프 및 화면(2열 그리드) 추가. Orbit 기반 ViewModel, 상태·부작용 정의. 빌드파일에 Hilt/의존성 추가.
앱 루트·네비·설정 연동
feature/root/build.gradle.kts, feature/root/src/main/java/khs/onmi/root/MainActivity.kt, navigation/src/main/java/khs/onmi/navigation/ONMINavRoutes.kt, feature/setting/src/main/java/.../SettingRoute.kt, feature/setting/src/main/java/.../SettingScreen.kt
루트에 :feature:allergies 모듈 의존성 추가. MainActivity에 네비그래프 등록. 네비 경로 상수 추가. 설정 화면에 알레르기 설정 항목 및 네비게이션 연결.
메인 화면·컴포넌트·뷰모델 연동
feature/main/src/main/java/.../MainViewModel.kt, .../container/MainState.kt, .../component/MealItem.kt, .../component/MealsSection.kt, .../screen/MainScreen.kt
MainState에 selectedAllergyIds 추가. MainViewModel에 GetSelectedAllergyIdsUseCase 주입 및 구독 로직 추가. Meals 컴포넌트가 MealMenuItem과 selectedAllergyIds를 받아 알레르기 표시 적용.
위젯 변경
feature/widget/src/main/java/com/onmi/widget/util/WidgetDataDisplayManager.kt
Widget에 노출되는 mealList가 MealMenuItem에서 이름 리스트로 변환되도록 변경(.map { it.name }).
기타
.gitignore
.omc 항목 추가.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant SettingScreen as 설정 화면
    participant AllergiesRoute as 알레르기 라우트
    participant AllergiesViewModel as ViewModel
    participant AllergyRepository as 저장소
    participant LocalDataSource as DataSource
    participant DataStore as DataStore

    User->>SettingScreen: 알레르기 설정 클릭
    SettingScreen->>AllergiesRoute: onAllergySettingClick
    AllergiesRoute->>AllergiesViewModel: toggleAllergy(id)

    AllergiesViewModel->>AllergyRepository: saveSelectedAllergyIds(ids)
    AllergyRepository->>LocalDataSource: saveSelectedAllergyIds(ids)
    LocalDataSource->>DataStore: 데이터 저장

    AllergiesViewModel->>AllergiesRoute: 상태 갱신 (reduce)
    AllergiesRoute->>User: UI 리렌더링 (선택 반영)
Loading
sequenceDiagram
    participant MainActivity
    participant MainViewModel as MainViewModel
    participant GetSelectedAllergyIdsUseCase as UseCase
    participant AllergyRepository as 저장소
    participant LocalDataSource as DataSource
    participant DataStore as DataStore
    participant MainScreen as 메인 화면

    MainActivity->>MainViewModel: 초기화

    MainViewModel->>GetSelectedAllergyIdsUseCase: invoke()
    GetSelectedAllergyIdsUseCase->>AllergyRepository: getSelectedAllergyIds()
    AllergyRepository->>LocalDataSource: getSelectedAllergyIds()
    LocalDataSource->>DataStore: 데이터 조회

    loop Flow 구독
        DataStore-->>LocalDataSource: 선택 ID 집합 방출
        LocalDataSource-->>AllergyRepository: Flow 전달
        AllergyRepository-->>GetSelectedAllergyIdsUseCase: Flow 전달
        GetSelectedAllergyIdsUseCase-->>MainViewModel: 집합 수신
        MainViewModel->>MainScreen: uiState 방출 (selectedAllergyIds 업데이트)
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 분

Possibly related PRs

Suggested reviewers

  • sagwamatrlawns

🐰 알레르기 선택 축하해요
작은 토글이 흐름을 타고
ID는 DataStore 속으로
화면에선 반짝이는 카드 하나
안전한 식탁, 당근 한 입 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목은 알레르기 설정 기능 추가라는 주요 변경사항을 명확하게 반영하고 있으며, 전체 PR의 핵심 목표와 일치합니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/125-add-allergy

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.

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

이 PR은 사용자가 자신의 알레르기 정보를 설정하고 관리할 수 있는 기능을 도입합니다. 이를 위해 알레르기 설정 화면이 추가되었고, 선택된 알레르기 정보를 로컬에 저장하는 데이터 계층이 구축되었습니다. 또한, 급식 메뉴를 표시할 때 각 음식에 포함된 알레르기 유발 성분을 식별하여 사용자에게 시각적으로 알릴 수 있도록 기존 급식 파싱 로직이 확장되었습니다. 이로써 사용자 경험이 향상되고 개인화된 정보를 제공할 수 있게 됩니다.

Highlights

  • 알레르기 설정 기능 추가: 사용자가 자신의 알레르기 정보를 설정하고 관리할 수 있는 새로운 기능이 추가되었습니다.
  • 로컬 DB를 통한 알레르기 정보 저장: 선택된 알레르기 정보를 로컬 데이터베이스에 저장하여 앱 재시작 후에도 유지되도록 구현되었습니다.
  • 급식 정보 파싱 개선: 급식 메뉴를 파싱할 때 알레르기 정보도 함께 추출하여 표시할 수 있도록 로직이 수정되었습니다.
  • UI 컴포넌트 및 내비게이션 추가: 알레르기 설정을 위한 새로운 UI 컴포넌트와 내비게이션 경로가 추가되었습니다.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

이 PR은 사용자가 알레르기를 선택하고, 선택된 알레르기 정보를 급식 메뉴에서 하이라이트하는 새로운 알레르기 설정 기능을 추가합니다. DataStore를 이용한 데이터 영속성, Jetpack Compose를 사용한 UI, Orbit MVI를 통한 상태 관리를 포함하여 기능 구현이 포괄적입니다. 새로운 기능 모듈과 명확한 관심사 분리로 코드 구조가 잘 잡혀있습니다. 코드의 명확성과 안정성을 높이기 위해 ViewModel의 상태 관리 및 알레르기 ID 저장을 위한 자료구조 선택과 관련하여 몇 가지 개선 제안 사항이 있습니다.

Copy link
Copy Markdown
Contributor

@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

🧹 Nitpick comments (8)
feature/allergies/src/main/java/khs/onmi/allergies/viewmodel/container/AllergiesSideEffect.kt (1)

4-4: 토스트 메시지 타입을 리소스 기반으로 추상화하는 것을 권장합니다.

String 직결 방식은 지역화 확장 시 비용이 커질 수 있어, messageResId 또는 공용 UiText 타입으로 전환해두면 유지보수가 쉬워집니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@feature/allergies/src/main/java/khs/onmi/allergies/viewmodel/container/AllergiesSideEffect.kt`
at line 4, The ShowToast side-effect currently carries a plain String (data
class ShowToast(val message: String) : AllergiesSideEffect()), which hinders
localization; change its payload to a resource-based abstraction (e.g.,
messageResId: Int or a shared UiText type) and update all places that construct
or consume ShowToast (viewModel emission sites and UI observers) to pass and
resolve the resource/UiText instead of raw strings; ensure the UI layer converts
UiText or resource IDs to localized strings before showing the toast and update
any tests/mocks to use the new type.
domain/src/main/java/com/onmi/domain/repository/AllergyRepository.kt (1)

6-7: 선택 ID 컬렉션은 Set<Int> 계약을 고려해보세요.

현재 List<Int>는 중복 저장 가능성이 열려 있어, 도메인 계약 자체로 유일성을 보장하면 상태/저장소 일관성이 좋아집니다.

🔧 제안 예시
 interface AllergyRepository {
-    fun getSelectedAllergyIds(): Flow<List<Int>>
-    suspend fun saveSelectedAllergyIds(ids: List<Int>)
+    fun getSelectedAllergyIds(): Flow<Set<Int>>
+    suspend fun saveSelectedAllergyIds(ids: Set<Int>)
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@domain/src/main/java/com/onmi/domain/repository/AllergyRepository.kt` around
lines 6 - 7, Update the AllergyRepository contract to enforce uniqueness by
changing the return and parameter types from List<Int> to Set<Int>: modify the
interface methods getSelectedAllergyIds() to return Flow<Set<Int>> and
saveSelectedAllergyIds(ids: Set<Int>); then update all implementations of
AllergyRepository (and any classes referencing getSelectedAllergyIds or
saveSelectedAllergyIds) to persist/emit Sets (or deduplicate incoming Lists to
Sets inside implementations) and adjust callers to convert between List and Set
as needed so domain-level uniqueness is guaranteed; target symbols:
AllergyRepository, getSelectedAllergyIds, saveSelectedAllergyIds.
data/src/main/java/com/onmi/data/datasource/LocalAllergyDataSource.kt (1)

6-7: 선택 ID는 List<Int>보다 Set<Int>가 의도를 더 잘 드러냅니다.

현재 계약은 중복 ID 저장을 허용합니다. “선택 상태”라면 집합 타입이 더 안전하고 호출부 실수를 줄입니다.

🔧 제안 수정안
 interface LocalAllergyDataSource {
-    fun getSelectedAllergyIds(): Flow<List<Int>>
-    suspend fun saveSelectedAllergyIds(ids: List<Int>)
+    fun getSelectedAllergyIds(): Flow<Set<Int>>
+    suspend fun saveSelectedAllergyIds(ids: Set<Int>)
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@data/src/main/java/com/onmi/data/datasource/LocalAllergyDataSource.kt` around
lines 6 - 7, Change the API to use sets to express “selected” semantics: update
the LocalAllergyDataSource contract methods getSelectedAllergyIds() to return
Flow<Set<Int>> and saveSelectedAllergyIds(ids: Set<Int>), then update every
implementation (repositories, DAOs, mappers, serializers) that implements or
calls getSelectedAllergyIds/saveSelectedAllergyIds to convert between List and
Set (deduplicate when reading/writing) and adjust persistence code
(entities/TypeConverters) and unit tests accordingly so callers receive/submit a
Set<Int> rather than a List<Int>.
feature/allergies/src/main/java/khs/onmi/allergies/constant/AllergyConstants.kt (1)

14-32: 사용자 노출 문자열을 리소스로 분리하는 것을 권장합니다.

알레르기명이 코드에 하드코딩되어 있어 다국어 대응/문구 변경 시 수정 범위가 커집니다. 문자열 리소스로 분리하면 관리가 훨씬 안정적입니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@feature/allergies/src/main/java/khs/onmi/allergies/constant/AllergyConstants.kt`
around lines 14 - 32, The hardcoded allergy names in AllergyConstants.kt (the
Allergy(...) enum/list entries such as Allergy(1, "난류", ...), Allergy(2, "우유",
...), etc.) should be moved to string resources; replace the raw Korean strings
with resource lookups (e.g., use context.getString(R.string.allergy_egg) or pass
a string resource id) and add corresponding entries in strings.xml for each
unique allergy (allergy_egg, allergy_milk, ...), updating any constructors or
consumers (e.g., the Allergy data class or enum factory methods) to
accept/respect string resource ids or resolved strings so UI code displays
localized text via Android resource APIs.
feature/setting/src/main/java/khs/onmi/setting/screen/SettingRoute.kt (1)

54-57: 빠른 연속 탭 시 동일 화면이 백스택에 중복될 수 있습니다.

onAllergySettingClick에서 navigate를 호출할 때 launchSingleTop = true를 적용하면 사용자가 빠르게 연속으로 탭했을 때 동일한 목적지가 백스택에 중복되는 것을 방지할 수 있습니다.

🔧 제안 수정안
         onAllergySettingClick = {
             EventLogger.clickAllergySettingButton()
-            navController.navigate(ONMINavRoutes.ALLERGIES)
+            navController.navigate(ONMINavRoutes.ALLERGIES) {
+                launchSingleTop = true
+            }
         },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@feature/setting/src/main/java/khs/onmi/setting/screen/SettingRoute.kt` around
lines 54 - 57, The onAllergySettingClick handler currently calls
EventLogger.clickAllergySettingButton() and
navController.navigate(ONMINavRoutes.ALLERGIES) which can push duplicate entries
on rapid taps; update the navigate call in onAllergySettingClick to use the
NavController navigate overload with a NavOptionsBuilder and set launchSingleTop
= true (i.e., navController.navigate(ONMINavRoutes.ALLERGIES) { launchSingleTop
= true }) so repeated quick taps do not duplicate the same destination on the
back stack.
feature/main/src/main/java/khs/onmi/main/component/MealItem.kt (1)

45-52: 알레르기 매칭은 Set 기반 조회로 한 번 최적화해두는 것을 권장합니다.

Line 51은 메뉴 아이템마다 List 포함 검사(in)를 수행합니다. 선택 ID를 한 번 Set으로 변환해두면 렌더링 경로에서 비용을 줄일 수 있습니다.

♻️ 제안 수정안
+import androidx.compose.runtime.remember
 import com.onmi.domain.model.meal.MealMenuItem
@@
 fun MealsItem(
@@
 ) {
+    val selectedAllergyIdSet = remember(selectedAllergyIds) { selectedAllergyIds.toSet() }
     ONMITheme { color, typography ->
@@
             meals.forEach { meal ->
                 MealItem(
@@
-                    isAllergyFood = meal.allergyIds.any { it in selectedAllergyIds }
+                    isAllergyFood = meal.allergyIds.any(selectedAllergyIdSet::contains)
                 )
             }
         }
     }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@feature/main/src/main/java/khs/onmi/main/component/MealItem.kt` around lines
45 - 52, selectedAllergyIds is being checked with List membership inside the
rendering loop causing repeated O(n) lookups; convert selectedAllergyIds to a
Set once (e.g., selectedAllergyIdSet) before the meals.forEach loop and update
the allergy match check used by MealItem (currently allergyIds.any { it in
selectedAllergyIds }) to use the set (e.g., allergyIds.any { it in
selectedAllergyIdSet } or allergyIds.any(selectedAllergyIdSet::contains) ) so
each containment check is O(1).
data/src/main/java/com/onmi/data/dto/meal/response/GetTodayMealsResponse.kt (1)

3-10: Data 레이어에서 Domain 모델 직접 참조

GetTodayMealsResponse DTO가 MealMenuItem domain 모델을 직접 import하고 있습니다. Clean Architecture 원칙에 따르면 data 레이어는 자체 모델을 가지고 domain으로 매핑하는 것이 이상적입니다.

현재 이 DTO는 역직렬화되지 않고 MealDataSourceImpl에서 직접 생성되어 바로 toModel()로 변환되므로 기능상 문제는 없습니다. 향후 리팩토링 시 고려해 주세요.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@data/src/main/java/com/onmi/data/dto/meal/response/GetTodayMealsResponse.kt`
around lines 3 - 10, GetTodayMealsResponse가 data 계층에서 domain 모델 MealMenuItem을 직접
참조하고 있으니, 데이터 계층 전용 DTO 타입을 만들고 이를 domain 모델로 매핑하도록 변경하세요: 새 DTO(예:
TodayMealItemDto / GetTodayMealsDto)를 정의하여 기존 GetTodayMealsResponse의
Pair<List<MealMenuItem>, String> 구조를 그대로 반영하고, MealDataSourceImpl에서 현재 사용 중인
GetTodayMealsResponse 대신 새 DTO를 생성·사용한 뒤 toModel() 또는 변환 함수(예: toDomainModel())를
구현해 DTO->domain(MealMenuItem)으로 변환하도록 교체하세요; 변경 대상 식별자: GetTodayMealsResponse,
MealMenuItem, MealDataSourceImpl, toModel().
feature/main/src/main/java/khs/onmi/main/component/MealsSection.kt (1)

86-90: Material 3에서 Divider는 deprecated 되었습니다.

DividerHorizontalDivider로 변경하세요. Material 3에서 Divider는 더 이상 권장되지 않으며, HorizontalDivider가 직접 대체 컴포넌트입니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@feature/main/src/main/java/khs/onmi/main/component/MealsSection.kt` around
lines 86 - 90, Replace the deprecated Divider usage in MealsSection.kt with the
Material3 HorizontalDivider: locate the Divider(...) call (the one using
thickness = 1.dp, color = color.UnselectedSecondary, modifier =
Modifier.padding(vertical = 32.dp)) and change it to HorizontalDivider(...)
preserving the same thickness, color and modifier arguments; also update/remove
the old Divider import and add the Material3 HorizontalDivider import so the
component resolves to androidx.compose.material3.HorizontalDivider (ensure color
reference UnselectedSecondary still matches the Material3 color type).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@core/designsystem/src/main/java/khs/onmi/core/designsystem/component/Card.kt`:
- Around line 85-90: The Icon in Card.kt currently uses a fixed
contentDescription ("Allergies Icon") which harms accessibility; update the Icon
call that uses painterResource(id = iconId) (in the Card composable) to either
set contentDescription = null when the icon is purely decorative, or accept and
pass a localized/props-driven contentDescription parameter (e.g.,
iconContentDescription) so screen readers get the right, non-duplicative label;
ensure you update any callers of Card to provide the description when needed and
keep the tint/isSelected logic unchanged.

In
`@data/src/main/java/com/onmi/data/datasourceimpl/LocalAllergyDataSourceImpl.kt`:
- Around line 20-24: getSelectedAllergyIds() can crash if non-numeric values are
stored because it uses it.toInt(); update the mapping to safely parse ints using
toIntOrNull() and filter nulls (e.g., use mapNotNull) when transforming
prefs[SELECTED_ALLERGY_IDS] inside the Flow.map so invalid entries are ignored
and an empty list is returned if none are valid.

In
`@feature/allergies/src/main/java/khs/onmi/allergies/viewmodel/AllergiesViewModel.kt`:
- Around line 30-41: toggleAllergy currently calls
allergyRepository.saveSelectedAllergyIds(...) without error handling and even
uses state.selectedAllergyIds (old value) after reduce; wrap the save in a
try/catch, call save with the computed updatedIds (the variable inside reduce)
and on failure post a user-visible message (Toast) and revert the state to the
previous selectedAllergyIds (undo the change) — locate this logic in the
toggleAllergy function (intent/reduce block) and handle exceptions from
allergyRepository.saveSelectedAllergyIds accordingly.

In `@feature/main/src/main/java/khs/onmi/main/viewmodel/MainViewModel.kt`:
- Around line 38-41: collectAllergyIds currently calls
getSelectedAllergyIdsUseCase().collect without handling exceptions, so a bad
value (e.g., toInt() failure) can cancel the flow and stop future updates; fix
by adding a Flow.catch { e -> /* log e */ reduce { state.copy(selectedAllergyIds
= emptyList()) } } (or otherwise handle the error and provide a safe fallback)
before collect in collectAllergyIds, ensuring getSelectedAllergyIdsUseCase()
errors do not cancel the coroutine and selectedAllergyIds is updated to a safe
value via reduce.

---

Nitpick comments:
In `@data/src/main/java/com/onmi/data/datasource/LocalAllergyDataSource.kt`:
- Around line 6-7: Change the API to use sets to express “selected” semantics:
update the LocalAllergyDataSource contract methods getSelectedAllergyIds() to
return Flow<Set<Int>> and saveSelectedAllergyIds(ids: Set<Int>), then update
every implementation (repositories, DAOs, mappers, serializers) that implements
or calls getSelectedAllergyIds/saveSelectedAllergyIds to convert between List
and Set (deduplicate when reading/writing) and adjust persistence code
(entities/TypeConverters) and unit tests accordingly so callers receive/submit a
Set<Int> rather than a List<Int>.

In `@data/src/main/java/com/onmi/data/dto/meal/response/GetTodayMealsResponse.kt`:
- Around line 3-10: GetTodayMealsResponse가 data 계층에서 domain 모델 MealMenuItem을 직접
참조하고 있으니, 데이터 계층 전용 DTO 타입을 만들고 이를 domain 모델로 매핑하도록 변경하세요: 새 DTO(예:
TodayMealItemDto / GetTodayMealsDto)를 정의하여 기존 GetTodayMealsResponse의
Pair<List<MealMenuItem>, String> 구조를 그대로 반영하고, MealDataSourceImpl에서 현재 사용 중인
GetTodayMealsResponse 대신 새 DTO를 생성·사용한 뒤 toModel() 또는 변환 함수(예: toDomainModel())를
구현해 DTO->domain(MealMenuItem)으로 변환하도록 교체하세요; 변경 대상 식별자: GetTodayMealsResponse,
MealMenuItem, MealDataSourceImpl, toModel().

In `@domain/src/main/java/com/onmi/domain/repository/AllergyRepository.kt`:
- Around line 6-7: Update the AllergyRepository contract to enforce uniqueness
by changing the return and parameter types from List<Int> to Set<Int>: modify
the interface methods getSelectedAllergyIds() to return Flow<Set<Int>> and
saveSelectedAllergyIds(ids: Set<Int>); then update all implementations of
AllergyRepository (and any classes referencing getSelectedAllergyIds or
saveSelectedAllergyIds) to persist/emit Sets (or deduplicate incoming Lists to
Sets inside implementations) and adjust callers to convert between List and Set
as needed so domain-level uniqueness is guaranteed; target symbols:
AllergyRepository, getSelectedAllergyIds, saveSelectedAllergyIds.

In
`@feature/allergies/src/main/java/khs/onmi/allergies/constant/AllergyConstants.kt`:
- Around line 14-32: The hardcoded allergy names in AllergyConstants.kt (the
Allergy(...) enum/list entries such as Allergy(1, "난류", ...), Allergy(2, "우유",
...), etc.) should be moved to string resources; replace the raw Korean strings
with resource lookups (e.g., use context.getString(R.string.allergy_egg) or pass
a string resource id) and add corresponding entries in strings.xml for each
unique allergy (allergy_egg, allergy_milk, ...), updating any constructors or
consumers (e.g., the Allergy data class or enum factory methods) to
accept/respect string resource ids or resolved strings so UI code displays
localized text via Android resource APIs.

In
`@feature/allergies/src/main/java/khs/onmi/allergies/viewmodel/container/AllergiesSideEffect.kt`:
- Line 4: The ShowToast side-effect currently carries a plain String (data class
ShowToast(val message: String) : AllergiesSideEffect()), which hinders
localization; change its payload to a resource-based abstraction (e.g.,
messageResId: Int or a shared UiText type) and update all places that construct
or consume ShowToast (viewModel emission sites and UI observers) to pass and
resolve the resource/UiText instead of raw strings; ensure the UI layer converts
UiText or resource IDs to localized strings before showing the toast and update
any tests/mocks to use the new type.

In `@feature/main/src/main/java/khs/onmi/main/component/MealItem.kt`:
- Around line 45-52: selectedAllergyIds is being checked with List membership
inside the rendering loop causing repeated O(n) lookups; convert
selectedAllergyIds to a Set once (e.g., selectedAllergyIdSet) before the
meals.forEach loop and update the allergy match check used by MealItem
(currently allergyIds.any { it in selectedAllergyIds }) to use the set (e.g.,
allergyIds.any { it in selectedAllergyIdSet } or
allergyIds.any(selectedAllergyIdSet::contains) ) so each containment check is
O(1).

In `@feature/main/src/main/java/khs/onmi/main/component/MealsSection.kt`:
- Around line 86-90: Replace the deprecated Divider usage in MealsSection.kt
with the Material3 HorizontalDivider: locate the Divider(...) call (the one
using thickness = 1.dp, color = color.UnselectedSecondary, modifier =
Modifier.padding(vertical = 32.dp)) and change it to HorizontalDivider(...)
preserving the same thickness, color and modifier arguments; also update/remove
the old Divider import and add the Material3 HorizontalDivider import so the
component resolves to androidx.compose.material3.HorizontalDivider (ensure color
reference UnselectedSecondary still matches the Material3 color type).

In `@feature/setting/src/main/java/khs/onmi/setting/screen/SettingRoute.kt`:
- Around line 54-57: The onAllergySettingClick handler currently calls
EventLogger.clickAllergySettingButton() and
navController.navigate(ONMINavRoutes.ALLERGIES) which can push duplicate entries
on rapid taps; update the navigate call in onAllergySettingClick to use the
NavController navigate overload with a NavOptionsBuilder and set launchSingleTop
= true (i.e., navController.navigate(ONMINavRoutes.ALLERGIES) { launchSingleTop
= true }) so repeated quick taps do not duplicate the same destination on the
back stack.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 3480ad02-936a-4310-ae7d-5f5804465fda

📥 Commits

Reviewing files that changed from the base of the PR and between cc2eaa2 and e2e4b18.

📒 Files selected for processing (33)
  • .gitignore
  • core/designsystem/src/main/java/khs/onmi/core/designsystem/component/Card.kt
  • core/designsystem/src/main/java/khs/onmi/core/designsystem/icon/AllergiesIcon.kt
  • data/src/main/java/com/onmi/data/datasource/LocalAllergyDataSource.kt
  • data/src/main/java/com/onmi/data/datasourceimpl/LocalAllergyDataSourceImpl.kt
  • data/src/main/java/com/onmi/data/datasourceimpl/MealDataSourceImpl.kt
  • data/src/main/java/com/onmi/data/di/DataModule.kt
  • data/src/main/java/com/onmi/data/di/RepositoryModule.kt
  • data/src/main/java/com/onmi/data/dto/meal/response/GetTodayMealsResponse.kt
  • data/src/main/java/com/onmi/data/repository/AllergyRepositoryImpl.kt
  • domain/src/main/java/com/onmi/domain/model/meal/MealMenuItem.kt
  • domain/src/main/java/com/onmi/domain/model/meal/response/GetMealsResponseModel.kt
  • domain/src/main/java/com/onmi/domain/repository/AllergyRepository.kt
  • domain/src/main/java/com/onmi/domain/usecase/allergy/GetSelectedAllergyIdsUseCase.kt
  • feature/allergies/build.gradle.kts
  • feature/allergies/src/main/java/khs/onmi/allergies/constant/AllergyConstants.kt
  • feature/allergies/src/main/java/khs/onmi/allergies/navigation/AllergiesNavigation.kt
  • feature/allergies/src/main/java/khs/onmi/allergies/screen/AllergiesRoute.kt
  • feature/allergies/src/main/java/khs/onmi/allergies/screen/AllergiesScreen.kt
  • feature/allergies/src/main/java/khs/onmi/allergies/viewmodel/AllergiesViewModel.kt
  • feature/allergies/src/main/java/khs/onmi/allergies/viewmodel/container/AllergiesSideEffect.kt
  • feature/allergies/src/main/java/khs/onmi/allergies/viewmodel/container/AllergiesState.kt
  • feature/main/src/main/java/khs/onmi/main/component/MealItem.kt
  • feature/main/src/main/java/khs/onmi/main/component/MealsSection.kt
  • feature/main/src/main/java/khs/onmi/main/screen/MainScreen.kt
  • feature/main/src/main/java/khs/onmi/main/viewmodel/MainViewModel.kt
  • feature/main/src/main/java/khs/onmi/main/viewmodel/container/MainState.kt
  • feature/root/build.gradle.kts
  • feature/root/src/main/java/khs/onmi/root/MainActivity.kt
  • feature/setting/src/main/java/khs/onmi/setting/screen/SettingRoute.kt
  • feature/setting/src/main/java/khs/onmi/setting/screen/SettingScreen.kt
  • feature/widget/src/main/java/com/onmi/widget/util/WidgetDataDisplayManager.kt
  • navigation/src/main/java/khs/onmi/navigation/ONMINavRoutes.kt
💤 Files with no reviewable changes (1)
  • core/designsystem/src/main/java/khs/onmi/core/designsystem/icon/AllergiesIcon.kt

Comment thread data/src/main/java/com/onmi/data/datasourceimpl/LocalAllergyDataSourceImpl.kt Outdated
Comment thread feature/main/src/main/java/khs/onmi/main/viewmodel/MainViewModel.kt Outdated
khs3994 and others added 3 commits March 25, 2026 19:57
- AllergiesViewModel: updatedIds를 reduce 외부에서 계산하여 레이스 컨디션 제거
- AllergiesViewModel: 저장 실패 시 이전 상태로 원복 및 Toast 표시
- LocalAllergyDataSourceImpl: toInt() → toIntOrNull() + mapNotNull로 크래시 방지
- MainViewModel: collectAllergyIds에 Flow.catch 추가로 코루틴 취소 방지

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
알러지 ID는 중복 불가 + 멤버십 체크가 주 용도이므로 Set이 의미적으로 적합하며
contains 연산이 O(1)로 개선됨

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- SettingRoute: 알러지 설정 navigate에 launchSingleTop 적용
- MealsSection: deprecated Divider를 HorizontalDivider로 교체

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@khs3994 khs3994 merged commit e517177 into develop Mar 25, 2026
2 checks passed
@khs3994 khs3994 deleted the feature/125-add-allergy branch March 25, 2026 13:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

알레르기 기능 추가

1 participant