feat: #42 알림 설정 화면 + 도리 등록 알림 권한 안내#46
Conversation
Debug/Release 환경 변수 분리, BuildEnvironment 도입, APS entitlements 추가. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
앱 진입점에서 FCM 토큰 등록 및 APNs 위임 연결. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
QA용 FCMPushTestEndpoint 추가. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
QA용 FCM 푸시 테스트 화면과 UITests 타겟 자산 추가. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
알림 설정 조회/변경에 필요한 Endpoint 및 Response 모델을 정의한다. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- 알림 설정 조회/토글 액션을 서버 API와 연결하고 실패 시 토글을 롤백한다. - 시스템 알림 권한이 꺼져 있을 때 안내 배너를 노출하고, 탭 시 시스템 설정으로 진입한다. - scenePhase 활성화 시 권한 상태를 재조회해 자동 갱신한다. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
도리 등록 성공 후 시스템 알림 권한이 꺼져 있으면 설정 유도 알럿을 노출하고, 탭 시 시스템 설정으로 진입한다. 알럿 타이틀 멀티라인 정렬을 위해 DoriCommonAlert의 title 정렬도 함께 조정했다. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
기존 FCMPushTestFeature를 마이페이지 네비게이션에 연결하고, 필요한 Core 의존성을 MyPage 모듈에 추가한다. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
CFBundleDisplayName을 APP_DISPLAY_NAME 변수로 분리하여 Debug는 'Dori-Debug', Release는 '도리'로 표시되도록 한다. PRODUCT_NAME은 ASCII로 유지해 .app 번들 파일명을 보존한다. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
kangddong
left a comment
There was a problem hiding this comment.
리뷰 남겼습니다. 푸시/알림 설정 쪽은 실제 사용자에게 바로 영향이 갈 수 있는 부분이라 머지 전에 수정이 필요해 보입니다. 추가로 git diff --check origin/develop...HEAD에서 trailing whitespace와 EOF blank line 경고가 확인됐습니다. tuist generate --no-open은 clean worktree 기준으로는 설정/의존성 주입 상태를 별도로 맞춰야 하므로, CI/신규 체크아웃 기준의 설정 파일 주입 방식도 같이 확인해주세요.
| _ application: UIApplication, | ||
| didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil | ||
| ) -> Bool { | ||
| FCMService.shared.configure() |
There was a problem hiding this comment.
FirebaseApp.configure()가 런치 시 무조건 실행되는데, GoogleService-Info.plist는 PR 트리에 없고 .gitignore에 추가되어 있습니다. 로컬에는 ignored 파일이 있어서 통과해도 fresh clone/CI/TestFlight 환경에서는 번들에 설정 파일이 없을 수 있고, 그 경우 앱 시작 단계에서 Firebase 초기화가 실패합니다. 환경별 plist를 빌드 단계에서 명시적으로 주입하거나, 누락 시 fail-fast 되는 스크립트/설정을 같이 넣는 게 필요합니다.
| FCMService.shared.tokenRefreshHandler = { token in | ||
| try? tokenStore.saveFCMToken(token) | ||
| let endpoint = RegisterFCMTokenEndpoint(token: token) | ||
| _ = try? await networkService.request( |
There was a problem hiding this comment.
FCM 토큰 등록 실패를 try?로 버리고 있어서 로그인 전 토큰이 먼저 발급되면 서버 등록 실패 후 재시도 경로가 없습니다. 실제로 권한 요청은 앱 시작 .task에서 실행되고, 인증 토큰 저장은 로그인 성공 후라 순서가 쉽게 어긋날 수 있습니다. 저장된 FCM 토큰을 로그인 성공/앱 인증 완료 시점에 다시 업로드하거나, 인증 실패 케이스를 재시도 큐로 남겨야 푸시 미수신 사용자가 생기지 않습니다.
| state.isLoading = false | ||
| for setting in settings { | ||
| applySetting(typeCode: setting.typeCode, enabled: setting.enabled, state: &state) | ||
| } |
There was a problem hiding this comment.
서버에서 받아온 개별 알림 설정은 반영하지만 isAllPushEnabled는 갱신하지 않아 기본값 false로 남습니다. 그러면 서버상 알림이 켜져 있어도 화면은 '알림이 꺼져 있어요' 상태로 보이고, 하위 설정 영역이 overlay로 비활성처럼 덮입니다. settingsLoaded에서 전체 스위치를 서버 응답 기반으로 계산하거나, 서버가 전체 push type을 내려주도록 모델링해야 합니다.
|
|
||
| case .allPushToggled(let value): | ||
| // TODO: OS 시스템 알림 설정과 연동 (UNUserNotificationCenter / 시스템 설정 화면 이동) | ||
| state.isAllPushEnabled = value |
There was a problem hiding this comment.
전체 푸시 토글은 로컬 상태만 바꾸고 서버 업데이트를 하지 않습니다. 사용자가 '앱 알림 받기'를 켜거나 꺼도 다음 진입 시 서버 값으로 돌아가거나, 현재 화면의 하위 토글 상태와 서버 상태가 불일치할 수 있습니다. 전체 토글이 제품 요구사항이라면 관련 typeCode들을 일괄 업데이트하고 실패 시 롤백해야 하고, 단순 UI 잠금용이면 서버 상태에서 파생되는 read-only 값으로 두는 편이 안전합니다.
| DoriModules.core.module.projectDependency, | ||
| .external(.composableArchitecture) | ||
| ], | ||
| entitlements: .file(path: "Resources/DoriApp.entitlements") |
There was a problem hiding this comment.
앱 타겟이 항상 Resources/DoriApp.entitlements를 사용하고, 해당 파일의 aps-environment가 development로 고정되어 있습니다. Release/App Store 배포에서는 production APNs entitlement가 필요하므로 배포 서명 실패나 푸시 환경 불일치가 날 수 있습니다. Debug/Release 별 entitlements를 분리하거나 빌드 설정으로 aps-environment를 맞춰주세요.
CI(Xcode 26.3 / Swift 6.2.4)에서 commonDictionary 리터럴 초기화 중 Dictionary literal contains duplicate keys 트랩이 발생하여, 빈 딕셔너리에 항목을 하나씩 할당하는 방식으로 우회한다. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- InfoPlist commonDictionary 리터럴에 UISupportedInterfaceOrientations 복원 (Xcode 26.3에서 dictionary literal 중복 키 트랩이 발생하던 형태) - build.yml Xcode 버전을 latest-stable → 26.2 로 명시 고정 Xcode 버전 차이가 원인이었는지 CI에서 확인하기 위한 임시 커밋이며, 검증 후 롤백/재정리 예정. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
가설 검증 결과 Xcode 26.2 고정 시 CI 통과 확인됨. 운영 정책상 Xcode latest-stable을 유지하되, dictionary literal 트랩을 회피하기 위한 baseInfoPlist mutation 방식 코드는 유지한다. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
dictionary literal 트랩 가설 재검증을 위해 CI가 실패하던 시점의 InfoPlist 형태(commonDictionary literal에 UISupportedInterfaceOrientations 포함)로 되돌린다. build.yml은 latest-stable 유지. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
About this PR
⚓ Related Issue
🥥 Contents
1. 알림 설정 API 엔드포인트/응답 모델 추가
FetchNotificationSettings,UpdateNotificationSetting) 및 Response 모델을 정의2. 알림 설정 화면 서버 연동 및 기기 알림 배너 추가
scenePhase활성화 시 권한 상태를 재조회해 자동 갱신3. 도리 등록 후 시스템 알림 권한 안내 알럿
4. 마이페이지 FCM 푸시 테스트 진입점 연결
FCMPushTestFeature를 마이페이지 네비게이션에 연결5. 릴리스 빌드 앱 표시명 한국어 처리
CFBundleDisplayName을APP_DISPLAY_NAME변수로 분리Dori-Debug, Release:도리로 홈 화면 표시PRODUCT_NAME은 ASCII 유지로.app번들 파일명 보존📸 Screenshot
Other information 🔥
UNUserNotificationCenter를 사용. AddDori는UserNotificationSettingsClient로 분리되어 있고, MyPage에서는 모듈 간 의존을 피하기 위해 인라인 호출. 추후 Core로 끌어올려 공유하는 게 깔끔할 것 같습니다.🤖 Generated with Claude Code