Skip to content

feat: 도서 검색 실패 기능 개발#267

Merged
doyeonk429 merged 13 commits intodevelopfrom
BOOK-476-feature/#265
Jan 28, 2026
Merged

feat: 도서 검색 실패 기능 개발#267
doyeonk429 merged 13 commits intodevelopfrom
BOOK-476-feature/#265

Conversation

@doyeonk429
Copy link
Member

@doyeonk429 doyeonk429 commented Jan 25, 2026

🔗 관련 이슈

📘 작업 유형

  • ✨ Feature (기능 추가)
  • 🐞 Bugfix (버그 수정)
  • 🔧 Refactor (코드 리팩토링)
  • ⚙️ Chore (환경 설정)
  • 📝 Docs (문서 작성 및 수정)
  • ✅ Test (기능 테스트)
  • 🎨 style (코드 스타일 수정)

📙 작업 내역

  • 검색 결과가 없을 때 사용자가 카카오톡 채널을 통해 도서 등록 요청을 할 수 있는 기능을 추가합니다.
  1. 외부 링크 처리 시스템 구축 (Clean Architecture)

    • ExternalLinkRepository: 외부 URL/앱 스킴 실행 가능 여부 확인 및 실행 인터페이스
    • DefaultExternalLinkRepository: UIApplication 기반 구현체
    • OpenExternalLinkUseCase: 앱 스킴 우선 실행 → 실패 시 웹 URL 폴백 로직
  2. 카카오톡 채널 연동

    • URLConstants: 카카오톡 앱 스킴(kakaoplus://) 및 웹 URL 관리
    • Info.plist에 KAKAO_ACCOUNT 환경 변수 추가
    • SearchCoordinator.showRequestPage(): 외부 링크 실행 처리
  3. 검색 화면 UI 개선

    • 검색 결과 없음 시 EmptyStateView 표시
    • 게스트: "로그인하기" 버튼 → 로그인 화면 이동
    • 회원: "문의하기" 버튼 → 카카오톡 채널 채팅 이동
  4. EmptyStateView 재사용성 개선

    • setContent(title:description:actionTitle:) 메서드 추가
    • 기존 onTapLogin → onTapActionButton으로 범용

🧪 테스트 내역

  • 브라우저/기기에서 동작 확인 -> 카카오톡 설치되어있는 실 기기에서 테스트 진행완료
  • 엣지 케이스 테스트 완료
  • 기존 기능 영향 없음

🎨 스크린샷 또는 시연 영상 (선택)

기능 미리보기 기능 미리보기
검색결과X(로그인) 검색결과X(게스트)
  • 시뮬레이터(카카오톡 미설치) -> Web URL 오픈
Simulator.Screen.Recording.-.iPhone.16.Pro.Max.-.2026-01-24.at.17.51.24.mp4
  • 실기기(카카오톡 설치O) -> 카카오톡 앱 오픈
ScreenRecording_01-26-2026.10-01-25_1.mov

✅ PR 체크리스트

  • 커밋 메시지가 명확합니다
  • PR 제목이 컨벤션에 맞습니다
  • 관련 이슈 번호를 작성했습니다
  • 기능이 정상적으로 작동합니다
  • 불필요한 코드를 제거했습니다

💬 추가 설명 or 리뷰 포인트 (선택)

  • ⭐ .xcconfig 업데이트 반드시 진행해야합니다!!! ⭐ (노션 보안문서 참고부탁드려요)

Summary by CodeRabbit

  • 새로운 기능

    • 외부 링크를 앱 스킴으로 우선 열고 실패 시 웹으로 폴백하는 외부 링크 열기 기능 추가
    • 빈 상태 화면에 제목·설명·액션 버튼을 지정할 수 있는 맞춤형 콘텐츠 추가
    • 카카오 채팅/앱 연동용 URL 상수와 요청 페이지로 이동하는 연결 기능 통합
  • 개선 사항

    • 검색 화면의 빈 결과 처리 향상(맞춤 메시지·버튼 노출 및 전면 표시)
    • 게스트/로그인 상태에 따른 빈 상태 행동 및 요청 페이지 이동 흐름 추가

✏️ Tip: You can customize this high-level summary in your review settings.

@doyeonk429 doyeonk429 self-assigned this Jan 25, 2026
@coderabbitai
Copy link

coderabbitai bot commented Jan 25, 2026

Walkthrough

외부 링크 열기 기능(리포지토리·유스케이스) 추가, 검색 화면에 범용 EmptyStateView 통합 및 버튼 액션 연결, Kakao 관련 URL 상수 및 Info.plist 키 추가, DI 등록과 코디네이터에서의 호출 흐름을 구현함.

Changes

코호트 / 파일(s) 변경 요약
외부 링크 리포지토리
src/Projects/BKDomain/Sources/Interface/Repository/ExternalLinkRepository.swift, src/Projects/BKData/Sources/Repository/DefaultExternalLinkRepository.swift, src/Projects/BKData/Sources/DataAssembly.swift
ExternalLinkRepository 프로토콜(c​anOpen, open) 추가. DefaultExternalLinkRepository 구현 추가(UIApplication 사용, Combine 퍼블리셔 반환). DI 컨테이너에 등록 추가.
외부 링크 유스케이스
src/Projects/BKDomain/Sources/Interface/Usecase/OpenExternalLinkUseCase.swift, src/Projects/BKDomain/Sources/UseCase/DefaultOpenExternalLinkUseCase.swift, src/Projects/BKDomain/Sources/DomainAssembly.swift
OpenExternalLinkUseCase 프로토콜 및 DefaultOpenExternalLinkUseCase 구현 추가. appScheme 우선 시도 후 URL 폴백 로직. DI 등록 추가.
검색 화면 통합
src/Projects/BKPresentation/Sources/MainFlow/Search/View/SearchView.swift, src/Projects/BKPresentation/Sources/MainFlow/Search/View/SearchViewController.swift, src/Projects/BKPresentation/Sources/MainFlow/Search/Coordinator/SearchCoordinator.swift, src/Projects/BKPresentation/Sources/MainFlow/Search/ViewModel/SearchViewModel.swift
SearchView에 범용 EmptyStateView 추가 및 레이아웃·보임 처리, 버튼 탭으로 로그인 또는 요청 페이지 이동 이벤트 연결. ViewController에 goToLogin/goToRequestPage 이벤트 추가, ViewModel에 requestPageTapped 액션 추가. 코디네이터에 UseCase 주입 및 showRequestPage() 추가(Combine 구독 관리).
EmptyStateView 일반화
src/Projects/BKPresentation/Sources/ArchiveFlow/View/EmptyStateView.swift, src/Projects/BKPresentation/Sources/ArchiveFlow/View/ArchiveView.swift
콜백/버튼명 변경(onTapLoginonTapActionButton, loginButtonactionButton), 커스텀 콘텐츠 지원(setContent), UI 업데이트 메서드명 변경(applyupdateUI(for:)) 및 탭 핸들러 리네이밍.
상수 및 설정
src/Projects/BKPresentation/Sources/Constant/URLConstants.swift, src/SupportingFiles/Booket/Info.plist, src/Workspace.swift
Kakao 계정 기반 kakaoAppScheme·kakaoChatURL 상수 추가, Info.plist에 KAKAO_ACCOUNT 키 추가, 워크스페이스 파일 헤더 연도 업데이트(2025→2026).

Sequence Diagram(s)

sequenceDiagram
    participant SearchView as "SearchView"
    participant SearchVC as "SearchViewController"
    participant Coordinator as "SearchCoordinator"
    participant UseCase as "OpenExternalLinkUseCase"
    participant Repo as "ExternalLinkRepository"
    participant App as "UIApplication"

    SearchView->>SearchVC: onTapActionButton
    SearchVC->>Coordinator: showRequestPage()
    Coordinator->>UseCase: execute(urlString, appScheme)
    alt appScheme 사용 가능
        UseCase->>Repo: canOpen(appScheme)
        Repo->>App: canOpenURL(appScheme)
        App-->>Repo: Bool
        Repo-->>UseCase: Bool
        opt canOpen 성공
            UseCase->>Repo: open(appScheme)
        end
    else appScheme 미사용/불가
        UseCase->>Repo: open(urlString)
    end
    Repo->>App: open URL (main thread)
    App-->>Repo: Bool(success)
    Repo-->>Coordinator: AnyPublisher<Bool, Never> (결과)
    Coordinator->>Coordinator: 결과 로깅 / 후속 처리
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 3 | ❌ 2
❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning Workspace.swift의 저작권 연도 업데이트는 범위를 벗어난 변경입니다. 나머지 모든 변경사항은 검색 실패 기능과 외부 링크 처리에 직접 관련되어 있습니다. Workspace.swift의 저작권 연도 변경(2025→2026)을 별도의 PR로 분리하거나, 이 변경이 필요한 이유를 설명하는 커밋 메시지를 추가하세요.
Docstring Coverage ⚠️ Warning Docstring coverage is 4.35% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목 'feat: 도서 검색 실패 기능 개발'은 검색 실패 시 사용자가 도서 등록을 요청할 수 있도록 하는 기능 추가를 명확하게 설명하며, PR의 주요 변경사항과 완벽하게 일치합니다.
Linked Issues check ✅ Passed PR이 링크된 이슈 #265의 모든 주요 코딩 요구사항을 충족합니다: 검색 실패 UI 개발(EmptyStateView), 외부 링크 네비게이션(ExternalLinkRepository/OpenExternalLinkUseCase), 게스트/인증 흐름 지원(SearchViewController 이벤트 처리).

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

✨ 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 BOOK-476-feature/#265

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.

@doyeonk429 doyeonk429 marked this pull request as ready for review January 26, 2026 01:12
@github-actions github-actions bot requested a review from clxxrlove January 26, 2026 01:12
@doyeonk429
Copy link
Member Author

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Jan 26, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/Projects/BKPresentation/Sources/MainFlow/Search/View/SearchView.swift (1)

108-134: 검색 결과가 생긴 뒤 빈 상태가 계속 남을 수 있습니다.

한 번 빈 상태가 노출된 뒤 결과가 생기면 emptyView를 숨기지 않아 화면을 덮을 가능성이 있습니다. 결과가 있는 분기에서 빈 상태를 명시적으로 숨겨 주세요.

🛠️ 수정 제안
-            } else {
-                collectionView.isHidden = false
+            } else {
+                updateEmptyState(isHidden: true)
                 collectionView.backgroundView = nil
                 snapshot.appendSections([.result])
                 // Book과 BookInfo 모두 처리
                 snapshot.appendItems(state.books.map { .result($0) }, toSection: .result)
                 snapshot.appendItems(state.bookInfos.map { .libraryResult($0) }, toSection: .result)
                 searchBar.setClearButtonMode(.always)
             }
