Repository navigation
수신자 열람 흐름 23개 파일이 afternote 모듈 리소스를 차용 — 수신자 전용 87개가 남의 소유, #926(홈) 밖 잔여 전량 #1066
Description
:feature:receiver:presentation 의 열람 흐름 화면들이 자기 모듈이 아니라 :feature:afternote:presentation 의 R 을 통해 문자열·이미지를 가져다 쓴다. 이름이 이미 receiver_* 인 문자열 78개가 애프터노트 모듈의 strings.xml 에 들어 있다.
실측 기준 리비전: 6b381db8 (origin/develop)
어쩌다 이렇게 됐나
#615/PR #919 가 수신자 흐름 155파일을 이 모듈로 옮길 때 리소스는 의도적으로 두고 갔다. PR 본문 「경계 처리」:
리소스 이동 없음 —
received_*계열 문자열을 author 상세 화면들도 공유 사용해 프리픽스 분리가 불가. 이동 파일들의 기존import ...afternote.presentation.R이 그대로 유효하므로 본문 무변경. 수신자 전용 리소스 재배치는 후속.
#926(PR #1061)이 그 「후속」 중 수신자 홈 2파일만 처리한다. 이 이슈는 그 밖에 남는 전량이다.
실측
:feature:receiver:presentation 에서 com.afternote.feature.afternote.presentation.R 을 import 하는 파일은 25개(main)이고, #926 이 가져가는 홈 2개를 빼면 23개 + 유닛테스트 3개다. 참조하는 고유 리소스 심볼은 97개(string 87 · drawable 10).
| 패키지 | 파일 |
|---|---|
deliveryverification |
10 (IdentityVerificationEmailScreen 10심볼 · DocumentUploadScreen 7 · MasterKeyScreen 6 · IdentityVerificationIntroScreen 5 · DeliveryVerificationCompleteScreen 5 · DocumentUploadViewModel 5 · IdentityVerificationViewModel 2 · MasterKeyViewModel 2 · component/DocumentSlotCard 2 · component/DocumentSourceBottomSheet 3) |
detail |
4 (SocialNetworkReceivedDetailScreen 8 · MemorialReceivedDetailScreen 3 · GalleryReceivedDetailScreen 1 · ReceivedAfternoteDetailViewModel 1) |
summary |
4 (ReceiverAfternoteScreen 19 · HeroCard 3 · TopHeader 2 · ReceiverDownloadAllViewModel 2) |
recordsbox |
2 (SenderRegistrationScreen 3 · ReceivedRecordsScreen 2) |
playlist |
2 (ReceiverPlayListScreen 1 · ReceiverMemorialPlaylistViewModel 1) |
senderdetail |
1 (SenderDetailScreen 17) |
src/test |
3 (DocumentUploadViewModelTest · MasterKeyViewModelTest · ReceiverMemorialPlaylistViewModelTest) |
심볼 97개는 세 갈래다
| 갈래 | 개수 | 실체 | 조치 |
|---|---|---|---|
| A. 이름부터 수신자 것 | 78 | receiver_verify_* 39 · receiver_sender_detail_* 18 · receiver_*_section_* 12 · receiver_download_all_* 4 · 기타 5 — 전부 string |
:feature:receiver:presentation 의 strings.xml 로 이동. 이름 무변경, 무손실 |
| B. 수신자 전용인데 이름이 애프터노트 | 9 | feature_afternote_img_book · img_letter · img_notebook · img_hero_background · img_default_profile_deceased · ic_person · ic_play_arrow · ic_settings · hero_last_greeting_caption |
이동 + receiver_* 로 리네임 (규칙 정본은 #1071) |
| C. author 화면과 실제로 공유 | 10 | 계정 섹션 6 + ic_lock · ic_playback · detail_title · load_error |
갈래마다 다르다 — 아래 참조 |
#919 가 "프리픽스 분리가 불가"라고 본 것은 C 10개에만 해당한다. 나머지 87개는 애프터노트 쪽 참조가 0건이라 그냥 옮기면 된다.
C 10개: core:ui 승격은 답이 아니다 (하나 빼고)
공유의 원인을 따라가 보면 리소스가 아니라 같은 UI 를 두 벌 그리고 있는 것이다.
| author | receiver |
|---|---|
AccountDetailScreen.AccountSection — "소셜 네트워크·비즈니스 상세 공용 ACCOUNT(아이디·비밀번호) 섹션" |
SocialNetworkReceivedDetailScreen.ReceivedAccountSection — "ACCOUNT(아이디·비밀번호) 섹션. 비밀번호 표시 토글만 보유" |
MemorialDetailScreen 영상 재생 오버레이(L373) |
MemorialReceivedDetailScreen 영상 재생 오버레이(L256) |
양쪽 다 passwordVisible 토글을 각자 들고, 같은 DetailSection·DetailInfoRow(이미 공유 중)를 쓰고, 같은 문자열 6개를 참조한다. 문자열을 core:ui 로 올리면 두 벌 중복은 그대로 둔 채 참조처만 바꾸는 것이 된다 — 차용은 사라지지만 원인은 남는다.
| 갈래 | 심볼 | 판단 |
|---|---|---|
계정 섹션 6 (section_account "ACCOUNT" · label_id · label_password · password_show/hide/mask) + ic_lock |
7 | AccountSection 을 shared/detail 로 통합(이미 공유 중인 DetailSection·DetailInfoRow 옆). 통합되면 receiver 쪽 참조가 0이 되어 이동 자체가 불필요해진다 |
ic_playback |
1 | 영상 재생 오버레이도 같은 두 벌 구조. 통합하거나, 아이콘만 core:ui 승격(도메인 어휘 없음 — #926 이 올린 4종과 같은 성격) |
detail_title "애프터노트 상세" |
1 | core:ui 부적절 — 특정 feature 의 화면 제목이다. 애프터노트 존치. 덤: 수신자 화면 TopBar 가 "애프터노트 상세"인 게 시안상 맞는지는 별건 |
afternote_detail_load_error "상세 정보를 불러오지 못했습니다." |
1 | core:ui 에 이미 core_ui_network_error_title·_description·_retry 가 있다. 그쪽 수렴 후보 — #604 와 함께 판단 |
판단 기준 — 참조 모듈 수가 아니라 "그리는 컴포넌트의 소유"
core:ui 의 strings.xml 18개가 어떻게 거기 있게 됐는지 실측하면 규칙이 나온다. 전부 core:ui 자신이 소유한 컴포넌트가 쓰는 문자열이다.
| 문자열 | 쓰는 곳 | feature 참조 |
|---|---|---|
core_ui_network_error_title·_description·_retry |
core/ui/popup/ErrorPopup.kt |
0 |
core_ui_recipient_designated·_not_designated |
core/ui/badge/RecipientDesignationBadge.kt |
0 |
core_ui_nav_item_timeletter 외 nav 4종 |
core/ui/bottombar/BottomNavTab.kt |
0 |
"타임레터"·"수신인 지정 완료" 처럼 도메인 어휘로 보이는 것도 여러 feature 가 참조해서 올라온 게 아니라, 그 문구를 그리는 컴포넌트(바텀탭·배지)가 코어에 있어서 딸려온 것이다. stringResource 로 이들을 참조하는 feature 모듈은 하나도 없다.
그래서 기준은 이렇게 선다.
- 리소스는 그것을 그리는 컴포넌트를 따라간다. 코어에 리소스를 두려면 그것을 쓰는 UI 가 코어에 있어야 한다 — refactor(receiver): 수신자 홈의 afternote R 차용 해소 — 소셜 아이콘·getIconResForType core:ui 승격, VM res id 매핑 제거 #926 이
AfternoteSourceIcon을core:ui컴포넌트로 만들고 아이콘 4종을 함께 올린 것이 이 형태다. - 두 모듈이 같은 문자열을 참조한다는 것 자체가 대개 같은 UI 를 두 벌 그리고 있다는 신호다. 참조 수를 근거로 코어에 올리면 중복 두 벌이 각자 코어를 보는 상태로 고정된다.
이 기준으로 보면 #926(코어행)과 이 이슈의 C 갈래(애프터노트 존치)가 갈리는 이유도 분명하다.
| 만나는 지점 | 결론 | |
|---|---|---|
| #926 | 수신자 홈 ↔ 애프터노트 — 홈은 애프터노트·마음의 기록·타임레터를 모으는 집계 화면이라 종류 아이콘이 도메인 경계에서 쓰인다 | 도메인 어휘 없는 그림 → core:ui 컴포넌트로 승격 |
| 이 이슈 C | 발신자 애프터노트 상세 ↔ 수신자 애프터노트 상세 — 양쪽 다 애프터노트 도메인 안이고, 모듈만 역할(author/receiver)로 갈려 있다 | 애프터노트 소유 유지. 공유 컴포저블(shared/detail)로 합치면 참조가 하나로 줄어 차용이 소멸 |
왜 고쳐야 하나
소유권이 흐려 남의 모듈 파일에서 충돌한다. 애프터노트의 strings.xml 은 항목 285개 중 118개(41%)가 receiv* 다. 수신자 문구 하나를 고치려면 애프터노트 모듈을 건드려야 하고, 반대로 애프터노트 담당이 자기 모듈 문자열을 정리하다 수신자 화면을 깬다. 수신자 모듈 자신의 strings.xml 은 22개뿐이다.
컴파일로도 테스트로도 안 잡힌다. 다른 모듈의 R 참조는 의존이 살아 있는 한 정상 컴파일된다. #1061 이 붙인 ReceiverHomeResourceKonsistTest 도 홈 패키지 한정이라, 이 23개 파일에서는 같은 차용이 지금도 새로 추가될 수 있다.
범위 밖 (같이 하지 않는다)
implementation(projects.feature.afternote.presentation)의존은 남는다. 리소스와 별개로 코드 심볼 27종을 실제로 쓴다 —reporting.AfternoteFailureStage/recordAfternoteFailure(각 6곳) ·shared.detail.*컴포저블 ·shared.model.MessageBlockUiModel·author.navigation.DetailLoading/LoadError/DesignPendingContent등. 이 이슈의 목표는 리소스 소유권 정정이지 의존 제거가 아니다.- 계측(
shouldReportInReceiverFlow·수신 스테이지)의 애프터노트 잔류는 refactor(afternote): 수신자 흐름 전체(155파일)를 :feature:receiver 로 이전 — 열람 관문 소유 해소 #919 가 별도 판단으로 미뤄 둔 몫 그대로.
완료 조건
- A 78개 · B 9개를
:feature:receiver:presentation소유로 이동(B 는 리네임 포함), 참조 23파일 + 테스트 3파일 갱신 -
AccountSection두 벌을shared/detail하나로 통합 — 계정 섹션 문자열 6 +ic_lock차용이 함께 소멸 -
ic_playback— 재생 오버레이 통합 또는core:ui승격 -
detail_title은 애프터노트 존치,afternote_detail_load_error는core_ui_network_error_*수렴 여부만 결론(실행은 refactor(core): 에러 문구 운반 타입 이원화 해소 — ErrorPayload 를 core UiText 로 수렴 #604 와 함께) -
ReceiverHomeResourceKonsistTest의 가드를 수신자 presentation 전 패키지로 확대 — 자신이 아닌 feature 의Rimport 금지 - 스크린샷 baseline 무변경 확인(리소스 이동·리네임은 렌더 결과에 영향 없음)
선행
이름 규칙의 정본은 #1071 이다. 이 이슈가 옮기는 87개는 옮기는 김에 최종 이름까지 맞춘다 — 같은 리소스를 두 번 만들지 않기 위해서다. :feature:receiver:presentation 의 프리픽스는 기존 22개가 전부 receiver_home_* 이므로 receiver_ 이고, A 갈래 78개는 이미 이 규칙을 만족해 이동만 하면 된다. #1071 1단계(리네임 0건, 설정만 추가)가 먼저 들어가면 빌드가 이를 강제한다.
PR #1061(#926) 착륙 후 착수한다 — 홈 2파일과 소셜 패턴 아이콘의 core:ui 승격 형태가 확정돼야 C 갈래 판단의 선례가 생긴다.
Activity
[-]refactor(receiver): 수신자 열람 흐름 23개 파일이 afternote 모듈 리소스를 차용 — 수신자 전용 87개가 남의 소유, #926(홈) 밖 잔여 전량[/-][+]수신자 열람 흐름 23개 파일이 afternote 모듈 리소스를 차용 — 수신자 전용 87개가 남의 소유, #926(홈) 밖 잔여 전량[/+]ci: selected 플랜 selector 클래스명 교정을 재대조한다 (#1066)
Merge pull request #1373 from Afternote/refactor/1066-receiver-resour…
1hyok commentedon Aug 29, 2026
✅ 완료 — 닫는다 (2026-08-30 실측)
PR #1373 (2026-08-28 머지, 「수신자 열람 흐름 리소스 89건을 receiver presentation 소유로」) 으로 이 이슈의 목표가 달성됐다. 이슈만 열려 있었다.
origin/develop실측:feature:receiver:presentation이com.afternote.feature.afternote.presentation.R을 import 하는 파일core.ui.R1건receiver_*문자열 소유:feature:receiver:presentation/strings.xml93건갈래 A(이름부터 수신자 것 78건)·B(수신자 전용인데 이름이 애프터노트 9건)·C(공유 10건) 처분이 모두 반영됐다.
잔여로 잡았던 것들의 현재 상태
receiver_*11건 (「미구현 화면 몫인지 확인 필요」 주석과 함께 잔류)AccountSection을shared/detail로 통합 (C 갈래)아직
feature/afternote에 남은receiver_*37건은 이 이슈 몫이 아니다receiver_mindrecord_*14 ·receiver_timeletter_*4 ·receiver_afternote_intro_line2·receiver_delivery_row_mind_records. refactor(afternote): receiver_* 잔류 미사용 문자열 11건 시안 대조 판정 — 전건 삭제 (#1066 후속) #1381 이 다룬receiver_verify_*·receiver_sender_registration_*11건과 다른 계열이라 그때 범위에 없었다.후자 20건은 #1079 (afternote 모듈 리소스 네이밍 통일) 범위다 — 그 이슈가 이 모듈의
receiver_프리픽스 잔류를 다루기로 이미 잡아 뒀고, 이 이슈가 착륙하면서 blocked 도 풀린다. 아래 코멘트로 재측정 결과를 넘긴다.