Skip to content

[#132] UserDefautls를 관리하는 객체를 Persistence 디렉토리 내에 구현한다#133

Merged
opficdev merged 12 commits intodevelopfrom
feat/#132-Persistence
Feb 25, 2026
Merged

[#132] UserDefautls를 관리하는 객체를 Persistence 디렉토리 내에 구현한다#133
opficdev merged 12 commits intodevelopfrom
feat/#132-Persistence

Conversation

@opficdev
Copy link
Copy Markdown
Owner

@opficdev opficdev self-assigned this Feb 25, 2026
@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @opficdev, 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은 애플리케이션 내 사용자 환경설정 관리 방식을 리팩토링합니다. UserDefaults에 직접 접근하는 방식을 추상화하기 위해 전용 UserPreferencesRepository와 관련 UseCase를 도입했습니다. 이 변경으로 시스템 테마, 첫 실행 상태, 최근 검색어, 푸시 알림 표시 설정 등 다양한 사용자 설정 처리가 중앙 집중화되어, 더 모듈화되고 테스트하기 쉬운 아키텍처를 제공합니다.

Highlights

  • 사용자 환경설정 관리 중앙화: 시스템 테마, 첫 실행 여부, 최근 검색어, 푸시 알림 설정 등 사용자 환경설정을 관리하기 위한 UserPreferencesRepository 프로토콜과 UserPreferencesRepositoryImpl 구현체가 도입되었습니다.
  • 의존성 주입 업데이트: DataAssembler, DomainAssembler, InfraAssembler가 UserPreferencesRepository 및 관련 스토어(UserDefaultsStore, ThemeStore), 그리고 새로운 UseCase들을 등록하고 해결하도록 업데이트되었습니다.
  • ViewModel 의존성 리팩토링: RootViewModel, PushNotificationViewModel, SearchViewModel, SettingViewModel이 UserDefaults에 직접 접근하는 대신 새로운 UserPreferencesRepository와 UseCase를 사용하도록 변경되었습니다.
  • 테마 관리 개선: 앱의 테마 관리가 UserPreferencesRepository와 ThemeStore를 통해 중앙 집중화되었으며, DevLogApp 및 SettingView에서 @AppStorage를 직접 사용하는 방식이 제거되었습니다.
  • 새로운 사용자 환경설정 UseCase 추가: 첫 실행, 최근 검색어, 푸시 알림 쿼리 설정, 시스템 테마 관리를 위한 여러 UseCase가 DevLog/Domain/UseCase/UserPreferences 경로에 추가되었습니다.
Changelog
  • DevLog/App/Assembler/DataAssembler.swift
    • UserPreferencesRepository를 등록했습니다.
  • DevLog/App/Assembler/DomainAssembler.swift
    • assemble 메서드를 헬퍼 함수를 사용하여 유스케이스를 등록하도록 리팩토링했습니다.
    • 새로운 사용자 환경설정 관련 유스케이스를 등록하기 위한 registerUserPreferencesUseCases 메서드를 추가했습니다.
  • DevLog/App/Assembler/InfraAssembler.swift
    • UserDefaultsStore와 ThemeStore를 등록했습니다.
  • DevLog/App/DevLogApp.swift
    • 테마에 대한 @AppStorage 직접 사용을 제거했습니다.
    • 새로운 테마 및 첫 실행 관련 유스케이스를 전달하도록 RootView 초기화를 업데이트했습니다.
  • DevLog/App/RootView.swift
    • viewModel.state.theme에 따라 preferredColorScheme을 적용했습니다.
    • 첫 실행을 위한 onAppear 로직을 조정했습니다.
  • DevLog/Data/Protocol/UserPreferencesRepository.swift
    • UserPreferencesRepository 프로토콜을 추가했습니다.
  • DevLog/Data/Repository/UserPreferencesRepositoryImpl.swift
    • UserPreferencesRepositoryImpl 구현체를 추가했습니다.
  • DevLog/Domain/UseCase/UserPreferences/Launch/FetchFirstLaunchUseCase.swift
    • FetchFirstLaunchUseCase 프로토콜을 추가했습니다.
  • DevLog/Domain/UseCase/UserPreferences/Launch/FetchFirstLaunchUseCaseImpl.swift
    • FetchFirstLaunchUseCaseImpl을 추가했습니다.
  • DevLog/Domain/UseCase/UserPreferences/Launch/UpdateFirstLaunchUseCase.swift
    • UpdateFirstLaunchUseCase 프로토콜을 추가했습니다.
  • DevLog/Domain/UseCase/UserPreferences/Launch/UpdateFirstLaunchUseCaseImpl.swift
    • UpdateFirstLaunchUseCaseImpl을 추가했습니다.
  • DevLog/Domain/UseCase/UserPreferences/PushNotification/FetchPushNotificationQueryUseCase.swift
    • FetchPushNotificationQueryUseCase 프로토콜을 추가했습니다.
  • DevLog/Domain/UseCase/UserPreferences/PushNotification/FetchPushNotificationQueryUseCaseImpl.swift
    • FetchPushNotificationQueryUseCaseImpl을 추가했습니다.
  • DevLog/Domain/UseCase/UserPreferences/PushNotification/UpdatePushNotificationQueryUseCase.swift
    • UpdatePushNotificationQueryUseCase 프로토콜을 추가했습니다.
  • DevLog/Domain/UseCase/UserPreferences/PushNotification/UpdatePushNotificationQueryUseCaseImpl.swift
    • UpdatePushNotificationQueryUseCaseImpl을 추가했습니다.
  • DevLog/Domain/UseCase/UserPreferences/Search/FetchRecentSearchQueriesUseCase.swift
    • FetchRecentSearchQueriesUseCase 프로토콜을 추가했습니다.
  • DevLog/Domain/UseCase/UserPreferences/Search/FetchRecentSearchQueriesUseCaseImpl.swift
    • FetchRecentSearchQueriesUseCaseImpl을 추가했습니다.
  • DevLog/Domain/UseCase/UserPreferences/Search/UpdateRecentSearchQueriesUseCase.swift
    • UpdateRecentSearchQueriesUseCase 프로토콜을 추가했습니다.
  • DevLog/Domain/UseCase/UserPreferences/Search/UpdateRecentSearchQueriesUseCaseImpl.swift
    • UpdateRecentSearchQueriesUseCaseImpl을 추가했습니다.
  • DevLog/Domain/UseCase/UserPreferences/Theme/ObserveSystemThemeUseCase.swift
    • ObserveSystemThemeUseCase 프로토콜을 추가했습니다.
  • DevLog/Domain/UseCase/UserPreferences/Theme/ObserveSystemThemeUseCaseImpl.swift
    • ObserveSystemThemeUseCaseImpl을 추가했습니다.
  • DevLog/Domain/UseCase/UserPreferences/Theme/UpdateSystemThemeUseCase.swift
    • UpdateSystemThemeUseCase 프로토콜을 추가했습니다.
  • DevLog/Domain/UseCase/UserPreferences/Theme/UpdateSystemThemeUseCaseImpl.swift
    • UpdateSystemThemeUseCaseImpl을 추가했습니다.
  • DevLog/Presentation/ViewModel/PushNotificationViewModel.swift
    • UserDefaults 직접 접근을 FetchPushNotificationQueryUseCase 및 UpdatePushNotificationQueryUseCase로 대체했습니다.
  • DevLog/Presentation/ViewModel/RootViewModel.swift
    • 첫 실행 및 테마에 대한 UserDefaults 직접 접근을 새로운 UseCase로 대체했습니다.
    • 테마 모니터링 로직을 추가했습니다.
  • DevLog/Presentation/ViewModel/SearchViewModel.swift
    • 최근 검색어에 대한 UserDefaults 직접 접근을 FetchRecentSearchQueriesUseCase 및 UpdateRecentSearchQueriesUseCase로 대체했습니다.
  • DevLog/Presentation/ViewModel/SettingViewModel.swift
    • 테마 상태를 SystemTheme으로 업데이트했습니다.
    • 테마 관찰 및 업데이트를 위한 새로운 테마 UseCase를 통합했습니다.
  • DevLog/Storage/Persistence/ThemeStore.swift
    • ThemeStore 클래스를 추가했습니다.
  • DevLog/Storage/Persistence/UserDefaultsStore.swift
    • UserDefaultsStore 클래스를 추가했습니다.
  • DevLog/UI/Common/MainView.swift
    • 새로운 쿼리 UseCase를 전달하도록 PushNotificationView 초기화를 업데이트했습니다.
  • DevLog/UI/Home/HomeView.swift
    • 새로운 최근 검색어 UseCase를 전달하도록 SearchView 초기화를 업데이트했습니다.
  • DevLog/UI/Profile/ProfileView.swift
    • 새로운 테마 UseCase를 전달하도록 SettingView 초기화를 업데이트했습니다.
  • DevLog/UI/Setting/SettingView.swift
    • 테마에 대한 @AppStorage를 제거했습니다.
    • 테마 표시를 업데이트했습니다.
    • ThemeView에 테마 바인딩을 전달했습니다.
  • DevLog/UI/Setting/ThemeView.swift
Activity
  • 이 PR은 이슈 #132를 해결합니다.
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.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

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

This pull request refactors UserDefaults access through UserPreferencesRepository, enhancing testability and maintainability by decoupling ViewModel and UserDefaults implementations. It introduces UserDefaultsStore and ThemeStore, defining user setting-related use cases following clean architecture principles. However, a critical vulnerability exists in the isFirstLaunch implementation, leading to a permanent denial of service. The method incorrectly checks for a Boolean value's existence, causing the application to remain in a perpetual "first launch" state, which triggers repeated automatic sign-outs and prevents users from accessing the main application features. This issue must be addressed before merging.

Comment on lines +51 to +54
if store.string(forKey: Key.firstLaunch) == nil {
return true
}
return store.bool(forKey: Key.firstLaunch)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

security-high high

The isFirstLaunch() method incorrectly uses store.string(forKey:) to check for the existence of a Boolean value in UserDefaults. This will always evaluate to true, causing a perpetual "first launch" state and a denial of service.

Comment on lines +98 to +100
try await signOutUseCase.execute()
send(.didLogined(false))
sessionUseCase.execute(false)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

security-medium medium

The automatic sign-out logic removed the error handling that was previously present. If signOutUseCase.execute() fails (e.g., due to a network error), the subsequent lines that clear the local session state (send(.didLogined(false)) and sessionUseCase.execute(false)) will not be executed. This leaves the user's session active on the device, which could lead to unauthorized access if the device is shared or accessed by another person. It is recommended to ensure that the local session state is always cleared, regardless of whether the server-side sign-out request succeeds.

                do {
                    try await signOutUseCase.execute()
                } catch {}
                send(.didLogined(false))
                sessionUseCase.execute(false)

@opficdev opficdev merged commit 266043f into develop Feb 25, 2026
1 check passed
@opficdev opficdev deleted the feat/#132-Persistence branch February 25, 2026 11:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

UserDefaults를 관리하는 객체를 Persistence 디렉토리 내에 구현한다

1 participant