[SOU-646] FCM 인프라·APNs 설정#73
Conversation
📝 WalkthroughSummary by CodeRabbitRelease Notes
WalkthroughFirebase Cloud Messaging 푸시 알림 기능을 iOS 앱에 통합합니다. 새로운 FCM 프레임워크 모듈을 추가하고, 앱 초기화 시 APNs 등록 및 FCM 토큰 동기화를 구현하며, 필요한 빌드 설정과 Firebase 의존성을 구성합니다. ChangesFCM 푸시 알림 통합
Sequence Diagram(s)sequenceDiagram
participant App as App Launch
participant Registry as PushNotificationRegistrar
participant UNCenter as UNUserNotificationCenter
participant Delegate as AppDelegate
participant FCM as FCMManager
participant Store as FCMTokenStore
participant Syncer as PushTokenSyncer
App->>Registry: requestPermissionIfNeeded()
Registry->>UNCenter: requestAuthorization()
UNCenter-->>Registry: granted
Registry->>App: registerForRemoteNotifications()
App->>Delegate: didFinishLaunching()
Delegate->>FCM: configure()
FCM->>FCM: FirebaseApp.configure()
Delegate->>FCM: fcmTokenUpdates() → AsyncStream
FCM->>Store: registerStream()
Delegate->>Delegate: for await token in stream
Note over Delegate: 토큰 수신 시
Delegate->>Syncer: sync(fcmToken: token)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested labels
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
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. Comment |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 34fe225. Configure here.
34fe225 to
5f15292
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 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.
Inline comments:
In `@Projects/App/Sources/Push/PushNotificationRegistrar.swift`:
- Around line 22-28: When handling the result of requestAuthorization, you
currently return early inside the error branch after logging via
Logger.shared.error; update that branch to also set the same "push permission
requested" flag you set on success (e.g., the pushPermissionRequested /
hasRequestedPushPermissions UserDefaults flag or the existing setter used
elsewhere in PushNotificationRegistrar) before returning so the app records that
a request was attempted even when an error occurs; keep the Logger.shared.error
call, then persist the flag (using the same method/path used in the success
flow) and only then return.
In `@Projects/Core/FCM/Project.swift`:
- Around line 8-9: 현재 Project.swift에 전역으로
ENABLE_MODULE_VERIFIER/CLANG_ENABLE_MODULE_VERIFIER를 "NO"로 설정한 근거가 부족하므로 빌드를 재현해
Xcode/Tuist 빌드 로그에서 "module verifier" 또는 "module map"/"umbrella
header"/"DEFINES_MODULE" 관련 정확한 경고·에러 문자열을 캡처하세요; 로그 메시지가 모듈 맵(또는 DEFINES_MODULE
누락) 문제를 가리키면 Project.swift에서 전역 모듈 검증기 비활성화 대신 해당 타겟의 모듈 맵 또는 DEFINES_MODULE
속성(타겟 정의 코드에서 DEFINES_MODULE 설정 또는 custom modulemap 사용)을 수정하여 문제를 해결하고, 만약 로그가
실제로 모듈 검증기 자체 오류를 지목하면 영향을 받는 특정 타겟에만
ENABLE_MODULE_VERIFIER/CLANG_ENABLE_MODULE_VERIFIER을 끄도록 변경해 전역 설정을 제거하세요.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 0eb9e022-21f5-43bf-880c-422721346a4e
⛔ Files ignored due to path filters (1)
Config/Example.xcconfigis excluded by!Config/**
📒 Files selected for processing (24)
.codex/skills/souzip-pr/SKILL.md.gitignoreProjects/App/App-Debug.entitlementsProjects/App/App-Release.entitlementsProjects/App/Sources/AppDelegate.swiftProjects/App/Sources/Factory/AppFactory.swiftProjects/App/Sources/Push/PushNotificationRegistrar.swiftProjects/App/Sources/Push/PushTokenSyncer.swiftProjects/App/Sources/SceneDelegate.swiftProjects/Core/FCM/Project.swiftProjects/Core/FCM/Sources/FCMManager.swiftProjects/Core/FCM/Sources/FCMTokenProviding.swiftProjects/Core/FCM/Sources/FCMTokenStore.swiftProjects/Core/FCM/Sources/Factory/FCMFactory.swiftTuist/Package.resolvedTuist/Package.swiftTuist/ProjectDescriptionHelpers/Configuration/DefaultInfoPlist.swiftTuist/ProjectDescriptionHelpers/Configuration/DefaultSettings.swiftTuist/ProjectDescriptionHelpers/Core/Module.swiftTuist/ProjectDescriptionHelpers/Dependencies/ExternalLibrary.swiftTuist/ProjectDescriptionHelpers/Dependencies/ModuleDependencies.swiftTuist/ProjectDescriptionHelpers/Scripts/BuildScripts.swiftTuist/ProjectDescriptionHelpers/Templates/Project+App.swiftTuist/ProjectDescriptionHelpers/Templates/Project+Framework.swift
💤 Files with no reviewable changes (1)
- Tuist/ProjectDescriptionHelpers/Templates/Project+App.swift
| if let error { | ||
| Logger.shared.error( | ||
| "푸시 권한 요청 실패: \(error.localizedDescription)", | ||
| category: .general | ||
| ) | ||
| return | ||
| } |
There was a problem hiding this comment.
권한 요청 실패 시에도 플래그를 설정해야 합니다.
현재 requestAuthorization 호출이 에러를 반환하면(네트워크 문제 등) 플래그가 설정되지 않은 채로 early return되어, 다음번 앱 실행 시 사용자가 다시 권한 프롬프트를 보게 됩니다. 권한 요청 시도 자체를 기록하려면 에러 발생 시에도 플래그를 설정해야 합니다.
🛡️ 제안 수정
]) { granted, error in
if let error {
+ UserDefaults.standard.set(
+ true,
+ forKey: UserDefaultsKey.hasPresentedPushPermissionPrompt
+ )
Logger.shared.error(
"푸시 권한 요청 실패: \(error.localizedDescription)",
category: .general
)
return
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if let error { | |
| Logger.shared.error( | |
| "푸시 권한 요청 실패: \(error.localizedDescription)", | |
| category: .general | |
| ) | |
| return | |
| } | |
| if let error { | |
| UserDefaults.standard.set( | |
| true, | |
| forKey: UserDefaultsKey.hasPresentedPushPermissionPrompt | |
| ) | |
| Logger.shared.error( | |
| "푸시 권한 요청 실패: \(error.localizedDescription)", | |
| category: .general | |
| ) | |
| return | |
| } |
🤖 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 `@Projects/App/Sources/Push/PushNotificationRegistrar.swift` around lines 22 -
28, When handling the result of requestAuthorization, you currently return early
inside the error branch after logging via Logger.shared.error; update that
branch to also set the same "push permission requested" flag you set on success
(e.g., the pushPermissionRequested / hasRequestedPushPermissions UserDefaults
flag or the existing setter used elsewhere in PushNotificationRegistrar) before
returning so the app records that a request was attempted even when an error
occurs; keep the Logger.shared.error call, then persist the flag (using the same
method/path used in the success flow) and only then return.
| "ENABLE_MODULE_VERIFIER": "NO", | ||
| "CLANG_ENABLE_MODULE_VERIFIER": "NO", |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
Firebase iOS SDK 11.14.0 Tuist SPM integration module verifier settings requirements
💡 Result:
You asked about “Firebase iOS SDK 11.14.0 Tuist SPM integration module verifier settings requirements”. Here’s what can be asserted from current sources about (a) Firebase 11.14.0 and (b) the Tuist/SPM settings patterns relevant to module verification/module-map problems. 1) Firebase iOS SDK 11.14.0 context Firebase Apple SDK 11.14.0 (June 3, 2025) is a released version of the “Firebase Apple SDK” distribution [1]. Release notes indicate it’s available as version 11.14.0 [1], and the SDK version is tracked in the repo release/compare tooling for 11.14.0 [2][3]. 2) What “module verifier settings” means (Xcode) Apple’s guidance for the Apple Clang Module Verifier is to enable the “Enable Module Verifier” build setting (Build Settings -> Apple Clang Module Verifier) and ensure “Supported Languages”/“Supported Language Dialects” match your requirements [4]. This is general Xcode guidance for identifying framework module issues before distribution [4]. 3) Tuist + SPM + Firebase: the practical “requirements” that map to module-verifier failures In Tuist, the most relevant build-setting category for Firebase SPM integration problems is the handling of module maps and DEFINES_MODULE. 3.1 Tuist generates/adjusts DEFINES_MODULE when a module map exists Tuist’s PackageInfoMapper logic sets “DEFINES_MODULE=NO” when it decides there is a module map coming from a directory/header/custom module-map setup (specifically when moduleMap is present and moduleMap kind is directory/header/custom) [5]. This is precisely the kind of setting that can affect module-map/module-verifier correctness. 3.2 Known Firebase-in-SPM issues in Tuist are usually solved by adjusting DEFINES_MODULE for specific targets There are multiple Tuist issue reports where developers ran into “DEFINE_MODULE was set, but no umbrella header could be found to generate the module map”, and one workaround was to set “DEFINES_MODULE”: false for Firebase-related targets (e.g., “Firebase”, “FirebaseAnalytics…”, “FirebaseCoreExtension”, etc.) via Tuist dependency targetSettings [6]. 3.3 Tuist had to change module-map generation behavior for a Firebase case A Tuist PR (“Fix integration of latest Firebase”) describes a Firebase Remote Config scenario where Tuist/module-map generation logic caused a compilation failure because a Swift-only target had publicHeadersSearchPath set but no headers; the fix was to “don’t generate a modulemap when a publicHeadersDir exists but it has no headers” and to “skip setting the DEFINES_MODULE=NO in those cases, so the objc target can consume the bridging header automatically generated by Xcode” [7]. So, if your question is “what Tuist module verifier settings requirements exist for Firebase 11.14.0 when integrating via SPM?”, the sourced answer is that Tuist’s SPM integration uses/affects module-map behavior through settings like DEFINES_MODULE, and Firebase-specific edge cases can require Tuist to avoid generating module maps (or avoid setting DEFINES_MODULE=NO) when there are no headers, so the objc targets can consume the bridging header automatically generated by Xcode [7]. 4) What you should actually configure in Tuist (actionable, grounded) A) Ensure your Xcode module verifier build settings are set correctly (general) - In Xcode, set “Enable Module Verifier” to Yes, and set “Supported Languages” and “Supported Language Dialects” to match what you need [4]. B) If you hit module-map/module-verifier failures specifically with Firebase SPM via Tuist, start by checking Tuist’s targetSettings for DEFINES_MODULE - Tuist issue workaround evidence shows setting DEFINES_MODULE false for many Firebase-related SPM products/targets can suppress “DEFINE_MODULE was set…” module-map generation warnings [6]. - Tuist’s own code shows it may set DEFINES_MODULE=NO in the presence of certain module-map configurations [5], and Tuist fixed a Firebase integration failure by skipping module-map generation and skipping DEFINES_MODULE=NO in the specific “publicHeadersDir exists but has no headers” case [7]. 5) Firebase SPM integration requirements that are not “module verifier” but are commonly required Firebase’s installation methods doc for Swift Package Manager states “Google Analytics requires adding the -ObjC linker flag to your target's build settings if included transitively.” [8]. Separately, Tuist’s dependencies guide states Firebase has a “Requires -ObjC linker flag” requirement (in its Firebase special configurations section) [9]. Limitations / what I could not find in the sources I did not find a Firebase 11.14.0–specific, single canonical “Tuist module verifier settings requirements” document that enumerates exact Tuist settings to configure for 11.14.0 specifically. Instead, the sources describe (1) general Xcode module verifier build settings [4], and (2) Tuist/Firebase integration failures and fixes centered on module-map + DEFINES_MODULE behavior [7][6][5], which is the most direct “requirement” relationship to module verifier/module map issues. If you share your Tuist snippet (how you declare Firebase as.remote/.external, and whether you’re using Tuist’s swiftPackageManager dependency integration or XcodeProj-based integration) and the exact module verifier warning/error text, I can map it to the correct Tuist targetSettings adjustments consistent with the above evidence.
Citations:
- 1: https://firebase.google.cn/support/release-notes/ios
- 2: firebase/firebase-ios-sdk@11.13.0...11.14.0
- 3: https://newreleases.io/project/github/firebase/firebase-ios-sdk/release/11.14.0
- 4: https://developer.apple.com/documentation/xcode/identifying-and-addressing-framework-module-issues
- 5: https://github.com/tuist/tuist/blob/main/cli/Sources/TuistLoader/SwiftPackageManager/PackageInfoMapper.swift
- 6:
DEFINE_MODULE was setwarning occurs in xcode 15 tuist/tuist#5513 - 7: Fix integration of latest Firebase tuist/tuist#6104
- 8: https://firebase.google.com/docs/ios/installation-methods
- 9: https://tuist-tuist.mintlify.app/guides/dependencies
Firebase 모듈 검증기 비활성화(ENABLE_MODULE_VERIFIER/CLANG_ENABLE_MODULE_VERIFIER)가 정말 필요한지 로그 근거로 재확인 요청
- Firebase iOS SDK + Tuist/SPM 통합에서 일반적으로 문제가 되는 지점은 모듈 검증기 자체가 아니라 모듈 맵/
DEFINES_MODULE쪽인 경우가 많습니다(전역 모듈 검증기 비활성화가 필수라는 문서 근거는 확인되지 않음). Projects/Core/FCM/Project.swift(8-9)에서 해당 설정이 필요한지 빌드 로그의 “module verifier”/“module map(umbrella header 등)” 관련 정확한 경고·에러 문구로 확인하고, 가능하면 원인에 맞춰 타겟별로 모듈 맵/DEFINES_MODULE를 조정하는 방향을 우선 검토해주세요.
🤖 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 `@Projects/Core/FCM/Project.swift` around lines 8 - 9, 현재 Project.swift에 전역으로
ENABLE_MODULE_VERIFIER/CLANG_ENABLE_MODULE_VERIFIER를 "NO"로 설정한 근거가 부족하므로 빌드를 재현해
Xcode/Tuist 빌드 로그에서 "module verifier" 또는 "module map"/"umbrella
header"/"DEFINES_MODULE" 관련 정확한 경고·에러 문자열을 캡처하세요; 로그 메시지가 모듈 맵(또는 DEFINES_MODULE
누락) 문제를 가리키면 Project.swift에서 전역 모듈 검증기 비활성화 대신 해당 타겟의 모듈 맵 또는 DEFINES_MODULE
속성(타겟 정의 코드에서 DEFINES_MODULE 설정 또는 custom modulemap 사용)을 수정하여 문제를 해결하고, 만약 로그가
실제로 모듈 검증기 자체 오류를 지목하면 영향을 받는 특정 타겟에만
ENABLE_MODULE_VERIFIER/CLANG_ENABLE_MODULE_VERIFIER을 끄도록 변경해 전역 설정을 제거하세요.

📌 변경 요약
Story
fcm-infrastructure(SOU-646): Firebase SDK·Push 설정·CoreFCM모듈·App 부트스트랩을 연결해 실기기에서 FCM 토큰을 확인할 수 있는 인프라까지 구축합니다.서버 토큰 API·푸시 수신·알림 UI는 후행 Story 범위입니다.
📌 변경 내용
1. Tuist · Core
FCM모듈FirebaseCore,FirebaseMessaging)Projects/Core/FCM/—FCMManager,FCMTokenStore,FCMTokenProviding,FCMFactoryOTHER_SWIFT_FLAGS $(inherited),frameworkConfigurations등)2. Push 빌드 설정
aps-environment: development / production)GoogleService-Info-Debug/Releaseplist 빌드 시 번들 복사UIBackgroundModes: remote-notificationGoogleService-Info*.plistgitignore3. App 부트스트랩
AppDelegate: Firebaseconfigure, APNs 콜백, FCM 토큰AsyncStream관찰PushNotificationRegistrar: 권한 요청·설정에서 허용 후 APNs 재등록SceneDelegate: 권한 요청·sceneDidBecomeActive동기화DeferredPushTokenSyncer: Story 2 서버 API 연동 placeholderAppFactory.fcmTokenProvider— 후행 Story 주입 지점Note
Medium Risk
Touches app launch, push entitlements, and Firebase config; misconfigured plists or APNs env would block tokens, but no server or notification handling yet.
Overview
Adds Firebase Cloud Messaging infrastructure so the app can obtain FCM tokens on real devices; server registration, inbound push handling, and notification UI are explicitly out of scope.
A new Core
FCMmodule wrapsFirebaseCore/FirebaseMessaging(FCMManager, actor-backedFCMTokenStore,AsyncStreamtoken updates). The App layer bootstraps Firebase inAppDelegate, forwards APNs device tokens, and observes token updates viaDeferredPushTokenSyncer(logs only until a backend API exists).PushNotificationRegistrarrequests notification permission once, registers for remote notifications, and re-syncs when the app becomes active after the user enables push in Settings.Tuist / build: Firebase iOS SDK via SPM; App depends on the FCM module (no direct Firebase imports in App). Debug vs Release entitlements (
aps-environmentdevelopment/production),remote-notificationbackground mode, pre-build copy of per-flavorGoogleService-Infoplists fromConfig/(gitignored), plus static-SPM build fixes (OTHER_SWIFT_FLAGS,frameworkConfigurations, module verifier off for FCM).Reviewed by Cursor Bugbot for commit 34fe225. Configure here.