Skip to content

[Fix] #867 - 콕찌르기 온보딩 노출 시 기존 유저를 체크하도록 변경#869

Open
kwonseokki wants to merge 4 commits into
developfrom
fix/#867-poke-onboarding-check
Open

[Fix] #867 - 콕찌르기 온보딩 노출 시 기존 유저를 체크하도록 변경#869
kwonseokki wants to merge 4 commits into
developfrom
fix/#867-poke-onboarding-check

Conversation

@kwonseokki
Copy link
Copy Markdown
Contributor

🌴 PR 요약

메인뷰 진입 여부를 체크하고나서 결과값에 따라서 poke/isNew 를 호출해서 더블체크 하도록 수정했습니다.

🌱 작업한 브랜치

🌱 PR Point

DefaultPokeMainUseCase 에서 isVisitedPokeMainView 값을 체크하고 결과값에 따라서 추가적으로 PokeMainRepository에 getIsNewUser 메서드를 추가적으로 호출하여 기존 사용자에게 온보딩 화면이 나타나지 않도록 수정했습니다.

    public func getIsNewUser() {
    #warning("TODO: 온보딩 노출조건 변경으로 기존 유저들을 위해서 임시로 추가 추후 getIsNewUser 체크 로직 제거 필요")
        Just(UserDefaultKeyList.User.isVisitedPokeMainView ?? false)
            .flatMap { [weak self] isVisited in
                guard let self = self else { return Just(false).eraseToAnyPublisher() }
                
                if isVisited {
                    return Just(false)
                        .eraseToAnyPublisher()
                } else {
                    return repository.getIsNewUser()
                        .replaceError(with: false)
                        .eraseToAnyPublisher()
                }
            }
            .sink { [weak self] isNewUser in
                self?.isNewUser.send(isNewUser)
            }.store(in: self.cancelBag)
    }

📌 참고 사항

📸 스크린샷

기능 스크린샷
기능이름 스크린샷 첨부

📮 관련 이슈

@kwonseokki kwonseokki requested review from juri123123 and yungu0010 May 5, 2026 13:07
@kwonseokki kwonseokki self-assigned this May 5, 2026
@kwonseokki kwonseokki added Fix 문제 해결, 코드 수정 석기🍙 labels May 5, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 5, 2026

Review Change Stack
No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f46c41f9-a4e0-4a72-91a4-41462ac8733e

📥 Commits

Reviewing files that changed from the base of the PR and between 1674748 and de08010.

📒 Files selected for processing (2)
  • SOPT-iOS/Projects/Domain/Sources/UseCase/PokeMainUseCase.swift
  • SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeMainScene/ViewModel/PokeMainViewModel.swift
🚧 Files skipped from review as they are similar to previous changes (1)
  • SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeMainScene/ViewModel/PokeMainViewModel.swift

Summary by CodeRabbit

  • Refactor
    • 온보딩 감지 로직이 개선되어 앱이 새 사용자 여부를 외부 조회로 확인하고, 필요 시 온보딩을 정확하게 표시합니다.
    • 뷰 로드 시 온보딩 판단 흐름이 중앙에서 관리되어 온보딩 호출이 일관되게 처리됩니다.
    • 기존 방문 이력 확인과 외부 확인을 결합해 온보딩 필요 여부 판단의 신뢰성이 향상되었습니다.

Walkthrough

저장소에 getIsNewUser() 퍼블리셔를 추가하고, 유스케이스는 방문 기록을 우선 확인해 필요 시 저장소에서 신규 여부를 조회해 isNewUser로 발행하며, 뷰모델은 해당 퍼블리셔를 구독해 온보딩을 트리거하도록 변경합니다.

Changes

콕찌르기 온보딩 흐름

Layer / File(s) Summary
저장소 인터페이스 및 구현
SOPT-iOS/Projects/Domain/Sources/RepositoryInterface/PokeMainRepositoryInterface.swift, SOPT-iOS/Projects/Data/Sources/Repository/PokeMainRepository.swift
getIsNewUser() 프로토콜 메서드 추가 및 PokeMainRepository가 pokeService.isNewUser()isNew 값을 Bool 퍼블리셔로 반환하도록 구현.
유스케이스 퍼블리셔와 검사 로직
SOPT-iOS/Projects/Domain/Sources/UseCase/PokeMainUseCase.swift
PokeMainUseCaseisNewUser: PassthroughSubject<Bool, Never> 추가 및 checkPokeOnboardingNeeded() 구현: UserDefaults에서 방문 여부 확인 후 미방문이면 repository.getIsNewUser() 호출, 에러는 false로 매핑하여 발행.
뷰모델 바인딩/트리거 변경
SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeMainScene/ViewModel/PokeMainViewModel.swift
viewDidLoad에서 useCase.checkPokeOnboardingNeeded() 호출로 온보딩 판정 위임, useCase.isNewUser를 구독하여 onPokeOnboardingNeeded 호출로 전달.

