Skip to content

AuthorReceiverRepository 가 동작하지 않음 — 에디터 수신자 목록이 항상 빈 리스트 #935

Closed

Description

@Sadturtleman

AuthorReceiverRepository 는 모든 메서드가 빈 값 또는 실패를 반환하는 죽은 구현인데, 애프터노트 에디터가 실제로 이것을 쓰고 있다. 같은 기능을 하는 UserRepository 가 이미 있고 다른 5개 화면이 그것을 쓴다.

퍼머링크 기준 커밋: 104462fd (origin/develop)


문제 — 구현이 동작하지 않는다

AuthorReceiverRepositoryImpl

override fun currentAuthorUserId(): Long? = null          // ← 항상 null (TODO)

override suspend fun refreshReceivers(): Result<Unit> {
    val userId = currentAuthorUserId() ?: run {
        clearReceivers()
        return Result.failure(IllegalStateException("No current author user id"))   // ← 항상 여기
    }
    ...
}

private suspend fun fetchReceiversForUser(userId: Long) = Result.success(emptyList())  // 도달 불가 + 빈 리스트
  • receivers 는 아무도 채우지 않는 in-memory MutableStateFlow
메서드 실제 반환
currentAuthorUserId() 항상 null
refreshReceivers() 항상 실패
observeReceivers() 항상 emptyList()
currentReceivers() 항상 emptyList()

영향 — 실제 화면이 이걸 쓴다

AfternoteEditorViewModel 이 프로덕션 경로에서 소비한다.

위치 호출 결과
L277 .observeReceivers() 빈 리스트
L312 .refreshReceivers() 항상 실패
L558 getReceiverById(id) 항상 null

이미 동작하는 것이 있다

UserRepository — core:domain

interface UserRepository {
    val receiverListFlow: Flow<List<Receiver>>
    suspend fun getReceivers(): List<Receiver>   // 파라미터 없음
}

다른 5개 화면이 이미 이것을 쓴다.

GetHomeSummaryUseCase:35        TimeletterViewModel:63
TimeLetterDetailViewModel:51    TimeLetterWriteViewModel:60
DiaryWriteViewModel:150
  • receiverListFlow 가 있어 observeReceivers() 의 역할도 이미 커버된다
  • 즉 AuthorReceiverRepository 는 UserRepository 의 죽은 병렬 구현이다

currentAuthorUserId 는 애초에 불필요하다

이유

  • GET /receivers 는 파라미터가 없다 — 서버가 액세스 토큰으로 호출자를 식별한다
  • 클라이언트가 userId 를 들고 있을 이유 자체가 없다
  • 실제로 userId 는 코드베이스 어디에도 저장되지 않는다. AccountRegistration(userId) 가 회원가입 응답에서 한 번 나오고 그대로 버려진다. TokenDataSource · UserProfileDataSource 모두 userId 를 갖고 있지 않다
  • TODO 가 오래 안 풀린 것은 채울 소스가 없어서가 아니라 채울 필요가 없어서다

결론: "userId 를 core 에서 관리하자" 가 아니라 "userId 개념 자체를 폐기" 가 맞다.


작업

  • AfternoteEditorViewModel 을 UserRepository 로 전환
    • observeReceivers() → receiverListFlow
    • refreshReceivers() → getReceivers() (또는 UserRepositoryImpl 의 receiverRefreshRevision 경로 활용)
    • getReceiverById(id) → Receiver 기준으로 재작성
  • AuthorReceiverEntry → core:model 의 Receiver 로 통합
    • AuthorReceiverMapping.kt (presentation 매퍼) 갱신 또는 삭제
  • AuthorReceiverRepository · AuthorReceiverRepositoryImpl 삭제
  • AfternoteAuthorRepositoryModule 의 bindAuthorReceiverRepository 삭제
  • AuthorReceiverEntry.kt 삭제

확인 필요 (선행)

  • 에디터 수신자 목록이 실기에서 실제로 비어 보이는지 확인 — 위 분석은 정적 호출 추적 결과다. 놓친 다른 주입 경로가 있을 수 있다
  • 확인되면 기능 미동작이므로 P1 승격 검토 — 수신자를 지정할 수 없으면 애프터노트 저장 자체가 서버 검증(475)에서 막힌다
  • 수신자 지정이 에디터 외 다른 경로(설정 > 수신인 관리 등)로도 가능한지 확인 — 가능하다면 영향 범위가 줄어든다

참고

