Repository navigation
feat(platform): 알림 목적지 이동을 앱 루트에 결선한다 — #1727 에서 Nav3 재작성분 분리 #1795
Copy link
Copy link
Open
Labels
area:platformCI·빌드·릴리스·저장소 운영 영역CI·빌드·릴리스·저장소 운영 영역enhancementNew feature or requestNew feature or request
Description
작업 유형
enhancement — 신규 기능·기존 기능 개선
주 담당 모듈
platform — Android 앱·CI·빌드·릴리스·저장소 운영
개요
#1727 (PR #1641) 이 세우는 알림 목적지 이동에서 Navigation 3 이관 때 다시 쓰는 앱 루트 결선 을 분리해 받는다 — AppNavigation.kt 의 호출부 8줄(0903 분리)에 더해, 0904 에 NotificationEntryEffect 컴포저블 본체도 PR 에서 걷어 여기로 옮겼다(본체가 AppState.navigateToBottomBarRoute 에 묶여 있어 미참조로 남겨 둘 이유가 없다).
이 결선은 앱 루트 NavHost 에 붙는데, #1702 가 그 루트를 NavDisplay 로 교체하며 startDestination 개념 자체를 없앤다.
범위
| 대상 | Nav2 였다면 | Nav3 에서 |
|---|---|---|
| 결선 위치 | AppNavigation.kt 의 NavHost 옆 NotificationEntryEffect(...) |
NavDisplay 를 소유하는 앱 셸 |
| 인증 관문 판정 | isSignedIn = startDestination == Route.Home |
startDestination 이 없다 — 백스택 시드 또는 인증 상태를 직접 읽어야 한다 |
| 목적지 이동 | appState.navigateToBottomBarRoute(...) (내부가 popUpTo·saveState·restoreState) |
탭별 로컬 스택 전환 계약 |
| 큐 소비 효과 | NotificationEntryEffect(appState, isSignedIn) — Activity 의 MainViewModel.pendingNotificationEntry 를 LaunchedEffect(identityKey, isSignedIn) 로 읽어 이동 뒤 consumeNotificationEntry |
같은 큐를 앱 셸이 소비 — 이동 프리미티브만 Nav3 계약으로 |
NotificationDestination.toRoute() 매핑, 인텐트 수신, PendingIntent 빌더 통합은 엔진 무관이라 #1727 에 남는다 — #1111 본문도 「어떤 Navigation 을 쓰든 필요한 인프라」 로 적어 두었다.
보존해야 할 동작
- 로그아웃 상태에서 알림을 타면 목적지로 가지 않는다 — 인증 관문을 건너뛰지 않는다.
- 로그인 상태면 지정 목적지 탭으로 이동하고, 미지정·해석 실패는 홈으로 떨어진다.
- 같은 알림을 두 번 처리하지 않는다.
보존해야 할 판단 (PR #1641 본문에서 옮김)
- 로그아웃 상태에서는 소비하지 않고 큐에 남긴다. Nav2 에선
startDestination == Route.Home이 «로그인 확정» 그 자체였다. 로그아웃이면 온보딩이고, 그때 목적지로 보내면 알림이 인증 관문을 건너뛰는 통로가 된다. 남겨 두면 로그인이 확정되는 순간 효과가 다시 돌아 그 목적지로 이어진다. - 이동은 바텀바 탭을 누른 것과 같은 백스택 규약을 재사용한다. 목적지가 전부 바텀바 최상위라 별도 이동 규칙을 만들면 같은 화면 조합에 두 벌의 백스택 동작이 생긴다.
MainActivity는 손대지 않는다. 효과가 Activity 와 같은ViewModelStoreOwner에서hiltViewModel()로 같은MainViewModel인스턴스를 받는다(NotificationPermissionEffect와 같은 방식). 파라미터로 내려보내면onXxx = {}no-op 디폴트가 필요해지고 그건NoOpCallbackDefaultKonsistTest가 막는다(refactor(platform): 컴포저블 no-op 콜백 디폴트 — 재발 가드·컨벤션 도입 + afternote 잔여 2건 #1388).
완료 조건
- 알림 탭이 지정 목적지 화면으로 이동한다.
- 위 보존 동작 3건이 계측 테스트로 검증된다.
- Nav2 개념 (
startDestination·NavHost결선) 에 의존하지 않는다. - fix(platform): 알림 목적지를 계약값으로 실어 진입 큐까지 전달한다 — 내부 목적지 축·홈 폴백, 이동 결선은 #1795 (#1111 분리) #1727 이 남긴 미참조 프로덕션 선언이 해소되어
ProductionVisibilityKonsistTestbaseline 에서 빠진다.
의존 관계
- blocked_by refactor(platform): 앱 루트를 Navigation 3 NavDisplay로 전환 #1702 — 앱 루트가
NavDisplay로 바뀐 뒤 결선한다.
자식 이슈
없음
참고
- 분리 원본: fix(platform): 알림 목적지를 계약값으로 실어 진입 큐까지 전달한다 — 내부 목적지 축·홈 폴백, 이동 결선은 #1795 (#1111 분리) #1727 · 알림 탭이 목적지로 갈 수 없는 구조 — MainActivity onNewIntent 부재, PendingIntent 빌더 2벌 중복 #1111 · PR fix(app,core): 알림 목적지를 계약값으로 실어 진입 큐까지 전달한다 (#1727) #1641
- 이관 소유: refactor(platform): 앱 루트를 Navigation 3 NavDisplay로 전환 #1702 (루트) · 소관 그래프 refactor(platform): 소관 그래프를 Navigation 3 로컬 스택으로 이관 #1698
- 엔진 중립 목적지 계약: feat(platform): App Links URI 계약·인텐트 수신·인증 후 목적지 재개 #924
- 같은 방식으로 분리된 건: feat(onboarding): 비밀번호 찾기 3화면을 온보딩 그래프에 배선한다 — #457 에서 Nav3 재작성분 분리 #1789 · 임시저장 이어쓰기·버튼 배선 제안 철회 #1791 · 임시저장 목록·진입·이어쓰기·저장 후 흐름을 PM에게 확인한다 #1792 · 작성 중 수신자 등록 진입·복귀·선택 흐름을 PM에게 확인한다 #1793 · feat(afternote): 수신자 복수 선택 반환 채널을 배선한다 — #1426 에서 Nav3 재작성분 분리 #1794
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
area:platformCI·빌드·릴리스·저장소 운영 영역CI·빌드·릴리스·저장소 운영 영역enhancementNew feature or requestNew feature or request
Activity
refactor(platform): 알림 목적지 이동의 앱 루트 결선을 떼어 Nav3 전환 뒤로 미룬다 (#1795)
refactor(app): 알림 진입 효과를 걷어 Nav3 루트 결선(#1795)으로 넘긴다 (#1727)
OnlyReadOneBook commentedon Sep 7, 2026
PR #1641의 최신 Repository Quality 검사에서 NotificationDestination.toRoute()는 프로덕션 소비자가 없고 매핑 테스트만 호출하는 것으로 확인됐습니다. 사용자 요청에 따라 해당 함수/파일과 NotificationDestinationRouteTest 3건, Konsist의 해당 예외를 #1641에서 제거합니다.
이 이슈(#1795)에서 Nav3 앱 셸의 실제 알림 소비 경로를 연결할 때 목적지 계약값(home/mind_record/time_letter/afternote)을 실제 탭으로 변환하는 구현과 동작 검증을 함께 추가해 주세요. 로그아웃 시 큐 보존, 로그인 후 지정 탭 이동/홈 폴백, 이동 후 occurrence 단회 소비가 검증 범위입니다. #1641에는 목적지 vocabulary, PendingIntent extra 전달, Intent 파싱/폴백, source+occurrence identity 계약이 그대로 남습니다. 테스트만을 위한 프로덕션 선언이나 예외 라벨은 추가하지 않습니다.
OnlyReadOneBook commentedon Sep 13, 2026
develop 실측으로 본문을 고치는 기록
origin/develop7d87aa3 (0913) 기준으로 본문을 재확인했다. 코드 PR 은 0줄이다. 본문이 적어 둔 범위가 0908 에 한 번 더 움직였고, 완료 조건 하나는 가리키는 대상이 사라졌다. 본문만 믿고 착수하면 없는 파일을 찾고 없는 baseline 줄을 지우려 하게 된다.지금 develop 에 이미 있는 것
#1727 이 남긴 부분은 그대로 서 있다. 목적지 계약값 4종(
core/common/.../notification/NotificationDestination.kt,home·mind_record·time_letter·afternote),MainActivity.kt:96의 인텐트 파싱 후enqueueNotificationEntry호출,MainViewModel.kt의 큐(:49enqueue ·:28pendingNotificationEntry ·:60consumeNotificationEntry), 그리고NotificationNavigationAndroidTest.kt의 수신 계측 4건.없는 것은 소비 쪽 전부다. 큐를 읽어 이동시키는 코드와, 목적지를 탭으로 옮기는 매핑이 둘 다 develop 에 없다.
1. 분리는 2건이 아니라 3건이다
본문이 적은 두 건 뒤에 한 건이 더 있다.
fd60e6aa1AppNavigation.kt결선 8줄ea7d65d13NotificationEntryEffect.kt본체 42줄f282cfc91NotificationDestinationRoute.kt24줄,NotificationDestinationRouteTest.kt37줄, 그리고ea7d65d13이 막 올렸던 Konsist baseline 항목 3줄세 번째 건은 0907 코멘트가 예고한 제거가 실제로 착지한 것이다. 그 코멘트는 예고였고 여기는 착지 실측이라 커밋과 줄 수를 남긴다.
2. 본문의 "toRoute 매핑은 #1727 에 남는다" 는 develop 에서 거짓이다
git grep toRoute -- app/src/main이 0건이고 파일 자체가 없다. 이 이슈의 범위는 효과 본체뿐 아니라 toRoute 매핑과 그 테스트 3건(목적지 4종이 서로 다른 Route 로 간다, Route 가 바텀바 최상위 안에 있다, 폴백은 홈이다)까지 다시 만드는 것으로 늘었다.복원 원본은 지워지기 직전 커밋에 그대로 있다.
이 매핑을 지금 미리 넣는 것은 안 된다. 0908 에 "프로덕션 소비자가 없다" 는 이유로 지운 코드라 소비자인 루트 결선 없이 다시 넣으면 같은 상태로 돌아가고,
.github/scripts/validate-test-only-production-declarations.mjs(#1895) 가 PR 이 src/main 에 새로 넣은 미참조 선언을 잡아 떨어뜨린다. 결선과 같은 PR 에서 함께 올려야 한다.3. 완료 조건 4 는 이미 무효다
"#1727 이 남긴 미참조 프로덕션 선언이 해소되어
ProductionVisibilityKonsistTestbaseline 에서 빠진다" 는 뺄 줄이 없다.konsist/src/test/kotlin/com/afternote/konsist/ProductionVisibilityKonsistTest.kt:380의INTENTIONAL_PRODUCTION_CONTRACTS에 이 이슈로 미룬 항목은 0건이다. 선언을 baseline 에 올려 둔 게 아니라f282cfc91이 선언을 통째로 지웠기 때문이다.4. 대신 완료 조건 4 를 이 자리로 다시 쓴다
실제로 남은 미참조 선언은 어느 게이트에도 안 걸리는 곳에 있다.
app/src/main/java/com/afternote/afternote_fe/MainViewModel.kt:28의pendingNotificationEntry와:60의consumeNotificationEntry가 main 소비자 0건이다.MainActivity.kt:96은enqueueNotificationEntry만 부르고, 나머지 참조는MainViewModelNotificationTest와NotificationColdStartAndroidTest뿐이다.이게 안 잡히는 이유는 두 게이트의 사각이 겹쳐서다.
ProductionVisibilityKonsistTest는 최상위 선언만 보고(.github/workflows/repository-quality.yml:229의 주석이 같은 사각을 적어 둔다), #1895 가드는 PR 이 새로 추가한 선언만 본다. 이미 들어와 있는 멤버 선언은 둘 다 지나간다.따라서 완료 조건 4 는 "이 둘에 main 소비자가 생긴다" 로 읽는 편이 맞다. 결선이 붙으면 자연히 충족된다.
5. 완료 조건 2 의 앵커
보존 동작 3건을 검증할 자리는 이미 현행 동작 단언으로 박혀 있다.
app/src/androidTest/java/com/afternote/afternote_fe/NotificationNavigationAndroidTest.kt:139-140은 로그인 warm 진입에서 타임레터 탭에 머무는 것을,:165-166은 background 진입에서 홈 탭에 머무는 것을 단언한다. 둘 다 이 이슈 번호를 적은 주석이 위에 붙어 있다.결선 때 이 두 단언을 목적지 탭 단언으로 뒤집는다. 뒷건은 테스트 이름도
backgroundNotification_resumesSameActivityAndKeepsCurrentScreen에서 이동 단언으로 되돌려야 한다. 앞건 이름은warmNotificationWhileLoggedIn_isReceivedWithoutRecreatingActivity라 그대로 둬도 된다.6. 블로커 체인 실측
blocked_by 인 #1702 는 오늘 기준 선행 4건 중 #1698 만 CLOSED 다. #1695 OPEN(1hyok), #1696 OPEN(koongmai), #1697 OPEN(Sadturtleman, 다시 #959 에 막혀 있다). 남은 셋 중 둘이 내 모듈 밖이라 #1702 는 임박하지 않았다. 이 이슈는 당분간 대기가 맞다.