Sequence Diagram

sequenceDiagram
  actor User
  participant ViewModel as PokeMainViewModel
  participant UseCase as DefaultPokeMainUseCase
  participant Repo as PokeMainRepository
  participant Service as PokeService
  participant UserDef as UserDefaults

  User->>ViewModel: viewDidLoad
  ViewModel->>UseCase: checkPokeOnboardingNeeded()
  UseCase->>UserDef: isVisitedPokeMainView 확인
  alt 이미 방문
    UserDef-->>UseCase: true
    UseCase->>UseCase: isNewUser에 false 발행
  else 미방문
    UserDef-->>UseCase: false
    UseCase->>Repo: getIsNewUser()
    Repo->>Service: isNewUser()
    Service-->>Repo: isNew 응답
    Repo-->>UseCase: Bool 퍼블리셔 반환
    UseCase->>UseCase: 결과를 isNewUser로 발행
  end
  UseCase-->>ViewModel: isNewUser 이벤트
  ViewModel->>User: onPokeOnboardingNeeded 콜백 실행
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 분

Possibly related PRs

  • sopt-makers/SOPT-iOS#862: 동일한 온보딩/신규 사용자 결정 코드 경로를 수정하며 getIsNewUser() 사용을 둘러싼 변경과 충돌 가능성 있음.
  • sopt-makers/SOPT-iOS#846: 유사한 온보딩 흐름을 구현하지만 use case에서의 퍼블리셔 처리 방식이 다름; 동일 파일들을 수정함.

Suggested reviewers

  • juri123123
  • yungu0010

개요

콕찌르기 온보딩 로직을 저장소-유스케이스-뷰모델 계층에 걸쳐 리팩토링하여, 사용자가 이전에 방문했는지 여부를 퍼블리셔 기반으로 관리합니다.

변경사항

신규 사용자 조회 플로우

계층 / 파일 요약
저장소 인터페이스
SOPT-iOS/Projects/Domain/Sources/RepositoryInterface/PokeMainRepositoryInterface.swift
getIsNewUser() 프로토콜 메서드 추가: AnyPublisher<Bool, any Error> 반환
저장소 구현
SOPT-iOS/Projects/Data/Sources/Repository/PokeMainRepository.swift
pokeService.isNewUser()의 결과를 isNew 속성으로 매핑하여 반환
유스케이스 인터페이스
SOPT-iOS/Projects/Domain/Sources/UseCase/PokeMainUseCase.swift (프로토콜)
isNewUser PassthroughSubject<Bool, Never> 퍼블리셔 및 checkPokeOnboardingNeeded() 메서드 선언
유스케이스 구현
SOPT-iOS/Projects/Domain/Sources/UseCase/PokeMainUseCase.swift (DefaultPokeMainUseCase)
UserDefaults에서 방문 이력 확인; 이미 방문했으면 false 즉시 발행, 미방문이면 저장소 호출; 에러는 false로 매핑 후 isNewUser로 전달
뷰모델 통합
SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeMainScene/ViewModel/PokeMainViewModel.swift
transform에서 viewDidLoaduseCase.checkPokeOnboardingNeeded() 호출; bindOutput에서 useCase.isNewUser 구독하여 onPokeOnboardingNeeded 콜백 실행

시퀀스 다이어그램

sequenceDiagram
    actor User
    participant ViewModel as PokeMainViewModel
    participant UseCase as DefaultPokeMainUseCase
    participant Repo as PokeMainRepository
    participant Service as PokeService
    participant UserDef as UserDefaults

    User->>ViewModel: viewDidLoad 발생
    ViewModel->>UseCase: checkPokeOnboardingNeeded() 호출
    UseCase->>UserDef: isVisitedPokeMainView 확인
    alt 이미 방문
        UserDef-->>UseCase: true
        UseCase->>UseCase: false 즉시 발행
    else 미방문
        UserDef-->>UseCase: false
        UseCase->>Repo: getIsNewUser() 호출
        Repo->>Service: isNewUser() 호출
        Service-->>Repo: isNew 반환
        Repo-->>UseCase: Bool 퍼블리셔 반환
        UseCase->>UseCase: 결과를 isNewUser로 발행
    end
    UseCase-->>ViewModel: isNewUser 퍼블리셔 업데이트
    ViewModel->>User: onPokeOnboardingNeeded 콜백 실행
