Repository navigation
서버 실패가 무음·빈 정상 화면으로 수렴 — 목록·상세·에디터 복구 수단 부재 #705
Copy link
Copy link
Labels
Description
📜 Overview (Required)
애프터노트 발신 흐름의 서버 실패·무응답이 화면별로 무음 실패, 복구 불가, 빈 정상 상태로 수렴한다.
1. 목록 새로고침 실패가 무음이다
- 기존 목록이 있는 상태에서 Paging refresh가 실패하면 표시만 사라지고 기존 목록만 남는다.
AfternoteHomeScreen은itemCount > 0이면LoadState.Error를 사용자에게 전달하지 않는다.AfternotePagingSource의 실패가ErrorReporter에도 기록되지 않는다.
2. 발신 상세 조회 실패에 재시도가 없다
DetailLoadErrorContent는 뒤로가기만 제공한다.AfternoteDetailViewModel의 재조회 진입점과 화면 배선이 없다.
3. 수정 prefill 조회 실패가 빈 정상 에디터로 보인다
loadExistingAfternoteForEdit실패 시isPrefillLoading=false만 설정한다.- 오류 상태·재시도·저장 차단 없이 빈 작성 폼이 노출돼 기존 기록을 덮어쓸 수 있다.
4. 저장·곡 검색 진행 상태가 화면에 전달되지 않는다
- ViewModel의
isSaving이 Screen에 전달되지 않아 요청 중에도 유휴 상태처럼 보인다. AddSongViewModel.isLoading도 검색 화면에서 소비하지 않는다.
5. 추모 영상 썸네일 업로드 실패가 저장을 막지 않는다
2026-08-24 추가. #938 작업 중 발견.
uploadMemorialThumbnail실패 시thumbnailUploadFailed=true만 세우고, 화면은 스낵바 1회 만 띄운다. 저장 버튼은 그대로 눌린다.- 저장되면 BE 가
MemorialVideo(videoUrl, null)로 객체 통째 교체하므로 썸네일 없는 영상이 확정된다. 수신자 화면은ReceiverMemorialVideoThumbnail에서AsyncImage를 건너뛰고 회색 그라디언트 + 재생 아이콘만 그린다 — 깨지진 않지만 시안에 정의된 상태가 아니다(시안은 썸네일 위추모 영상/2분 34초오버레이가 전제 — 추억 노트 상세 시안 결손 — 하단 고지·영상 재생·오버레이·타이틀 개행 #463 3번 항목). - 복구 경로가 없다. 썸네일만 재시도하는 수단이 없고,
withMemorialVideo가 영상 교체 시 썸네일을 리셋하므로 영상을 처음부터 다시 골라야 썸네일이 생긴다. - 3번(prefill 실패)과 같은 계열이다 — 실패를 오류 상태로 유지하지 않고 저장으로 흘려보낸다. 애프터노트는 사후 전달이라 잘못 확정된 결과를 되돌릴 기회가 제한적이다.
처방 선택지 (착수 시 결정)
- (a) 썸네일 재시도 액션 노출 — 영상 재선택 없이 추출·업로드만 다시. 영상 업로드 성공분을 버리지 않아 손실이 가장 적다
- (b) 저장 시 확인 다이얼로그 — "썸네일 없이 저장하면 수신자에게 회색 카드로 보입니다"
- (c) 저장 차단 — 3번과 같은 처방이지만, 영상 업로드까지 성공한 상태를 버리게 되므로 단독으로는 과하다
✅ 시안 확인 완료 (2026-08-24) — 시안에 정의된 상태는 두 가지뿐이다.
- 영상 있음 (2667:14467 · 2667:15440) — 썸네일이 채워지고 중앙 재생 버튼 + 좌하단
추모 영상/2분 34초오버레이 - 영상 없음 (2672:16029) — 빈 카드에
+아이콘만 (첨부 유도)
"영상은 있는데 썸네일만 없는" 제3의 상태는 시안에 없다. 현재 코드가 만들어 내는 화면(회색 그라디언트 + 재생 아이콘, 썸네일 없음)은 1번도 2번도 아닌 어중간한 상태 — 영상이 있다고 주장하면서 미리보기를 못 보여준다. 따라서 (a) 재시도로 그 상태 자체를 만들지 않는 쪽이 맞다. (b)는 시안에 없는 상태를 사용자 동의로 확정하게 만들어 차선이다.
필요한 동작
- 기존 목록과 함께 refresh 실패를 알리고 재시도를 제공한다.
- 발신 상세 Error 화면에 재조회 액션을 연결한다.
- prefill 실패를 빈 폼으로 전환하지 말고 오류·재시도 상태로 유지하며 저장을 막는다.
- 저장·곡 검색의 진행 상태를 화면에 전달한다.
- 목록
LoadState.Error를 기록하되 반복 retry의 중복 계측을 억제한다. - 썸네일 업로드 실패를 스낵바 1회로 끝내지 말고, 재시도 수단을 주거나 저장 전에 확인을 받는다.
📌 Child Issue(Optional)
No response
📍 Note (Optional)
- 성공 후 재진입 갱신은 상세·수신 흐름 6개 화면이 재진입 시 미갱신 — 수정 후 복귀해도 옛 값 표시 #701, 필수값 검증 안내는 #624와 별개다.
- 실패 안내의 최종 UI 방식은 #446과 정렬한다.
- 5번의 계측은 이미
ErrorReporter(MEMORIAL_THUMBNAIL_UPLOAD)에 붙어 있어 refactor(core,afternote): ErrorReporter 채택 — Logcat 에만 남는 실패 16곳 분류 #962 범위와 겹치지 않는다 — 여기서 다루는 건 사용자 동작(차단·재시도)이다.
Reactions are currently unavailable
Activity
1hyok commentedon Aug 3, 2026
developd313c06f에서 곡 검색 실패 경로도 실기기로 확인했습니다.Beatles로 바꾸고 응답을 보류했습니다.Imagine Dragons검색 결과가 그대로 남았습니다. 진행 표시나 입력 잠금은 없었습니다.1hyok commentedon Aug 8, 2026
구현 기준값 확보 — 2026-08-09 새벽 류하늬 님 회신 2건 + 시안 실측.
목록·상세·에디터 복구 UI를 위 기준으로 착수할 수 있습니다.
1hyok commentedon Aug 24, 2026
부분 해소 관찰 (develop
4e0a648eb, 2026-08-25 04:21 KST)목록에 한해서는 실패 시 "애프터노트 목록을 불러오지 못했습니다." + "다시 시도" 가 정상 노출됩니다. 이슈 본문이 말하는 "빈 정상 화면으로 수렴" 은 목록에서는 재현되지 않았습니다.
상세·에디터 경로는 dev 서버 폐쇄 시간대라 도달하지 못해 미검증입니다. 남은 범위가 상세·에디터뿐이라면 이슈 제목·본문을 그쪽으로 좁히는 게 현재 상태에 맞을 것 같습니다.
참고로 같은 실패 조건에서 타임레터(#714)는 빈 목록으로 위장하고, 설정(#708)은 로그아웃 항목만 남으며, 마음의 기록(#716)은 예외 원문을 그대로 출력합니다. 애프터노트 목록이 네 기능 중 유일하게 제대로 처리되고 있습니다.
1hyok commentedon Aug 25, 2026
1번 항목 — 앞선 «부분 해소» 관찰의 사각지대
08-24 코멘트에서 "목록에 한해서는 실패 시 문구 + 다시 시도가 정상 노출된다" 고 적었는데, 그건
itemCount == 0일 때뿐입니다. 이 이슈 본문이 지목한 조건(itemCount > 0)은 그대로 남아 있습니다.목록을 유지하는 판단 자체는 맞습니다(전면 교체하면 보고 있던 것이 사라짐). 문제는 그 실패를 알리는 경로가 하나도 없다는 것입니다.
PullToRefreshBox인디케이터만 사라지고 옛 목록이 그대로라, 사용자에게는 «새로고침 성공» 과 구분되지 않습니다.수신자 목록은 사각지대가 더 넓습니다
이 이슈는 발신 흐름 기준인데, 같은 화면을 재사용하는 수신자 목록(
ReceiverAfternoteHomeEntry)은 조건이 하나 더 나쁩니다.append실패 안내AfternoteHomeEntry)nextKey = null)로 append 가 발생하지 않음snackbarHostStateAfternoteHomeScreen기본값이라 띄울 주체가 없음refresh실패(목록 있음)즉 수신자 목록에서 실패는 refresh 하나뿐인데, 그 하나가
itemCount > 0이면 아무 데도 안 나타납니다.참고 — #611 에서 다룬 범위
#1171 은
itemCount == 0갈래만 손댔습니다. 전달 조건 미충족(403/2009)과 연결 실패를 갈라 각각 다른 안내를 그리고, 재시도가 무의미한 쪽은 버튼을 주지 않습니다.itemCount > 0은 손대지 않았고 이 이슈 범위로 남깁니다.남은 결정
디자이너 확정값은 "자리 문구 + 오류 팝업 병행"(08-09 류하늬 님 회신)인데, 지금 붙은 건 자리 문구 쪽뿐입니다.
itemCount > 0실패를 팝업으로 알릴지 스낵바로 알릴지가 이 항목의 실제 결정 지점입니다 — 팝업이면core:ui의NetworkErrorPopup이 이미 있습니다.[-]fix(afternote): 서버 실패가 무음·빈 정상 화면으로 수렴 — 목록·상세·에디터 복구 수단 부재[/-][+]서버 실패가 무음·빈 정상 화면으로 수렴 — 목록·상세·에디터 복구 수단 부재[/+]1hyok commentedon Aug 30, 2026
5번(추모 영상 썸네일 업로드 실패가 저장을 막지 않는다)을 착수 단위로 #1550 에 분리했습니다. 나머지 1~4번은 여기 남습니다 — 2026-08-30 실측으로 넷 다 아직 유효합니다(홈은
refreshState is LoadState.Error && items.itemCount == 0이라 기존 목록이 있으면 여전히 무음, prefill 실패는isPrefillLoading = false만).분리하면서 본문 5번이 현행 코드와 어긋나는 부분 두 가지를 확인했습니다.
1.
thumbnailUploadFailed플래그는 더 이상 없다#831(에디터 오류 상태 통합)로
AfternoteEditorError.Upload(Target.THUMBNAIL)오류 이벤트에 흡수됐습니다. 화면 동작(액션 없는 스낵바 한 줄)은 그대로지만, 재시도를 붙일 자리가 플래그가 아니라 그 오류 채널이라 처방 설계가 달라집니다.2. 추출 실패 갈래가 빠져 있다
본문 5번은 업로드 실패만 다루는데, 프레임 추출 실패(
onMemorialThumbnailExtractionFailed→ErrorReporter/MEMORIAL_THUMBNAIL_EXTRACT)는 스낵바조차 없이 완전 무음이면서 결과는 같은 «영상은 있는데 썸네일만 없는» 제3의 상태입니다. 재시도 수단을 만들면 두 갈래를 같은 액션에 태워야 하는데, 추출 실패는 손에 바이트가 없어 재추출부터 돌아야 해 트리거가 다릅니다.덧붙여 서버 몫을 실측했습니다(
Afternote-BEorigin/main).AfternotePlaylist.MemorialVideo는videoUrl·thumbnailUrl두 칸을 nullable 로 저장만 하고 영상에서 프레임을 뽑는 로직이 없습니다 — 즉 FE 가 못 채우면 영구 결손이고, 재편집으로도 못 고칩니다(prefill 된 원격 URL 은isLocalContentUri()검사에서 추출을 건너뜀). 5번의 "복구 경로가 없다" 는 판단은 그대로 유효합니다.1hyok commentedon Aug 30, 2026
3번(수정 prefill 실패가 빈 정상 에디터로 보인다)의 폭발 반경이 넓어졌다 — #1596 / PR #1600 이후 실측 기준으로 남깁니다.
종전에는 prefill 실패 뒤 빈 폼에 제목만 채워 저장하면 수신자·남길 말씀이 덮였습니다(미디어는 요청 바디에서 키가 빠져 서버 값이 살아남았습니다). PR #1600 이
AfternotePlaylistRequestDto의 미디어 기본값을 떼면서 빈 폼이 곧"memorialPhotoUrl": null·"memorialVideo": null로 나갑니다. BE 는 이제 그 명시적 null 을 삭제로 읽어 DB 참조를 끊고 S3 객체까지 회수합니다(Afternote-BE72fee63).즉 영정사진과 장례식 영상이 실제로 지워집니다. 되돌릴 수 없는 축이 하나 늘었습니다.
지금 저장을 막고 있는 것은
AfternoteEditorValidator의 제목 필수 검사뿐이고, 그건 사용자가 제목을 한 글자 치면 통과합니다 — 우연한 가드라 근거로 삼을 수 없습니다.이 이슈의 처방 3번("prefill 실패를 빈 폼으로 전환하지 말고 오류·재시도 상태로 유지하며 저장을 막는다")이 그대로 답입니다. 우선순위 판단에 참고하시라고 덧붙입니다.
fix(afternote): prefill 이 아직 도착하지 않은 저장도 막는다 (#705)
fix(afternote): 「읽는 중」과 「불러오지 못함」을 다른 문구로 가른다 (#705)
test(afternote): 재시도 널 가지를 잠그고 배너 판정을 화면 계약으로 검증한다 (#705)
test(afternote): 새 develop 의 emptyListDescription 을 싣고 수집 완료를 기다린다 (#705
test(afternote): 배너 표시 판정의 화면 단위 단언을 접는다 (#705)
1hyok commentedon Sep 2, 2026
구현은 PR #1608 에 들어갔습니다. 다만 목록이 남은 새로고침 실패의 표시 갈림(배너 · 전면 오류 · 미표시) 은 회귀 테스트로 잠그지 못했습니다.
판정 함수를 화면 파일의
private로 두어야 해서(#1678) 테스트가 직접 부를 수 없고, 화면을 그려서 확인하는 방식은 PR 안에서 두 번 시도해 두 번 다 CI 에서 무너졌습니다. 기전은 #1443 이 실측해 둔 Robolectric 실행 순번 문제와 같습니다.검증 보강은 #1790 으로 분리했습니다. 계측 테스트로 올리는 안과 본문 컴포저블을 갈라 결정적으로 그리는 안 두 가지를 담아 뒀습니다.
Merge remote-tracking branch 'origin/refactor/1746-memorial-content-f…
merge: 부모 #1763 의 prefill 재시도 구조 위에 임시저장 이어쓰기를 얹는다 (#808)
fix(afternote): 임시저장 버튼을 등록과 같은 게이트로 묶고 발행분 편집에선 그리지 않는다 (#808)