Repository navigation
에디터 수신자 지정 불가 — 선택 화면 라우팅 미연결 + AuthorReceiverRepository 죽은 구현 (전 카테고리 신규 등록 차단) #540
Description
📜 Overview (Required)
애프터노트 에디터의 "수신자 추가" + 버튼이 무동작이다. AfternoteNavGraph.kt:74 에서 onNavigateToSelectReceiver = {} 로 비어 있고 주석이 // TODO: 수신인 선택 화면 라우팅 연결 이다. 애프터노트용 수신자 선택 화면 자체가 레포에 없다(마인드레코드 ReceiverSelectBottomSheet·타임레터 RecipientListScreen 은 각 기능 전용).
영향 카테고리 = 구현된 4종 전부(MEMORIAL·SOCIAL·BUSINESS·GALLERY). 갤러리는 원래 별도 다이얼로그 경로였으나 #680 수정(PR #774 머지)으로 그 경로가 폐기되고 같은 onNavigateToSelectReceiver 에 합류했다.
수신자는 서버 계약상 필수(등록 시 최소 1명, 미지정 시 400 code 1615 "수신자(receivers)는 최소 1명 이상 필요합니다" — 라이브 실측)라, 진입점이 죽어 있으면 해당 카테고리는 등록 자체가 불가능하다. 즉 #501 이 섹션을 노출시켜도 이 라우팅이 연결되기 전까지 등록 데드엔드는 남는다.
⚠️ 위 한 문단은 2026-08-03 이후로 사실이 아니다 — 아래 「등록 차단 논거 정정」 참조. 진입점이 죽어 있다는 진단 자체는 유효하다.
에뮬레이터 런타임 실측(2026-07-27): 소셜 에디터에서 수신자 +(y=1452) 탭 → 화면 전환·다이얼로그 없음, logcat 무반응.
📌 Child Issue(Optional)
No response
📍 Note (Optional)
- ✅ 수신자 선택 화면 시안은 존재한다 — 디자인 게이트 해소(2026-08-08 Figma REST 실측). 이 이슈가 "시안 유무 확인 필요" 로 달아 둔
blocked: 디자인은 미확인 상태에서 붙인 것이었고, 확인 결과 3벌이 있다:115:15841·2249:14101·3631:24820. 셋 다 검색 필드 + 초성 인덱스(ㄱ~ㅎ) 구조이고, 가장 최근 것(3631:24820)에는 타이틀 "수신자 선택" 과 하단 "수신자 선택 완료하기" 버튼이 명시돼 있다. - ⏳ PM 논의 진행 중 — 진입 흐름 확장분(디자인 게이트 아님). 전건호 역질문(2026-08-06)에 대해 제안한 흐름은 "수신자 추가하기" → "수신자 선택" 개명 → 기존 수신자 시트 → 시트 하단 "+ 새 수신자 등록" → 설정>수신자 등록 화면 → 복귀 시 방금 등록한 수신자가 선택된 상태. 서버 영향은 0으로 확인됐다(
ReceiverRequest가receiverId단일 필드, 신규 등록 API 가 이미receiverId를 응답). "기존 목록에서 고르기" 본체는 어느 안이든 동일하므로 이 이슈의 라우팅 연결은 결론과 무관하게 착수 가능하고, "+ 새 수신자 등록" 진입만 결론 후 추가된다. - 기능적으로는 "이미 등록된 수신자 목록에서 고르기"가 맞다(서버가 기존
receiverId를 요구하므로, 신규 생성 다이얼로그로는 유효한 id 를 만들 수 없다). GET /users/receivers로 사용자의 등록 수신자 목록을 받을 수 있다.- QA 근거: 노션 2차 QA(2026-07-28) 23번.
🔁 #935 흡수 (2026-08-24) — 원인은 둘이다
같은 데드엔드를 리포지토리 축에서 다시 진단한 #935 를 이 이슈로 흡수한다. 라우팅만 연결해도 수신자 지정은 여전히 동작하지 않는다 — 죽은 리포지토리가 두 번째 원인이기 때문이다. 아래는 origin/develop 실측(기준 6123a68a, 관련 파일은 #935 의 기준 커밋 104462fd 와 바이트 동일).
원인 A — 라우팅 미연결 (이 이슈의 원래 진단)
AfternoteNavGraph.kt:73 onNavigateToSelectReceiver = {}, // TODO: 수신인 선택 화면 라우팅 연결
→ 애프터노트용 수신자 선택 화면이 레포에 없다. 추가 확인: 선택 결과를 돌려받는 키 SELECTED_RECEIVER_ID_KEY 는 읽는 코드만 있고 쓰는 코드가 레포에 없다(NavigationKeys.kt:4 정의, AfternoteNavGraphEditor.kt:33-34 읽기·삭제).
원인 B — AuthorReceiverRepository 가 죽은 구현
AuthorReceiverRepositoryImpl 은 모든 메서드가 빈 값 또는 실패를 반환한다.
| 메서드 | 실제 반환 |
|---|---|
currentAuthorUserId() (L27) |
항상 null (TODO) |
refreshReceivers() (L29-38) |
항상 실패 — userId 가 null 이라 fetchReceiversForUser 에 도달 불가 |
observeReceivers() (L22) |
항상 emptyList() — 아무도 채우지 않는 in-memory MutableStateFlow |
currentReceivers() (L24) |
항상 emptyList() |
에디터가 이걸 프로덕션 경로에서 소비한다 — AfternoteEditorViewModel L277 observeReceivers() · L312 refreshReceivers() · L558 getReceiverById().
폼에 수신자가 들어가는 경로 3개 중 2개가 이것 때문에 죽어 있다.
| 경로 | 상태 |
|---|---|
replaceReceiversIfEmpty(uiState.authorReceivers) — 신규 작성 시 (AfternoteNavGraphEditor.kt:131-133) |
❌ authorReceivers 가 항상 빈 리스트 |
tryApplyReceiverSelectionFromSavedState → getReceiverById(id) |
❌ currentReceivers() 가 비어 항상 null → early return (원인 A 로 애초에 호출도 안 됨) |
applyPrefill — 수정 모드 (#566) |
✅ 상세 응답에서 채워짐 |
즉 신규 작성 한정으로 수신자 지정이 불가능하고, 수정 모드는 prefill 덕에 살아 있다.
이미 동작하는 대체재가 있다 — UserRepository
core:domain 의 UserRepository 가 같은 기능을 하고, 수신자 목록 소비처 7곳이 이미 이것을 쓴다 — GetHomeSummaryUseCase:35 · TimeletterViewModel:63 · TimeLetterDetailViewModel:51 · TimeLetterWriteViewModel:60 · DiaryWriteViewModel:150 · ReceiverListViewModel:21 · RecipientListViewModel:21.
interface UserRepository {
val receiverListFlow: Flow<List<Receiver>> // observeReceivers() 의 역할을 커버
suspend fun getReceivers(): List<Receiver> // 파라미터 없음
}AuthorReceiverRepository 는 이것의 죽은 병렬 구현이다.
currentAuthorUserId 는 애초에 불필요하다
GET users/receivers(UserApiService.kt:30) 는 파라미터가 없다 — 서버가 액세스 토큰으로 호출자를 식별한다- 실제로 userId 는 코드베이스 어디에도 저장되지 않는다. main 소스 전체에서
userId는 8곳뿐이고 전부 회원가입 응답 경로(AuthDto→AccountRegistration→AuthMapper)와 이 죽은 Impl 이다.TokenDataSource·UserProfileDataSource모두 userId 를 갖고 있지 않다 - TODO 가 오래 안 풀린 것은 채울 소스가 없어서가 아니라 채울 필요가 없어서다
"userId 를 core 에서 관리하자" 가 아니라 "userId 개념 자체를 폐기" 가 맞다.
✅ 작업
A. 수신자 선택 화면 + 라우팅 (확정 사양: 위 Note 의 전건호 08-06 답글, 시안 3631:24820)
- 수신자 선택 화면 신설 — 검색 필드 + 초성 인덱스(ㄱ~ㅎ), 타이틀 "수신자 선택", 하단 "수신자 선택 완료하기"
-
AfternoteNavGraph.kt:73의onNavigateToSelectReceiver = {}TODO 연결 - 선택 결과 반환 배선 —
SELECTED_RECEIVER_ID_KEY를 쓰는 쪽 구현 - 4개 카테고리 전부 확인 (MEMORIAL·SOCIAL·BUSINESS·GALLERY — fix(afternote): 갤러리 수신자 직접 입력 다이얼로그 폐기 — 수신자 선택 경로로 통일 (closes 680) [base: feat/675] #774 머지로 갤러리도 이 경로에 합류)
B. 죽은 리포지토리 제거 (#935 에서 흡수)
-
AfternoteEditorViewModel을UserRepository로 전환 —observeReceivers()→receiverListFlow,refreshReceivers()→getReceivers(),getReceiverById(id)를Receiver기준으로 재작성 -
AuthorReceiverEntry→core:model의Receiver(receiverId·name·relation) 로 통합,AuthorReceiverMapping.kt갱신 또는 삭제 -
AuthorReceiverRepository·AuthorReceiverRepositoryImpl·AuthorReceiverEntry.kt삭제 -
AfternoteAuthorRepositoryModule의bindAuthorReceiverRepository삭제 - androidTest 3파일의 Fake 구현 정리 —
AfternoteAuthorAndroidTest:206·AfternoteAuthorExtendedAndroidTest:521·AfternoteAuthorImplementedCoverageAndroidTest:315(PR androidTest 도메인 API 드리프트 44건+런타임 7건 수정, PR 컴파일 게이트 추가 #949 와 충돌 주의)
⚠️ 전환 시 주의
receiverListFlow는 수신인 조회 실패가 receiverListFlow 미처리 예외로 전파 — 소비 화면 앱 크래시 #884(OPEN) 미해소 — 조회 실패가 미처리 예외로 전파돼 소비 화면이 크래시한다. 에디터를 여기 물리면 크래시 대상이 하나 늘어난다- 신규 작성 경로의
replaceReceiversIfEmpty(authorReceivers)는 "등록된 수신자 전원 자동 지정"이다. B 만 하면 475 는 우회되지만 시안의 "골라서 지정" 의도와 어긋나므로, A 와 함께 이 자동 채움을 유지할지 판단이 필요하다 - 기존
feat/540브랜치(2026-08-14,c6a94702)는AfternoteNavActions스텁만 추가하고getReceiverById를 지운 채 호출처(AfternoteNavGraphEditor.kt:35)를 안 고쳐 컴파일이 깨진 미완성 상태다. 시그니처만 참고하고 develop 에서 새로 시작한다
🔧 등록 차단 논거 정정 (2026-08-29) — 심각도가 내려간다
이 이슈의 「서버가 수신자 최소 1명을 요구하므로 진입점이 죽으면 등록 자체가 불가능」 논거는 진단 시점(2026-07-27 라이브 실측)에는 사실이었으나 2026-08-03 이후로는 성립하지 않는다.
근거 — BE e7f073d(2026-08-03, hwanggyuun) 「fix: 애프터노트 생성 시 receivers·actions를 선택 필드로 완화」
문서만 맞추지 않고, 수신자·체크리스트 없이도 등록할 수 있게 생성 검증을 변경한다. SOCIAL credentials·PLAYLIST songs 등 카테고리 고유 필수는 유지한다.
BE origin/main(aba24df, 2026-08-27) 재실측 결과:
AfternoteValidationCommons.validateRequiredReceivers는 정의만 남고 호출처 0건이다.ErrorCode.RECEIVERS_REQUIRED(1615) 자체는 살아 있으나 애프터노트 생성 경로가 아니라 타임레터 SCHEDULED(TimeLetterService)와 수신자 서비스(ReceivedService·MindRecordReceiverService)에서만 던진다.
따라서 이 이슈가 푸는 것은 「전 카테고리 등록 차단(치명)」이 아니라 「신규 작성에서 수신자를 지정할 수단 부재(기능 결손)」다. 수신자 없이도 등록은 된다. 수정 모드는 prefill 로 살아 있으므로 영향은 신규 작성 경로에 한정된다.
제목의 「전 카테고리 신규 등록 차단」도 같은 이유로 과장이다. 이력 보존을 위해 제목은 두되 판정은 이 절을 따른다.
관련: 에디터의 필수 표시·검증 기준은 서버 계약을 따른다는 0829 확정에 따라, FE 쪽 수신자·처리방법 필수 취급도 #1334 에서 제거됐다.
Activity
OnlyReadOneBook commentedon Jul 28, 2026
2026-07-28 13:16 에뮬 런타임 재현 확인.
노트 탭 → 작성 → 종류 = 소셜네트워크에서 "수신자 추가" 의 + 를 탭해도 화면 변화가 없습니다(UI 트리 변화 0). 같은 세션에서 종류를 "갤러리 및 파일" 로 바꾸면 같은 자리에서 수신자 입력 다이얼로그가 정상적으로 뜹니다.
수신자는 등록 필수값이라(
수신자를 한 명 이상 선택해 주세요.검증) 소셜네트워크는 등록까지 진행할 수 없습니다.OnlyReadOneBook commentedon Jul 28, 2026
최신 develop(
18d65f84) 빌드에서도 그대로 재현됩니다. 2026-07-28 18:45 실측.노트 탭 → FAB → 소셜네트워크 에디터 → "수신자 추가"
+탭 → 화면 변화 0, 바텀시트·라우팅 없음. 애프터노트 등록 완주가 여전히 막혀 있습니다(수신자 최소 1명이 서버 필수값이라 등록 자체가 불가).OnlyReadOneBook commentedon Jul 30, 2026
재현 확인 (2026-07-30, develop
a3623e4b)소셜 에디터에서 "수신자 추가" + 버튼을 눌러도 화면 전환 없음 · 네트워크 호출 0건(logcat OkHttp). 두 번 탭해도 동일하다.
같은 화면의 "처리 방법 리스트" + 버튼은 정상 동작한다 — 탭하면 "처리 방법을 입력해 주세요" 입력 행이 추가된다. 무동작인 것은 수신자 쪽 진입점뿐이다.
수신자는 서버 필수값(code 1615)이라, 이 상태에서는 앱만으로 SOCIAL 애프터노트를 등록할 수 없다. 이번 QA 에서 애프터노트 데이터를 curl 로 만들어야 했던 이유이기도 하다.
OnlyReadOneBook commentedon Aug 8, 2026
갱신: #680 수정(feat/680, PR 예정)으로 갤러리 다이얼로그 경로가 폐기되고 GALLERY 도
onNavigateToSelectReceiver로 통일된다. 그 머지 후에는 본문의 "갤러리만 별도 다이얼로그 경로라 동작한다" 서술이 낡고, 이 라우팅 미연결의 영향 카테고리는 4종 전부(MEMORIAL·SOCIAL·BUSINESS·GALLERY) 가 된다. 이 이슈 해소 시 갤러리 진입점도 함께 살아난다.OnlyReadOneBook commentedon Aug 8, 2026
라우팅 목적지 사양이 확정됐습니다 — 갤러리 에디터 프레임 700-38183 의 핀 스레드, 전건호 08-06 답글(댓글 1873986804):
#680 (PR 예정) 머지 시 GALLERY 도 본 이슈의 라우팅 미연결 그룹에 합류해 해소 범위가 4개 카테고리 전부가 됩니다. 선택 결과 수신 배선은
tryApplyReceiverSelectionFromSavedState(SELECTED_RECEIVER_ID_KEY)가 이미 준비돼 있습니다.OnlyReadOneBook commentedon Aug 21, 2026
2026-08-21 배포 후보 직접 QA — GALLERY까지 범위 확대 재현
배포 기준 보정 후 대상인
cc725f47d0704e2b05cab65726ae66b4812c9337(PR #802 merge SHA, 현재 앱 트리와 동일)에서 에뮬레이터로 재현했습니다.재현
갤러리 및 파일로 변경수신자 추가의+탭접근성 트리상 버튼은
clickable=true, bounds[478,838][604,964]였고 탭 후에도 화면에는갤러리 및 파일,수신자 추가,처리 방법 리스트가 그대로 남았습니다.현재 원인 지점
AfternoteEditorContent.kt: GALLERY의onAddClick = onNavigateToSelectReceiverAfternoteNavGraph.kt:onNavigateToSelectReceiver = {} // TODO: 수신인 선택 화면 라우팅 연결#680에서 GALLERY의 잘못된 직접입력/임시 ID 경로는 제거됐지만, 그 결과 GALLERY도 이 미연결 콜백을 사용하게 됐습니다. 따라서 현재 영향 범위는 기존 본문의 MEMORIAL·SOCIAL·BUSINESS가 아니라 GALLERY를 포함한 구현 카테고리 전부입니다.
담당은 현재 assignee(
1hyok)와 blame(80783a49e, 해당 TODO 배선) 기준이 일치해 유지합니다.[-]fix(afternote): 에디터 수신자 추가 진입점 무동작 — 수신인 선택 화면 라우팅 미연결 (MEMORIAL·SOCIAL·BUSINESS 등록 차단)[/-][+]fix(afternote): 에디터 수신자 지정 불가 — 선택 화면 라우팅 미연결 + AuthorReceiverRepository 죽은 구현 (전 카테고리 신규 등록 차단)[/+][-]fix(afternote): 에디터 수신자 지정 불가 — 선택 화면 라우팅 미연결 + AuthorReceiverRepository 죽은 구현 (전 카테고리 신규 등록 차단)[/-][+]에디터 수신자 지정 불가 — 선택 화면 라우팅 미연결 + AuthorReceiverRepository 죽은 구현 (전 카테고리 신규 등록 차단)[/+]OnlyReadOneBook commentedon Aug 28, 2026
라우팅 연결·수신자 선택 화면·SELECTED_RECEIVER_ID_KEY 결과 반환은 PR #1372 로 반영됐다(원인 B 의 죽은 리포지토리는 현 develop 에서 이미 해소돼 있어 원인 A 만 남아 있었음). 이 이슈는 #791(수신자 선택 공용 컴포넌트 추출)에 blocked 로 걸려 있어 #791 결론 후 공용 전환 여부를 정리하면서 닫는다. «+ 새 수신자 등록» 진입 확장은 PM 결론 대기로 계속 범위 밖.
docs(afternote): 목록 로드 실패 시 선택이 조용히 소실되는 경로에 추적 이슈 #1405 주석을 남긴다 (#540)
refactor(afternote): 수신자 선택 화면을 공용 ReceiverSelectScreen 소비로 전환한다
refactor(afternote): SelectReceiverViewModel 백킹 필드를 _uiState 로 맞춘다
refactor(afternote): 수신자 선택 문구 2종을 공용 기본값에 맡긴다
refactor(afternote): 수신자 선택 제목도 공용 기본값에 맡긴다
refactor(afternote): 손으로 만든 로딩 화면을 core:ui LoadingBody 로 교체한다
OnlyReadOneBook commentedon Aug 29, 2026
✅ 완료 — 닫는다 (2026-08-30 실측)
원인 A·B 가 모두 해소돼 이 이슈에 남은 작업이 없다.
AfternoteNavGraph.kt:63onNavigateToSelectReceiver = actions::navigateToSelectReceiverSELECTED_RECEIVER_ID_KEY쓰는 코드 0건AppNavigationActions.kt:478이 쓰고,AfternoteNavGraphEditor.kt:50-51이 읽고 지운다AuthorReceiverRepository죽은 구현origin/develop실측으로author/editor/receiver/select/SelectReceiverViewModel.kt·author/navigation/AfternoteNavGraphSelectReceiver.kt존재를 확인했다.이 이슈에서 갈라져 나간 갈래 — 전부 열린 이슈가 추적 중
「+ 새 수신자 등록」 PM 논의 대기분은 #1427 이 이어받았으므로 이 이슈를 대기 상태로 열어 둘 이유가 없다.