You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
상세·하위 화면 9종이 재진입 시 미갱신 — load() 가 에러 재시도에만 결선 #703
2026-09-06 담당 범위별로 이슈와 PR을 분리했습니다. 이 이슈는 두 하위 작업을 함께 추적하며, 어느 한쪽 PR의 병합만으로 닫지 않습니다.
📍 Note (Optional)
설정 수신자 목록은 같은 계열이지만 #579 로 이미 등록되어 있어 이 이슈에서 제외했다.
전 앱 62개 화면 중 당겨서 새로고침이 있는 곳은 홈 탭·애프터노트 홈 2곳뿐이고, 재진입 갱신이 결선된 곳은 6곳뿐이다(2026-08-03 실측). 같은 계열을 담당별로 나눠 등록했다 — 애프터노트·수신자 흐름 #701, 마인드레코드 #702, 타임레터·설정 #703, 설정 수신자 목록 #579.
changed the title [-]fix(timeletter,setting): 상세·하위 화면 9종이 재진입 시 미갱신 — load() 가 에러 재시도에만 결선[/-][+]상세·하위 화면 9종이 재진입 시 미갱신 — load() 가 에러 재시도에만 결선[/+]on Aug 28, 2026
origin/develop7d87aa3f4 (2026-09-13) 기준으로 본문 실측표를 다시 쟀다. 결론은 이 이슈가 지금 순수 추적용이라는 것이고, 그래서 코드 대신 기록을 남긴다. 본문은 고치지 않았다. 아래가 정정분이다.
1. 9종 전부 미결선이 맞고, 표의 줄 번호는 밀렸다
재진입마다 서버 상태를 갱신하도록 결선된 것은 9종 중 0건이다. 타임레터 상세 3종은 여전히 에러 재시도 버튼에만 load() 가 걸려 있다. 결선 상태 자체는 본문 그대로 유효하고, 줄 번호만 어긋난다.
파일
본문 표
develop 7d87aa3f4
TimeLetterDetailScreen.kt
:76
:84
RecipientTimeletterScreen.kt
:86
:90
RecipientTimeLetterDetailScreen.kt
:76
:84
TimeletterScreen.kt (대조군)
:60-61
:72-74
SettingScreen.kt (대조군)
:69
:69 (그대로)
설정 4종 VM 은 init 1회 로드에 private 로드 함수뿐이라는 것도 그대로다. ConnectedAccountsViewModel.kt:29·:33, DeliveryConditionViewModel.kt:40·:44, ProfileEditViewModel.kt:27·:31, PushNotificationViewModel.kt:50·:62·:84.
하위 둘은 모두 열려 있다. #1920 OPEN(1hyok), #1921 OPEN(koongmai), PR #1930 OPEN·MERGEABLE(base handoff/708-setting-1hyok), PR #1905 OPEN·MERGEABLE(base develop, head f0cfec520). 열린 PR 62건의 본문에서 Closes 를 전수 검색해도 이 범위를 무는 것은 #1930(Closes #1920)과 #1905(Closes #1921) 둘뿐이다. #2034 는 Closes #579 로 별건이다. 두 PR 이 들어오기 전까지 여기서 낼 코드가 없다.
2. 「해야 할 일」 3번은 어느 하위 이슈도 물지 않는다
당겨서 새로고침 결정(3번)이 #1920 완료 조건에도 #1921 완료 조건에도 없다. 두 하위가 다 닫혀도 3번은 미결로 남는다.
다만 develop 실코드가 이 항목의 전제를 이미 약화시켰다.
임시저장은 복귀 경로 한정으로 이미 결선돼 있다. TimeLetterNavGraph.kt:97-110·:152-157 의 savedStateHandle 키 timeletter_draft_changed 로, 작성·수정 화면에서 목록으로 돌아오면 DraftLetterScreen.kt:52-57 이 loadDrafts() 를 부른다. 커밋 68ed54514 (2026-08-27), 본문 실측일 8월 3일 이후에 들어왔다. 본문 표의 「정의 있음, 화면 재진입 결선 없음」은 「복귀 경로 한정 결선 있음」으로 읽어야 한다.
수신자 목록은 명시적 refresh 함수가 없는 것은 맞지만 「재로드 진입점 없음」은 오해를 부른다. RecipientListViewModel.kt:20-27 이 SharingStarted.WhileSubscribed(5_000) 로 receiverListFlow 를 구독하고, UserReceiverRepositoryImpl.kt:62-77 의 그 flow 는 콜드라 새 구독마다 서버를 다시 조회한다(UserRepositoryImplTest.kt:151 의 「새 구독은 서버에서 목록을 다시 조회한다」가 고정). 화면이 collectAsStateWithLifecycle 이므로 5초 넘게 벗어났다 돌아오면 이미 자동 재조회된다. 남는 구멍은 5초 이내 재진입뿐이다.
여기에 #1905 가 두 화면 모두에 ON_RESUME refreshOnReturn() 을 얹는다(fix/703f0cfec520 기준 DraftLetterScreen.kt:68-70, RecipientListScreen.kt:58-60). 당겨서 새로고침까지 넣으면 같은 화면에 갱신 경로가 셋이 된다. 구독 재개와 resume 가 같은 조회를 두 번 보낸다는 지적은 #1905 의 RecipientListViewModel.kt:41 리뷰 스레드에 아직 열려 있다. 결정 자체는 타임레터 담당(koongmai) 몫으로 남긴다.
3. 설정 쪽에 표에 없는 10번째 화면이 있다
PushNotificationViewModel 에는 라우트가 둘 붙어 있다. SettingNavGraph.kt:103-108 의 NotificationRoute(NotificationSettingScreen)와 :110-114 의 PushNotificationRoute(PushNotificationScreen). 본문 표는 이 VM 을 화면 한 개로 셌고, #1920 은 대상에 PushNotificationScreen 만 적었다.
NotificationSettingScreen 은 develop(:85-87)에서도 #1930 HEAD(handoff/1920-setting-1hyok:90-91)에서도 ON_RESUME 에 기기 알림 권한(로컬값)만 보낸다. 정작 이 화면만 그리는 서버 값인 마케팅 수신 동의 sms·email·push 는 재진입에 갱신되지 않는다. DeviceAlarmOffSection 을 실제로 호출하는 곳은 NotificationSettingScreen.kt:163 하나뿐이고(PushNotificationScreen.kt:12 는 import 만 남아 있다), 그 값을 채우는 loadMarketingConsents() 는 develop :84, #1930 HEAD :206 모두 init 에서만 불린다. #1930 이 추가하는 refreshOnReturn()(HEAD :163-170)도 refreshDeviceAlarmStatus() 와 loadPushSettings() 만 부른다.
가드로는 드러나지 않는다. RefreshOnReturnWiringKonsistTest 는 refreshOnReturn 을 선언한 VM 에 결선 사이트가 최소 하나 있는지만 보고, KDoc :30-32 에서 스스로 「ON_RESUME 에서 정말 그 ViewModel 의 것을 부르는가」까지는 보지 않는다고 적어 두었다. PushNotificationScreen.kt:27 한 곳만 결선돼도 초록이다.
여기서 코드로 메우지 않는 이유. develop 의 PushNotificationViewModel 은 아직 MVI 가 아니라서(onIntent 없음, _uiState 직접 갱신) develop 위에서 고치면 #1967 → #1925 → #1930 스택이 들어오는 즉시 Intent 방식으로 다시 쓰게 되고, PushNotificationViewModel.kt 에서 #1930 과 충돌한다. 자리는 새 PR 이 아니라 #1930(이슈 #1920) 범위 확장이다.
4. Note 의 집계 정정
「재진입 갱신이 결선된 곳은 6곳뿐이다(2026-08-03 실측)」는 낡았다. 형제 이슈 #702(마인드레코드)가 CLOSED/COMPLETED 로 들어오면서 늘었다. develop 에서 다시 세면 이렇다.
refreshOnReturn() 을 선언한 ViewModel 12개, 그 ON_RESUME 결선 파일 12개. AppNavigation.kt:144-150, AfternoteDetailRoute.kt:160, ReceivedAfternoteDetailRoute.kt:45, ReceivedAfternoteNavHost.kt:80, ReceiverHomeEntry.kt:25, HomeTabMindRecordLazyItems.kt:93, ReceiverMindRecordScreen.kt:78, DailyQuestionAnswerListScreen.kt:60, DiaryScreen.kt:77, DraftListScreen.kt:88, WeeklyReportScreen.kt:55, SenderDetailScreen.kt:69.
다른 패턴 둘: SettingScreen.kt:69 의 refresh(), TimeletterScreen.kt:72-74 의 repeatOnLifecycle(STARTED) + load().
NotificationSettingScreen.kt:85-87 은 ON_RESUME 이 있으나 기기 알림 권한만 갱신하므로 서버 상태 갱신으로 세지 않는다.
즉 서버 상태를 재진입에 갱신하는 결선 파일은 14개다. *Screen.kt 파일만 세면 9개인데, 결선이 Route·NavHost·NavGraph·Entry 파일에도 있어서 화면 파일만 세면 실태를 못 잡는다. 「전 앱 62개 화면」도 세는 단위가 무엇이었는지 알 수 없어 확정 오류로 적지 않는다. 다시 잰다면 기준을 같이 적는 편이 낫다. presentation 모듈 main 소스셋의 *Screen.kt 파일은 70개다.
당겨서 새로고침이 2곳뿐이라는 것은 그대로 유효하다. HomeTabScreen.kt:139, AfternoteHomeScreen.kt:114.
한 가지 더. RefreshOnReturnWiringKonsistTest 는 #1930 이 새로 세우는 가드가 아니라 develop 에 이미 있는 가드다(8b9fd0131, 2026-08-31, #701 계열. 963bf304f#1725 로 공유 스코프 진입점을 쓰게 다듬었다). #1930 은 여기에 MVI 의 onIntent(XIntent.RefreshOnReturn) 결선까지 같은 계약으로 검사하도록 확장한다.
이 이슈는 09-06 에 담당별로 나눈 뒤 두 하위를 함께 추적하는 역할만 남아 있었다. 범위를 다 끝내서 닫는 것이 아니다. 추적을 하위 두 이슈로 옮기고 닫는다. 두 하위가 각자의 담당 큐에 서 있어 진행 상황은 하위 자체로 보인다. #928·#945 와 같은 처리다.
본문의 "어느 한쪽 PR의 병합만으로 닫지 않습니다", #1920 본문의 "이 이슈 완료만으로 상위 #703 전체를 닫지 않는다", 09-20 코멘트의 "#1920과 #1921의 실제 최종 소비 구현과 병합을 확인해야 하며"는 한쪽만 끝났을 때 전체를 완료로 처리하지 말라는 조건이다. 이 조건은 #1920 과 #1921 이 각자의 구현이 머지되어 닫히는 것으로 충족된다. 부모를 열어 둔다고 더 확인되는 것은 없다. #1920 본문의 그 줄도 이 처리에 맞춰 고쳤다.
옮긴 것과 예약하지 않은 것
09-13 코멘트 3번의 10번째 화면(NotificationSettingScreen 의 마케팅 수신 동의가 재진입에 갱신되지 않음)은 이 이슈 코멘트에만 있었다. fix(setting): 설정 하위 화면 4종의 재진입 갱신 (#703 분리) #1920 본문의 대상과 완료 조건에 옮겼다. develop f69332d 에서도 NotificationSettingScreen.kt:83 의 ON_RESUME 은 refreshDeviceAlarmStatus() 만 부르고, loadMarketingConsents() 는 PushNotificationViewModel.kt:53 의 init 에서만 불린다.
본문 "해야 할 일" 3번(목록 화면에 당겨서 새로고침을 둘지)은 기능 제공 여부라 PM 확인 대상이다. 어느 하위의 완료 조건으로도 옮기지 않았다. 제공하기로 결정되면 그때 최신 코드 기준으로 새 이슈를 등록한다.
Activity
[-]fix(timeletter,setting): 상세·하위 화면 9종이 재진입 시 미갱신 — load() 가 에러 재시도에만 결선[/-][+]상세·하위 화면 9종이 재진입 시 미갱신 — load() 가 에러 재시도에만 결선[/+]chore(timeletter): 설정 인수 변경을 분리하고 타임레터 범위만 남긴다 (#703)
1hyok commentedon Sep 13, 2026
실측 기록: 지금 여기서 뗄 코드 범위는 없고, 대신 남기는 네 가지
origin/develop7d87aa3f4(2026-09-13) 기준으로 본문 실측표를 다시 쟀다. 결론은 이 이슈가 지금 순수 추적용이라는 것이고, 그래서 코드 대신 기록을 남긴다. 본문은 고치지 않았다. 아래가 정정분이다.1. 9종 전부 미결선이 맞고, 표의 줄 번호는 밀렸다
재진입마다 서버 상태를 갱신하도록 결선된 것은 9종 중 0건이다. 타임레터 상세 3종은 여전히 에러 재시도 버튼에만
load()가 걸려 있다. 결선 상태 자체는 본문 그대로 유효하고, 줄 번호만 어긋난다.7d87aa3f4TimeLetterDetailScreen.ktRecipientTimeletterScreen.ktRecipientTimeLetterDetailScreen.ktTimeletterScreen.kt(대조군)SettingScreen.kt(대조군)설정 4종 VM 은 init 1회 로드에 private 로드 함수뿐이라는 것도 그대로다.
ConnectedAccountsViewModel.kt:29·:33,DeliveryConditionViewModel.kt:40·:44,ProfileEditViewModel.kt:27·:31,PushNotificationViewModel.kt:50·:62·:84.하위 둘은 모두 열려 있다. #1920 OPEN(
1hyok), #1921 OPEN(koongmai), PR #1930 OPEN·MERGEABLE(basehandoff/708-setting-1hyok), PR #1905 OPEN·MERGEABLE(basedevelop, headf0cfec520). 열린 PR 62건의 본문에서Closes를 전수 검색해도 이 범위를 무는 것은 #1930(Closes #1920)과 #1905(Closes #1921) 둘뿐이다. #2034 는Closes #579로 별건이다. 두 PR 이 들어오기 전까지 여기서 낼 코드가 없다.2. 「해야 할 일」 3번은 어느 하위 이슈도 물지 않는다
당겨서 새로고침 결정(3번)이 #1920 완료 조건에도 #1921 완료 조건에도 없다. 두 하위가 다 닫혀도 3번은 미결로 남는다.
다만 develop 실코드가 이 항목의 전제를 이미 약화시켰다.
TimeLetterNavGraph.kt:97-110·:152-157의savedStateHandle키timeletter_draft_changed로, 작성·수정 화면에서 목록으로 돌아오면DraftLetterScreen.kt:52-57이loadDrafts()를 부른다. 커밋68ed54514(2026-08-27), 본문 실측일 8월 3일 이후에 들어왔다. 본문 표의 「정의 있음, 화면 재진입 결선 없음」은 「복귀 경로 한정 결선 있음」으로 읽어야 한다.RecipientListViewModel.kt:20-27이SharingStarted.WhileSubscribed(5_000)로receiverListFlow를 구독하고,UserReceiverRepositoryImpl.kt:62-77의 그 flow 는 콜드라 새 구독마다 서버를 다시 조회한다(UserRepositoryImplTest.kt:151의 「새 구독은 서버에서 목록을 다시 조회한다」가 고정). 화면이collectAsStateWithLifecycle이므로 5초 넘게 벗어났다 돌아오면 이미 자동 재조회된다. 남는 구멍은 5초 이내 재진입뿐이다.여기에 #1905 가 두 화면 모두에 ON_RESUME
refreshOnReturn()을 얹는다(fix/703f0cfec520기준DraftLetterScreen.kt:68-70,RecipientListScreen.kt:58-60). 당겨서 새로고침까지 넣으면 같은 화면에 갱신 경로가 셋이 된다. 구독 재개와 resume 가 같은 조회를 두 번 보낸다는 지적은 #1905 의RecipientListViewModel.kt:41리뷰 스레드에 아직 열려 있다. 결정 자체는 타임레터 담당(koongmai) 몫으로 남긴다.3. 설정 쪽에 표에 없는 10번째 화면이 있다
PushNotificationViewModel에는 라우트가 둘 붙어 있다.SettingNavGraph.kt:103-108의NotificationRoute(NotificationSettingScreen)와:110-114의PushNotificationRoute(PushNotificationScreen). 본문 표는 이 VM 을 화면 한 개로 셌고, #1920 은 대상에PushNotificationScreen만 적었다.NotificationSettingScreen은 develop(:85-87)에서도 #1930 HEAD(handoff/1920-setting-1hyok:90-91)에서도 ON_RESUME 에 기기 알림 권한(로컬값)만 보낸다. 정작 이 화면만 그리는 서버 값인 마케팅 수신 동의 sms·email·push 는 재진입에 갱신되지 않는다.DeviceAlarmOffSection을 실제로 호출하는 곳은NotificationSettingScreen.kt:163하나뿐이고(PushNotificationScreen.kt:12는 import 만 남아 있다), 그 값을 채우는loadMarketingConsents()는 develop:84, #1930 HEAD:206모두 init 에서만 불린다. #1930 이 추가하는refreshOnReturn()(HEAD:163-170)도refreshDeviceAlarmStatus()와loadPushSettings()만 부른다.가드로는 드러나지 않는다.
RefreshOnReturnWiringKonsistTest는refreshOnReturn을 선언한 VM 에 결선 사이트가 최소 하나 있는지만 보고, KDoc:30-32에서 스스로 「ON_RESUME 에서 정말 그 ViewModel 의 것을 부르는가」까지는 보지 않는다고 적어 두었다.PushNotificationScreen.kt:27한 곳만 결선돼도 초록이다.여기서 코드로 메우지 않는 이유. develop 의
PushNotificationViewModel은 아직 MVI 가 아니라서(onIntent없음,_uiState직접 갱신) develop 위에서 고치면 #1967 → #1925 → #1930 스택이 들어오는 즉시 Intent 방식으로 다시 쓰게 되고,PushNotificationViewModel.kt에서 #1930 과 충돌한다. 자리는 새 PR 이 아니라 #1930(이슈 #1920) 범위 확장이다.4. Note 의 집계 정정
「재진입 갱신이 결선된 곳은 6곳뿐이다(2026-08-03 실측)」는 낡았다. 형제 이슈 #702(마인드레코드)가 CLOSED/COMPLETED 로 들어오면서 늘었다. develop 에서 다시 세면 이렇다.
refreshOnReturn()을 선언한 ViewModel 12개, 그 ON_RESUME 결선 파일 12개.AppNavigation.kt:144-150,AfternoteDetailRoute.kt:160,ReceivedAfternoteDetailRoute.kt:45,ReceivedAfternoteNavHost.kt:80,ReceiverHomeEntry.kt:25,HomeTabMindRecordLazyItems.kt:93,ReceiverMindRecordScreen.kt:78,DailyQuestionAnswerListScreen.kt:60,DiaryScreen.kt:77,DraftListScreen.kt:88,WeeklyReportScreen.kt:55,SenderDetailScreen.kt:69.SettingScreen.kt:69의refresh(),TimeletterScreen.kt:72-74의repeatOnLifecycle(STARTED)+load().NotificationSettingScreen.kt:85-87은 ON_RESUME 이 있으나 기기 알림 권한만 갱신하므로 서버 상태 갱신으로 세지 않는다.즉 서버 상태를 재진입에 갱신하는 결선 파일은 14개다.
*Screen.kt파일만 세면 9개인데, 결선이 Route·NavHost·NavGraph·Entry 파일에도 있어서 화면 파일만 세면 실태를 못 잡는다. 「전 앱 62개 화면」도 세는 단위가 무엇이었는지 알 수 없어 확정 오류로 적지 않는다. 다시 잰다면 기준을 같이 적는 편이 낫다. presentation 모듈 main 소스셋의*Screen.kt파일은 70개다.당겨서 새로고침이 2곳뿐이라는 것은 그대로 유효하다.
HomeTabScreen.kt:139,AfternoteHomeScreen.kt:114.한 가지 더.
RefreshOnReturnWiringKonsistTest는 #1930 이 새로 세우는 가드가 아니라 develop 에 이미 있는 가드다(8b9fd0131, 2026-08-31, #701 계열.963bf304f#1725 로 공유 스코프 진입점을 쓰게 다듬었다). #1930 은 여기에 MVI 의onIntent(XIntent.RefreshOnReturn)결선까지 같은 계약으로 검사하도록 확장한다.1hyok commentedon Sep 20, 2026
2026-09-20 하위 이슈·PR 상태를 다시 확인했습니다.
f0cfec520bb5665359c6a168c8cae603e4a04600입니다. 해당 작업을 이 이슈에서 중복 구현하지 않습니다.이 이슈에서 새로 분리해 구현할 잔여 화면은 없습니다. #1920과 #1921의 실제 최종 소비 구현과 병합을 확인해야 하며, 한쪽이 닫혔다는 이유로 전체 완료로 처리하지 않습니다. 목록의 당겨서 새로고침 제공 여부를 아직 확정된 추가 구현으로 간주하지 않습니다.
1hyok commentedon Sep 23, 2026
추적을 하위 이슈로 옮기고 닫는다 (2026-09-23)
이 이슈는 09-06 에 담당별로 나눈 뒤 두 하위를 함께 추적하는 역할만 남아 있었다. 범위를 다 끝내서 닫는 것이 아니다. 추적을 하위 두 이슈로 옮기고 닫는다. 두 하위가 각자의 담당 큐에 서 있어 진행 상황은 하위 자체로 보인다. #928·#945 와 같은 처리다.
"한쪽만으로 닫지 않는다"는 조건과의 관계
본문의 "어느 한쪽 PR의 병합만으로 닫지 않습니다", #1920 본문의 "이 이슈 완료만으로 상위 #703 전체를 닫지 않는다", 09-20 코멘트의 "#1920과 #1921의 실제 최종 소비 구현과 병합을 확인해야 하며"는 한쪽만 끝났을 때 전체를 완료로 처리하지 말라는 조건이다. 이 조건은 #1920 과 #1921 이 각자의 구현이 머지되어 닫히는 것으로 충족된다. 부모를 열어 둔다고 더 확인되는 것은 없다. #1920 본문의 그 줄도 이 처리에 맞춰 고쳤다.
옮긴 것과 예약하지 않은 것
NotificationSettingScreen.kt:83의 ON_RESUME 은refreshDeviceAlarmStatus()만 부르고,loadMarketingConsents()는PushNotificationViewModel.kt:53의 init 에서만 불린다.Refs #703은 그대로 둔다.