🤖 Fix all issues with AI agents
In `@src/Projects/BKPresentation/Sources/Constant/URLConstants.swift`:
- Around line 10-15: The kakaoAccount initializer only checks for nil but not
empty or placeholder build-time tokens, so update the closure used by private
static let kakaoAccount to validate the loaded string from
bundle.object(forInfoDictionaryKey: "KAKAO_ACCOUNT") as? String: ensure the
value is non-empty after trimming whitespace and does not contain common
placeholder patterns (e.g., startsWith "$(" or contains "$(" or equals the
literal "$(KAKAO_ACCOUNT)"); if validation fails, call fatalError with a clear
message mentioning kakaoAccount and the invalid value to fail fast and avoid
constructing bad URLs.
🧹 Nitpick comments (1)
src/Projects/BKPresentation/Sources/MainFlow/Search/View/SearchViewController.swift (1)

75-90: print 대신 통일된 로깅 사용을 권장합니다.

프로덕션 로그 정책과 일관성을 위해 Log.debug로 통일하는 편이 좋습니다.

🔧 제안 변경
-                print("LOG: 게스트 모드 - 로그인 화면으로 이동")
+                Log.debug("게스트 모드 - 로그인 화면으로 이동", logger: AppLogger.viewModel)

Copy link
Member

@clxxrlove clxxrlove 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

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

🤖 Fix all issues with AI agents
In `@src/Projects/BKPresentation/Sources/MainFlow/Search/View/SearchView.swift`:
- Around line 122-134: In the .result(let state) non-empty branch ensure the
empty state is hidden so results aren't obscured: call
updateEmptyState(isHidden: true, ...) or set emptyView.isHidden = true inside
the else branch (where collectionView.isHidden = false) — update the logic
around the .result case (referencing the .result pattern, updateEmptyState and
emptyView/collectionView) so that when state.books or state.bookInfos are
non-empty the empty view is explicitly hidden.

@doyeonk429 doyeonk429 merged commit 5476099 into develop Jan 28, 2026
3 checks passed
@doyeonk429 doyeonk429 deleted the BOOK-476-feature/#265 branch January 28, 2026 23:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BOOK-476/feat] 도서 검색 실패 UI 개발

2 participants