Activity

  1. OnlyReadOneBook commented on Aug 23, 2026

    @OnlyReadOneBook
    Collaborator

    #540 으로 흡수 — 중복

    같은 데드엔드(에디터에서 수신자를 지정할 수 없어 신규 등록이 서버 검증에 막힘)를 이미 #540 이 P0 로 추적하고 있었다. 이 이슈는 그 증상을 리포지토리 축에서 다시 진단한 것이므로 #540 에 합쳐 닫는다. 진단 내용은 전부 #540 본문의 🔁 #935 흡수 섹션으로 옮겼다.

    develop 실측에서 정정된 점

    • 원인이 하나가 아니다. 이 이슈가 짚은 죽은 리포지토리 외에, AfternoteNavGraph.kt:73 의 onNavigateToSelectReceiver = {} // TODO 로 수신자 선택 화면 자체가 연결돼 있지 않다. SELECTED_RECEIVER_ID_KEY 도 읽는 코드만 있고 쓰는 코드가 레포에 없다. 즉 이 이슈의 작업 목록만 수행하면 "등록된 수신자 전원 자동 지정" 으로 475 만 우회될 뿐, 골라 넣는 UX 는 여전히 미구현으로 남는다.
    • "영구적으로 비어 있다" 는 신규 작성 한정이다. 수정 모드는 EditorFormPrefill.receivers(fix(afternote): 수정 진입 시 기존 수신자 prefill 부재 — 검증에 걸려 수정 저장 불가 #566, closed)가 상세 응답에서 채운다. 본문이 "놓친 다른 주입 경로가 있을 수 있다" 고 단 우려가 실제로 맞았다.
    • "다른 5개 화면" 은 7곳이다. ReceiverListViewModel:21(설정>수신인 관리)·RecipientListViewModel:21(타임레터) 누락. UserRepository 주입 자체는 19곳.
    • 전환 대상에 함정이 있다. receiverListFlow 는 수신인 조회 실패가 receiverListFlow 미처리 예외로 전파 — 소비 화면 앱 크래시 #884(open) 미해소 — 조회 실패가 미처리 예외로 전파돼 소비 화면이 크래시한다. 에디터를 여기 물리면 크래시 대상이 하나 늘어난다.
    • 작업 목록 누락 — androidTest 3파일의 AuthorReceiverRepository Fake 구현(AfternoteAuthorAndroidTest:206·AfternoteAuthorExtendedAndroidTest:521·AfternoteAuthorImplementedCoverageAndroidTest:315)도 함께 정리해야 한다(PR androidTest 도메인 API 드리프트 44건+런타임 7건 수정, PR 컴파일 게이트 추가 #949 와 충돌 주의).

    확인된 점

    기준 커밋 104462fd 는 origin/develop 조상이고 관련 파일은 develop HEAD(6123a68a)와 바이트 동일 — 본문의 라인 링크는 전부 유효하다. 죽은 구현 4메서드, VM 소비 L277/L312/L558, 파라미터 없는 GET users/receivers, userId 미저장(main 소스 전체 8곳 전부 회원가입 응답 경로), 서버 코드 475 모두 실측 일치. userId 개념 폐기 결론도 타당하다.

  2. OnlyReadOneBook commented on Aug 23, 2026

    @OnlyReadOneBook
    Collaborator

    재오픈 — #791 과 찢어 독립 착수 (2026-08-24)

    #540 은 #791(수신자 선택 화면 공용 컴포넌트 추출, 어사인 koongmai, 미착수)에 blocked_by 로 묶여 있다. 그런데 #791 이 막는 것은 선택 화면·라우팅(작업 A) 뿐이고, 이 이슈가 다루는 데이터 계층 정리(작업 B) 는 #791 범위 밖이다 — #791 본문이 범위 제외로 타 기능의 실제 전환 을 명시한다.

    따라서 B 를 #540 에서 도로 분리해 이 이슈로 독립 착수한다. 흡수는 취소하지 않고 역할만 나눈다:

    이슈 범위 선행
    #540 A — 수신자 선택 화면 + 라우팅 연결 + 선택 결과 반환 배선 #791 (blocked)
    #935 (이 이슈) B — 죽은 AuthorReceiverRepository 제거 · UserRepository 전환 · AuthorReceiverEntry→Receiver 통합 없음 — 착수 가능

    B 만 적용해도 P0 증상은 실질 해소된다: replaceReceiversIfEmpty(authorReceivers) 가 살아나 신규 작성 시 등록 수신자 전원이 폼에 자동 지정되고(EditorFormPrefill 주석이 명시한 원래 과도기 설계), 불필요한 수신자는 기존 deleteReceiver 로 뺄 수 있어 475 데드엔드가 풀린다. 추가(선택) 진입점만 A 로 남는다.

    앞선 흡수 코멘트의 정정 사항(원인 2축, 신규 작성 한정, 소비처 7곳, #884 크래시 리스크, androidTest Fake 3건)은 그대로 유효하며 아래 작업 목록에 반영돼 있다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

bugSomething isn't working

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions