Repository navigation
refactor(afternote): 합본 UserRepository 대신 좁은 계약 UserReceiverRepository·MyProfileRepository 를 주입한다 (#1743) - #1837
Conversation
에디터가 프로세스 사망에서 되살아나면 두 갈래가 겹쳤다 — 폼 스냅샷이 사용자의 미저장 편집을 되살리고, 곧이어 `init` 의 상세 재조회가 폼이 더러운지 묻지 않고 `pendingPrefill` 을 다시 발행해 화면이 그것을 실으면서 되살린 편집을 서버 값으로 덮었다. 「덮지 않는다」로 정한다. 서버 값으로 되돌릴지 묻는 화면은 시안도 문구도 없고, 사용자가 쓴 것을 조용히 버리는 쪽이 더 나쁘다. 재조회 자체는 그대로 돈다 — 기준 스냅샷(#1617)이 없으면 저장이 막히고 카테고리도 서버가 아는 값이어야 한다. 막는 것은 「폼에 덮어쓰기」 하나이고, 프리필을 싣지 않은 경로에서는 화면의 통보가 오지 않으므로 skeleton 을 재조회 쪽에서 직접 걷는다. 가드가 보는 것은 폼 스냅샷과 「프리필이 실렸다」 표식이지 값 비교가 아니다. 계정 정보와 남기실 말씀은 화면이 소유해 폼에 없으므로, 값으로 갈랐다면 비밀번호만 고친 복원이 「폼이 같다」로 읽혀 그대로 덮인다. 표식만 보지도 않는다 — 스냅샷 저장은 용량 초과를 삼키므로, 표식만 남은 빈 폼에서 프리필까지 막으면 그 빈 폼이 기준과 짝지어져 「전부 지움」 저장이 된다(#705·#1617 이 막은 경로다). 그래서 프리필이 실린 적 없는 복원은 종전대로 프리필을 받는다.
🚧 리뷰 적체 가드 — 이 PR 을 닫습니다팀 리뷰 응답 대기 · 1건
이 저장소는 팀 리뷰 응답 또는 자기 PR 의 변경요청 대응을 기다리는 PR 이 1건이라도 남아 있으면 새 PR 을 열 수 없습니다 (#1136, #1679). 각 PR 에 필요한 리뷰는 한 건입니다 — 누구든 먼저 판정을 내면 그 PR 은 모두의 목록에서 빠집니다. 승인 뒤 변경을 다시 볼 의무는 없고, 변경요청도 작성자가 같은 리뷰어에게 재요청한 뒤 실질 커밋·응답·본문 편집을 남긴 경우에만 다시 리뷰어의 몫이 됩니다. 되살리는 법위 PR 에 필요한 리뷰나 작성자 조치를 끝낸 뒤 이 PR 을 다시 여세요. 브랜치는 지워지지 않았고 커밋도 그대로입니다. gh pr reopen 1837리뷰보다 이 PR 이 급하면 |
|
이 PR 은
|
리뷰 지적 반영. savedStateHandle.contains(EDITOR_FORM_SNAPSHOT_KEY) 는 문자열 존재만 본다. readFormSnapshotOrDefault() 가 디코딩 실패를 삼켜 빈 기본 폼으로 떨어지므로, 「표식 있음 + 문자열 있음 + 디코딩 실패」 조합에서 가드가 참이 되어 프리필이 막히고 빈 폼이 새 기준 스냅샷과 짝지어진다 — 이 PR 의 KDoc 이 스스로 피하겠다고 적은 「전부 지움」 저장이다. readFormSnapshotOrDefault() 가 RestoredForm(form, fromSnapshot) 을 돌려주게 하고 그 결과로 판정한다. 조건이 KDoc 의 주장과 일치한다. 회귀 테스트를 붙이고 결정 실험으로 확인했다 — 조건을 contains(...) 로 되돌리자 「스냅샷이 깨져 빈 폼으로 떨어진 복원은 프리필을 받는다」가 실패했다.
`Pixel 2 API 30 androidTest` 가 두 번 연속 red 였다. 에뮬레이터가 아니라
`:app:hiltJavaCompileDebugAndroidTest` 가 죽는다.
[Dagger/MissingBinding] MyProfileRepository cannot be provided
without an @Provides-annotated method.
MyProfileRepository is injected at
GetHomeSummaryUseCase(myProfileRepository, …)
`TestCoreUserRepositoryModule` 이 `CoreUserRepositoryModule` 을 통째로
`replaces` 하는데, 좁은 계약 2종의 `@Binds` 가 바로 그 정본 모듈에 있었다.
`GetHomeSummaryUseCase` 가 `UserRepository` 대신 둘을 받게 되면서 계측
그래프에서만 비게 됐다 — 단위 테스트는 Hilt 를 타지 않아 드러나지 않았다.
**#1837 이 애프터노트 몫으로 같은 자리에 같은 블록을 이미 넣어 뒀다.**
그래서 새로 쓰지 않고 그 파일을 그대로 가져왔다 — 두 브랜치의 해당 파일이
바이트 단위로 같아, 어느 쪽이 먼저 들어가도 충돌 없이 합쳐진다.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ea5nJ6nL7c2pdCNzKGztW2
|
형제 충돌이 해소됐다 — 지금은 이 PR 과 같은 파일을 서로 다르게 고친 열린 PR 이 없다 (#1750). |
…o tmp/1837-conflict # Conflicts: # feature/afternote/presentation/src/test/kotlin/com/afternote/feature/afternote/presentation/AfternoteAuthorTestFixtures.kt
merge queue 방출 — merge group CI 실패사유 실패한 job: 고친 뒤 |
Closes #1743
Refs #1694, #1804
상세 화면은
MyProfileRepository, 편집기와 수신자 선택 화면은UserReceiverRepository를 주입받도록 좁힙니다. 사용하지 않는 합본 계약을 제거하고 테스트도 기존 core domain의 좁은 fake를 사용합니다. 호출 순서와 오류 처리는 유지합니다.직접 base는 #2167의
refactor/2166-media-mapping입니다. 이 PR의 실제 diff는 afternote presentation 20개 파일의 주입 계약 전환입니다. 저장 UseCase #1838과 MVI #1972가 이 경계를 소비합니다. 복원 prefill 가드 #1839는 최종 MVI 뒤의 독립 수정으로 옮겼습니다.검증
HEAD
246df1325ad5954d672562176aed07341c9bab3c에서 presentation 340개 테스트가 통과했습니다(실패·오류·건너뜀 0). presentation ktlint, 실제 base 대비 전체 diff의 모듈 소유권 검사와git diff --check를 통과했습니다.🧪 CI Test Plan
{ "androidTest": { "mode": "selected", "reason": "에디터와 수신자 선택의 저장소 주입을 UserReceiverRepository로 좁혔다. 실제 NavHost와 Hilt 그래프에서 수신자 확정·취소·조회 실패 후 재시도가 같은 fake 데이터로 동작하는지 검증한다. 상세 MyProfileRepository 경로는 단위 테스트, 전체 계측 Hilt 그래프는 assembleDebugAndroidTest로 검증했다.", "tests": [ { "path": "app/src/androidTest/java/com/afternote/afternote_fe/ReceiverSelectionResultAndroidTest.kt", "selector": "com.afternote.afternote_fe.ReceiverSelectionResultAndroidTest#afternoteEditorNavHost_receiverSelectOpensWithFormReceiverCheckedAndConfirmAddsOnlyTheChosen", "device": "api34" }, { "path": "app/src/androidTest/java/com/afternote/afternote_fe/ReceiverSelectionResultAndroidTest.kt", "selector": "com.afternote.afternote_fe.ReceiverSelectionResultAndroidTest#afternoteEditorNavHost_receiverSelectBackKeepsEditorReceiversUnchanged", "device": "api34" }, { "path": "app/src/androidTest/java/com/afternote/afternote_fe/ReceiverSelectionResultAndroidTest.kt", "selector": "com.afternote.afternote_fe.ReceiverSelectionResultAndroidTest#afternoteSelectReceiver_emptyAndLoadFailureBlockConfirmUntilRetryLoadsList", "device": "api34" } ] } }