Loading

예상 코드 리뷰 난이도

🎯 3 (Moderate) | ⏱️ ~20 분

관련 PR

  • sopt-makers/SOPT-iOS#846: 동일한 코드 경로(PokeMainRepository/PokeMainRepositoryInterface의 getIsNewUser 추가 및 PokeMainViewModel/유스케이스에 통합)를 수정합니다.
  • sopt-makers/SOPT-iOS#862: 콕찌르기 온보딩/신규 사용자 플로우 및 동일한 저장소/유스케이스/뷰모델 인터페이스를 다룹니다.

제안 리뷰어

  • juri123123
  • yungu0010

시 🐰

온보딩의 길을 정돈하고 ✨
신규 사용자 여부를 다시 묻네
저장소에서 유스케이스로
뷰모델까지 흘러가는 데이터
기존 사용자는 이젠 평온하리 🌙

🚥 Pre-merge checks | ✅ 4 | ❌ 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 (4 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목은 변경 사항의 핵심인 '콕찌르기 온보딩 노출 시 기존 유저 체크' 기능을 명확하게 요약하고 있습니다.
Description check ✅ Passed PR 설명은 isVisitedPokeMainView 체크 후 getIsNewUser를 추가 호출하는 변경사항을 상세히 설명하고 있습니다.
Linked Issues check ✅ Passed PR의 코드 변경사항(isVisitedPokeMainView 체크 후 repository.getIsNewUser() 호출)이 #867의 목표인 '기존 사용자에게 온보딩 미노출'을 충족합니다.
Out of Scope Changes check ✅ Passed 모든 변경사항이 #867의 기존 유저 온보딩 체크 관련 목표에 직접 연관되어 있으며 범위 내에 있습니다.

✏️ 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 fix/#867-poke-onboarding-check

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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.

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.

🧹 Nitpick comments (1)
SOPT-iOS/Projects/Domain/Sources/UseCase/PokeMainUseCase.swift (1)

97-97: 💤 Low value

#warning 이슈 트래킹 필요

#warning 코멘트가 명시하듯, isVisitedPokeMainView 기반 단락 로직은 임시 조치이며 추후 제거가 필요합니다. 별도 이슈로 추적하지 않으면 코드에 그대로 남을 가능성이 있습니다.

해당 항목을 추적할 GitHub 이슈를 생성해 드릴까요?

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@SOPT-iOS/Projects/Domain/Sources/UseCase/PokeMainUseCase.swift` at line 97,
The inline `#warning` in PokeMainUseCase.swift flags a temporary workaround around
isVisitedPokeMainView vs getIsNewUser that must be tracked; create a GitHub
issue describing the temporary on-boarding workaround and planned removal, then
replace the `#warning` with a concise TODO comment that includes the created issue
number (and optionally a short action: e.g., "remove isVisitedPokeMainView
fallback and restore getIsNewUser logic"); reference the affected symbols
isVisitedPokeMainView and getIsNewUser in the issue and TODO so reviewers can
locate and remove the temporary logic later.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@SOPT-iOS/Projects/Domain/Sources/UseCase/PokeMainUseCase.swift`:
- Line 97: The inline `#warning` in PokeMainUseCase.swift flags a temporary
workaround around isVisitedPokeMainView vs getIsNewUser that must be tracked;
create a GitHub issue describing the temporary on-boarding workaround and
planned removal, then replace the `#warning` with a concise TODO comment that
includes the created issue number (and optionally a short action: e.g., "remove
isVisitedPokeMainView fallback and restore getIsNewUser logic"); reference the
affected symbols isVisitedPokeMainView and getIsNewUser in the issue and TODO so
reviewers can locate and remove the temporary logic later.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 53fb9c52-4b0d-47c7-a40e-90ba9211b87f

📥 Commits

Reviewing files that changed from the base of the PR and between 0c5b85d and 1674748.

📒 Files selected for processing (4)
  • SOPT-iOS/Projects/Data/Sources/Repository/PokeMainRepository.swift
  • SOPT-iOS/Projects/Domain/Sources/RepositoryInterface/PokeMainRepositoryInterface.swift
  • SOPT-iOS/Projects/Domain/Sources/UseCase/PokeMainUseCase.swift
  • SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeMainScene/ViewModel/PokeMainViewModel.swift

Copy link
Copy Markdown
Member

@yungu0010 yungu0010 left a comment

Choose a reason for hiding this comment

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

고생하셨습니다👍👍👍👍 리뷰 한 번 확인해주세요~!

더불어 isVisitedPokeMainView = true 저장 위치를 Repository로 옮기는 것을 제안드립니다.

isVisitedPokeMainView는 "온보딩을 노출해야하는가"를 판단하는 플래그인데, getIsNewUser()를 호출하는 순간 온보딩 노출 여부가 결정되기 때문에 Repository 계층에서 유저디폴트 설정을 하는 것이 더 적합한 것 같습니다.

또한 현재 API 호출 에러가 발생하면 false를 반환하여 OnboardingVC가 생성되지 않아 true 설정이 누락될 위험성이 있어보여요. 한 번 고려해주세요.

추가로 Poke와 Stamp 모듈에서는 withUnretained가 잘 사용되지 않고 있는데 withUnretained이 컨벤션이기도 하고 코드도 간결해져서 사용하면 좋을 것 같습니다!

func getFriend() -> AnyPublisher<[PokeUserModel], Error>
func getFriendRandomUser(randomType: String, size: Int) -> AnyPublisher<PokeFriendRandomUserModel, Error>
func getFriendRandomUser(randomType: String, size: Int) -> AnyPublisher<PokeFriendRandomUserModel, Error>
func getIsNewUser() -> AnyPublisher<Bool, any Error>
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

기존 Error 타입도 any로 맞추면 좋을 것 같습니다! 추후 Swif6로 마이그레이션 할 때 같이 붙여보아요 . .

}.store(in: self.cancelBag)
}

public func getIsNewUser() {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

해당 메소드의 퍼블리셔 반환값이 온보딩 노출 여부인만큼 checkPokeOnboardingNeeded라는 메소드명은 어떠신가요?

Comment on lines +98 to +110
Just(UserDefaultKeyList.User.isVisitedPokeMainView ?? false)
.flatMap { [weak self] isVisited in
guard let self = self else { return Just(false).eraseToAnyPublisher() }

if isVisited {
return Just(false)
.eraseToAnyPublisher()
} else {
return repository.getIsNewUser()
.replaceError(with: false)
.eraseToAnyPublisher()
}
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
Just(UserDefaultKeyList.User.isVisitedPokeMainView ?? false)
.flatMap { [weak self] isVisited in
guard let self = self else { return Just(false).eraseToAnyPublisher() }
if isVisited {
return Just(false)
.eraseToAnyPublisher()
} else {
return repository.getIsNewUser()
.replaceError(with: false)
.eraseToAnyPublisher()
}
}
Just(UserDefaultKeyList.User.isVisitedPokeMainView ?? false)
.withUnretained(self)
.flatMap { owner, isVisited in
if isVisited {
return Just(false)
.eraseToAnyPublisher()
} else {
return repository.getIsNewUser()
.replaceError(with: false)
.eraseToAnyPublisher()
}

withUnretained를 쓰면 프로젝트 컨벤션에도 맞고 코드도 훨씬 간결해질 것 같습니다!

.eraseToAnyPublisher()
}
}
.sink { [weak self] isNewUser in
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

여기도 withUnretained로 맞춰주세요!

@kwonseokki
Copy link
Copy Markdown
Contributor Author

고생하셨습니다👍👍👍👍 리뷰 한 번 확인해주세요~!

더불어 isVisitedPokeMainView = true 저장 위치를 Repository로 옮기는 것을 제안드립니다.

isVisitedPokeMainView는 "온보딩을 노출해야하는가"를 판단하는 플래그인데, getIsNewUser()를 호출하는 순간 온보딩 노출 여부가 결정되기 때문에 Repository 계층에서 유저디폴트 설정을 하는 것이 더 적합한 것 같습니다.

또한 현재 API 호출 에러가 발생하면 false를 반환하여 OnboardingVC가 생성되지 않아 true 설정이 누락될 위험성이 있어보여요. 한 번 고려해주세요.

추가로 Poke와 Stamp 모듈에서는 withUnretained가 잘 사용되지 않고 있는데 withUnretained이 컨벤션이기도 하고 코드도 간결해져서 사용하면 좋을 것 같습니다!

getIsNewUser() 메서드에서 온보딩 노출 여부를 결정하는 게 아닌 단순히 노출 여부를 확인하는 용도이고 실제로는 사용자가 직접 온보딩뷰를 이탈하여 메인뷰에 진입했을때 플래그를 변경하는 것으로 이해를 했습니다. 그래서 OnboardingVC의 viewDidDisappear 에서 플래그를 변경하도록 했는데 이러한 경우에도 Repository에서 변경을 하도록 수정이 필요할까요?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Fix 문제 해결, 코드 수정 석기🍙

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Fix] 기존 콕찌르기 사용자에게 온보딩이 나타나는 오류

2 participants