Skip to content

fix(core): 수신자 목록의 로딩·실패 결과를 보존한다 (#1281 분리) #2045

Closed
1 of 1 issue completed

Description

@OnlyReadOneBook

작업 유형

bug — 버그·오동작

주 담당 모듈

core — 코어

개요

#1281의 설정 수신자 목록에서 최초 로딩·조회 실패·실제 0건·마지막 성공 목록을 유지한 갱신 실패를 구분하려면, 현재 receiverListFlow: Flow<List<Receiver>>가 버리는 조회 결과를 보존해야 합니다. 이 이슈는 #1281에서 요청한 공통 저장소 계약의 담당 범위를 분리합니다.

완료 조건:

  • 수신자 목록 조회의 로딩·성공·실패를 공통 도메인 결과로 전달합니다.
  • 기존 목록 전용 구독자의 동작과 공개 계약은 유지합니다.
  • 세션 격리 수정은 #2135에서 독립 완료합니다. 이 이슈의 결과 상태와 UI 소비는 그 격리 계약을 그대로 보존합니다.
  • 최초 실패·실제 0건·성공 뒤 갱신 실패·재시도·취소 전파·새 결과 상태와 기존 세션 격리의 통합을 공개 저장소 계약 테스트로 검증합니다.
  • 결과의 첫 로딩에 세션 식별을 전달하고, 인증 실패가 이전 목록을 폐기했는지 명시합니다. 화면은 새 구독과 401을 null 목록으로 추측하지 않습니다.
  • #1281의 실제 설정 소비자와 함께 구현하여 사용되지 않는 미래 API를 남기지 않습니다.

두 이슈는 같은 조회 결과와 소비를 완성하는 PR에서 함께 검증합니다. 빈 상태의 제품 문구·새 등록 흐름(#556)은 포함하지 않습니다.

화면 증거

보존해야 할 결과 화면이다. 최초 로딩, 최초 조회 실패, 재조회 실패에서 기존 목록을 유지한 상태다.

수신자 목록 조회 상태

독립 수정 분리 (2026-09-21)

#2135는 실제 DataStore에서 중간 로그아웃 방출을 놓치면 이전 계정의 수신자 캐시를 재사용하는 저장소 결함만 고칩니다. 로딩·오류 UI와 MVI 전환 없이 현재 공개 계약으로 검증하고 완료할 수 있습니다. 화면에서 다른 계정 목록이 보이는 경로까지 재현한 것은 아닙니다. #2135의 완료 조건을 이 이슈의 별도 미완료 구현으로 중복 추적하지 않습니다. 기존 #1281의 공통 결과 계약 연계는 유지합니다.

구현 순서

#1695와 #1805가 PR #2173에서 완성한 Nav3 entry 및 MVI 목록 소비를 선행합니다. #2135의 세션 격리와 #2127의 수정 후 목록 갱신은 독립 코어 PR #2137·#2130에서 먼저 머지합니다. #1281과 이 결과 계약은 PR #2154에서 최종 Nav3 소비까지 함께 검증합니다. 선행 코어 PR의 base를 설정 구조 아래로 옮기지 않습니다.

Activity

  1. added
    bugSomething isn't working
    area:core공용 코어·네트워크 기능 영역
    on Sep 13, 2026
  2. github-actions commented on Sep 13, 2026

    @github-actions
    Contributor

    bug 이슈는 사이드바 Fields > Priority 로 심각도를 지정해야 합니다. 판정 기준:

    • Urgent: 치명 — 크래시·데이터 소실·보안 무력화·핵심 경로 차단·가짜 성공
    • High: 심각 — 실패·틀린 값의 정상 위장, 핵심 기능 무동작
    • Medium: 불편 — 우회로가 있는 오동작·틀린 표시, 핵심 흐름은 유지
    • Low: 경미 — 문구·정렬·마감 품질 흠, 기능 영향 없음

    값이 비어 있어도 이슈를 닫지는 않습니다. 이 안내는 이슈당 한 번만 답니다.

  3. OnlyReadOneBook commented on Sep 13, 2026

    @OnlyReadOneBook
    CollaboratorAuthor

    착수 전 실측입니다. 이 이슈의 완료 조건은 이미 열린 PR #2051 에 전량 구현돼 있고, 남은 건 코드가 아니라 스택 머지 순서입니다. 라벨러의 한계 때문에 이 이슈만 미착수처럼 보입니다.

    1. 완료 조건 5개가 이미 구현된 위치

    PR #2051 (fix/1281-receiver-list-state, 구현 커밋 81ccfc4a0, 현재 head 37be93e1d). 항목별 대응입니다.

    완료 조건 구현
    공통 도메인 결과 core/domain/src/main/java/com/afternote/core/domain/model/ReceiverListState.kt 신규 22줄. Loading(previousReceivers) / Success(receivers) / Failure(previousReceivers) / SignedOut
    공개 계약 추가 core/domain/.../repository/UserReceiverRepository.kt +5/-1 에 receiverListStateFlow
    기존 구독자 동작 유지 core/data/.../repoimpl/UserReceiverRepositoryImpl.kt +32/-23 에서 receiverListFlow 를 receiverListStateFlow.mapNotNull 로 파생. Loading 은 null 로 걸러 방출하지 않고, Failure 는 previousReceivers.orEmpty(), SignedOut 은 emptyList()
    세션 경계와 401 같은 파일의 flatMapLatest 비로그인 분기가 SignedOut, 401 에서 lastKnownReceivers = null 로 캐시 폐기
    공개 계약 테스트 core/data/src/test/.../UserRepositoryImplTest.kt +222줄
    소비자 동반 구현 feature/setting/.../screen/ReceiverListRouteContent.kt 신규 94줄, ReceiverListViewModel.kt +54/-9, ReceiverListContract.kt +10/-2, ReceiverListStateScreenshotTest.kt 112줄과 baseline 8장

    추가된 receiverListStateFlow 계약 테스트는 6개이고, 본문의 검증 항목과 그대로 대응합니다.

    receiverListStateFlow - 로딩 뒤 성공한 빈 목록을 명시한다
    receiverListStateFlow - 첫 실패는 빈 목록 성공과 구별되고 같은 구독에서 재시도한다
    receiverListStateFlow - 갱신 로딩과 실패에 마지막 성공 목록을 보존한다
    receiverListStateFlow - 401 뒤에는 다음 로딩과 일시 실패에도 폐기한 캐시를 내지 않는다
    receiverListStateFlow - 로그아웃과 새 로그인 사이에 이전 계정 캐시를 격리한다
    receiverListStateFlow - 수집 취소를 API에 전파하고 실패 상태와 리포트를 만들지 않는다
    

    2. 이 이슈가 미착수로 보이는 이유

    라벨러가 PR 당 이슈 1건만 잡습니다. .github/scripts/label-issues-with-open-prs.mjs:70 이 extractTitleIssueNumber(pullRequest.title) 를 쓰고, .github/scripts/validate-pr-issue-link.mjs:58 의 그 함수는 제목 끝의 참조가 정확히 하나일 때만 그 번호를 돌려줍니다. 본문은 보지 않습니다.

    #2051 제목이 fix(setting): 수신자 목록 조회 상태와 재시도 연결 (#1281) 이라 #1281 만 pr-open 라벨과 issue-pr-open:2051 링크 코멘트를 받았고, 본문 두 번째 줄의 Closes #2045 는 라벨도 코멘트도 받지 못했습니다. base 가 develop 이 아니어서 GraphQL closingIssuesReferences 도 빈 배열이라 Development 칸 역시 비어 있습니다.

    실측 대조입니다. #1281, #579, #1805, #1502, #1695 는 전부 pr-open 을 갖고 있고, 이 이슈만 bug, area:core 둘뿐입니다.

    3. 남은 장애물은 선행 산출물이 아니라 머지 순서

    스택은 아래부터 이렇습니다. 다섯 PR 전부 열려 있습니다.

    develop
     ← #1962 codex/1695-setting-nav3
     ← #1967 refactor/1502-setting-state-mvi
     ← #2018 refactor/1805-receiver-list-mvi
     ← #2034 fix/579-receiver-reentry
     ← #2051 fix/1281-receiver-list-state
    

    #2051 의 체크는 guard 하나만 red 입니다. Unit Test, Static Analysis(Ktlint, Android Lint), Screenshot, Pixel 2 네 종, CodeQL, Repository Quality 는 전부 pass 이고, 나머지는 skipping 입니다. guard 가 낸 red 는 의도된 차단입니다.

    ::error::#1281 이 아직 열린 #579 에 blocked — 머지 순서 위반. 선행 이슈를 먼저 완료할 것 (base: fix/579-receiver-reentry)
    ::warning::base 가 'fix/579-receiver-reentry' — 스택 PR 은 base 를 develop 로 PATCH 한 뒤 머지할 것
    

    base 가 develop 이 아닌 것은 warning 이고, red 를 만든 것은 열린 선행 이슈 #579 입니다. 이 이슈도 GitHub blocked_by 로 #579 에 걸려 있습니다.

    4. 다음에 여는 사람에게

    지금 develop 위에서 같은 범위를 다시 쓰지 마십시오. 세 가지가 걸립니다.

    첫째, 중복입니다. UserReceiverRepositoryImpl.kt 와 UserReceiverRepository.kt 는 #2051 이 이미 고쳐 둔 파일이라, 스택이 내려올 때 정면 충돌합니다.

    둘째, 계약만 떼면 소비처가 없습니다. origin/develop(7d87aa3f4)에서 receiverListFlow 를 읽는 프로덕션 코드는 두 곳뿐입니다. feature/setting/presentation/.../viewmodel/ReceiverListViewModel.kt:21 과 feature/timeletter/presentation/.../viewmodel/RecipientListViewModel.kt:21 이고, 뒤쪽은 timeletter 담당 모듈입니다. 소비자 없이 receiverListStateFlow 만 올리면 완료 조건 5번이 직접 금지한 미사용 미래 API 가 됩니다.

    셋째, 남은 한 소비처는 갈아엎힐 코드입니다. develop 의 ReceiverListViewModel.kt 는 stateIn 하나짜리 28줄인데, #2018 과 #2034 가 이를 MVI 로 재작성하고 #2051 이 거기에 +54/-9 를 얹습니다. 지금 그 파일에 상태 소비를 배선하면 스택이 내려온 뒤 통째로 다시 고쳐야 합니다.

    그래서 이 이슈에서 할 일은 새 코드가 아니라 #1962 부터 아래에서 위로 순서대로 머지하는 것입니다. #2051 이 머지되면 이 이슈는 본문의 Closes #2045 로 함께 닫힙니다.

  4. added
    pr-open이 이슈를 구현하는 PR 이 열려 있다 — base 가 기본 브랜치가 아니어도 드러낸다
    on Sep 13, 2026
  5. OnlyReadOneBook commented on Sep 13, 2026

    @OnlyReadOneBook
    CollaboratorAuthor

    이 이슈를 맡은 PR 은 #2051 이다 (base fix/579-receiver-reentry). 본문 첫 절에 Closes #1281 과 Closes #2045 가 나란히 있고, 저장소가 로딩·성공·실패 결과를 보존하도록 바꾸는 공통 계약 쪽이 이 이슈의 몫이다. 갱신 실패는 마지막 성공 목록을 유지하되 401·로그아웃·새 로그인 구간에서는 이전 목록을 버린다.

    pr-open 라벨을 손으로 붙였다. 라벨러가 PR 제목의 (#1281) 만 읽어 #1281 에는 라벨이 붙고 이 이슈에는 붙지 않았다. 이 이슈가 #2082 을 연 계기다. 미착수 조사에서 구현이 이미 있는데도 미착수로 보였고 중복 착수로 이어질 뻔했다.

    base 가 기본 브랜치가 아니라서 GitHub 이 closing 참조를 승격하지 않아 Development 칸도 비어 있다. 라벨이 유일한 신호인데 그 신호가 절반만 나온 자리다.

    이 코멘트의 마커는 라벨러가 쓰는 것과 같아서, #2082 수정이 머지돼도 같은 내용이 다시 달리지 않는다. 라벨은 그 전까지 배포본 리컨사일러가 도로 떼어 간다.

  6. removed
    pr-open이 이슈를 구현하는 PR 이 열려 있다 — base 가 기본 브랜치가 아니어도 드러낸다
    on Sep 13, 2026
  7. added
    pr-open이 이슈를 구현하는 PR 이 열려 있다 — base 가 기본 브랜치가 아니어도 드러낸다
    on Sep 23, 2026
  8. github-actions commented on Sep 23, 2026

    @github-actions
    Contributor

    이 이슈를 맡은 PR 은 #2154 다 (base fix/2135-receiver-session-cache).

    base 가 기본 브랜치(develop)가 아니라서 GitHub 은 이 이슈의 Development 칸에
    아무것도 표시하지 않는다. 본문에 Closes #N 이 있어도 마찬가지다 — 그 링크는 기본 브랜치를
    target 하는 PR 에서만 만들어진다.

    PR 이 닫히거나 머지되면 이 이슈의 pr-open 라벨은 다음 리컨사일에서 떨어진다.

  9. removed
    pr-open이 이슈를 구현하는 PR 이 열려 있다 — base 가 기본 브랜치가 아니어도 드러낸다
    on Sep 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

area:core공용 코어·네트워크 기능 영역bugSomething isn't working

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions