Repository navigation
presentation 패키지 구조 통일 — 타입별 묶음을 기능별로 (모듈마다 규칙이 다름) #945
Copy link
Copy link
Closed
2 / 42 of 4 issues completedLabels
area:platformCI·빌드·릴리스·저장소 운영 영역CI·빌드·릴리스·저장소 운영 영역refactor동작 변경 없이 코드 구조·책임·경계를 개선하는 작업동작 변경 없이 코드 구조·책임·경계를 개선하는 작업
Description
presentation 모듈의 패키지 구조가 모듈마다 다르고, 타입별로 묶인 모듈에서는 화면 하나를 고치려면 3~4개 폴더를 오가야 한다. 기능(화면)별 묶음으로 통일한다.
퍼머링크 기준 커밋: 104462fd (origin/develop)
상황 — 두 패턴이 섞여 있다
A. 타입별 묶음 — mindrecord · timeletter · setting
일기 작성 하나가 4개 폴더에 흩어진다.
component/DiaryComponent.kt
model/DailyDiary.kt
screen/sender/DiaryWriteScreen.kt
viewmodel/DiaryWriteUiState.kt
viewmodel/DiaryWriteViewModel.kt
setting 의 Passkey 도 마찬가지 — 화면 4개 + ViewModel + 컴포넌트가 3개 폴더에 분산된다.
component/PasskeyListItem.kt
screen/PassKeyListScreen.kt · PassKeyMakingScreen.kt · PassKeyPasswordScreen.kt · PassKeyScreen.kt
viewmodel/PassKeyViewModel.kt
B. 기능별 묶음 — onboarding · afternote
한 폴더에 다 있다.
signup/SignUpScreen.kt
signup/SignUpViewModel.kt
signup/SignUpUiState.kt
signup/SignUpSteps.kt
signup/SignUpInputLabel.kt
afternote 는 167개 파일로 가장 큰 모듈인데 이미 B 방식이다. 소수를 다수에 맞추는 게 아니라 그 반대다.
| 모듈 | 파일 수 | 현재 방식 |
|---|---|---|
afternote |
167 | B (기능별) |
mindrecord |
75 | A (타입별) |
setting |
64 | A (타입별) |
timeletter |
38 | A (타입별) |
onboarding |
27 | B (기능별) |
문제 — 타입별 묶음 안에서도 일관되지 않다
mindrecord 기준:
| 파일 | 위치 | |
|---|---|---|
DiaryWriteUiState.kt |
viewmodel/ |
State 가 viewmodel 폴더에 |
DailyDiary.kt |
model/ |
다른 State 성 타입은 model 에 |
DiaryCard.kt |
component/ |
|
DiaryWriteScreen.kt |
screen/sender/ |
- State 가
viewmodel/에도 있고model/에도 있다. 어디를 봐야 할지 규칙이 없다 setting은viewmodel/20 ·component/20 ·screen/17 로 세 폴더가 거의 같은 크기다
이유 — 왜 기능별이 나은가
- 변경이 같이 일어난다 — 화면 하나를 수정하면 Screen · ViewModel · State 가 거의 항상 함께 바뀐다. 커밋 diff 가 한 폴더 안에 모인다
- 삭제가 쉽다 — 기능이 사라지면 폴더째 지운다. 지금은 4곳을 뒤져야 하고, 그래서 core:model 죽은 타입 6개 삭제 — 참조 0건, 살아있는 타입과 이름 혼동 #941(죽은 타입 6개) 같은 잔재가 남는다
internal이 실질적으로 작동한다 — 기능 내부 전용 타입을 폴더 밖에서 안 보이게 하려는 의도가 구조로 드러난다- 가장 큰 모듈(
afternote)과onboarding이 이미 이 방식이다
목표 구조
feature/<name>/presentation/
<기능1>/ # 예: diarywrite/
DiaryWriteScreen.kt
DiaryWriteViewModel.kt
DiaryWriteUiState.kt
component/ # 이 기능 전용 컴포넌트
<기능2>/
shared/ # 2개 이상 기능이 쓰는 것만
navigation/
지킬 것
- 깊이는 2단계까지 —
afternote는 기능별이지만author/editor/memorial/playlist로 4단계까지 간다. 그대로 두면 반대 방향으로 불편해진다. 이관 시 2단계로 제한하고,afternote도 별도 항목으로 평탄화 검토 - 진짜 공용 컴포넌트는
shared/에 남긴다 — 여러 화면이 쓰는 것을 전부 기능 폴더로 밀어넣으면 중복이 생긴다.afternote의shared/가 참고 사례 - State 위치를 규칙으로 확정 — 화면 상태(
*UiState)는 기능 폴더 안, 여러 화면이 공유하는 UI 모델만shared/model
작업 — 모듈 단위로 쪼갠다
파일 이동만이라 위험은 낮지만 diff 가 거대해진다. 한 PR 로 묶으면 #926 · #924 와 충돌 시 리베이스가 불가능해지므로 모듈별로 분리한다.
범위 조정 (2026-08-25) — 모듈별 실행분을 담당자별 이슈로 분리했다. 이 이슈는 규칙 정본과 진행만 본다.
분리 전 체크리스트는setting담당을1hyok으로 잘못 적고 있었다(설정 모듈은 박경민 몫). 실행 이슈에서 바로잡았다.
- 규칙 문서화 (목표 구조 · 깊이 제한 ·
shared/기준 · State 위치) — 선행, 1hyok · PR docs: presentation 패키지 구조 규칙 문서 신설 — 기능별 묶음으로 확정 (#945 선행) [base: develop] #1062 - presentation 을 기능별 묶음으로 이관 — 38개 파일, 타입별 4폴더 (#945 파일럿) #1086 —
feature/timeletter/presentation(38개, 가장 작음 → 파일럿) — @koongmai - presentation 을 기능별 묶음으로 이관 — 80개 파일, 타입별 8폴더 (#945 실행분) #1087 —
feature/mindrecord/presentation(80개) — @Sadturtleman - refactor(setting): presentation을 기능별 폴더로 정리한다 #1088 —
feature/setting/presentation(64개) — @koongmai -
feature/afternote/presentation깊이 평탄화 검토 (117개, 이미 기능별이므로 이관 아님) — 1hyok
순서 주의
- refactor(receiver): 수신자 홈의 afternote R 차용 해소 — 소셜 아이콘·getIconResForType core:ui 승격, VM res id 매핑 제거 #926 (app 에서 홈 분리) 와 충돌한다 — 홈이
feature:home:presentation으로 나가면서 새 모듈이 생기므로, 그 모듈은 처음부터 목표 구조로 만든다 - feat(platform): App Links URI 계약·인텐트 수신·인증 후 목적지 재개 #924 (Nav3 전환) 와 충돌한다 — Nav3 파일럿 대상이
mindrecord다. 같은 모듈을 동시에 건드리지 말 것 - 각 모듈 이관은 다른 작업이 그 모듈에 없을 때 단독 PR 로 진행
- 이동 PR 에는 파일 이동 외 변경을 섞지 말 것 (리뷰 가능성 확보)
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
area:platformCI·빌드·릴리스·저장소 운영 영역CI·빌드·릴리스·저장소 운영 영역refactor동작 변경 없이 코드 구조·책임·경계를 개선하는 작업동작 변경 없이 코드 구조·책임·경계를 개선하는 작업
Activity
OnlyReadOneBook commentedon Aug 24, 2026
선행 항목인 규칙 문서화를 #1062 로 올렸다.
규칙 5개 (문서:
docs/convention/presentation-package-structure.md)screen/·viewmodel/·component/를 1단계에 두지 않는다component·model·util)뿐 — 기능 폴더 안에 기능 폴더 금지shared/는 2개 이상 기능이 쓸 때만. 한 기능만 쓰면 그 기능 폴더로 내린다*UiState·*UiEvent·*UiEffect는 ViewModel 과 같은 폴더navigation/·reporting/은 모듈에 하나이관 PR 규칙(모듈 1개 = PR 1개, 이동 외 변경 금지, 검증 명령)도 같은 문서에 있다.
본문 표가 이슈 작성 이후 바뀌었다
efbb1256c기준으로 다시 세면 이렇다(src/main의.kt만).afternotemindrecordreceiversettingtimeletteronboardinghomeafternote167 → 116 은 집계 방식 차이가 아니라 실제 감소다. 본문 기준 커밋104462fd(8/23) 시점엔feature/receiver모듈이 없었고, 그 뒤 모듈이 분리되면서 52개 파일이 receiver 로 빠져나갔다. 같은 이유로 본문 표에receiver가 없는 것도 정상이다receiver(65개)는 이미 기능별이라 이관 대상이 아니다home은 파일 5개라 아직 폴더를 나눌 규모가 아니다. 화면이 늘면 R1 을 따르면 된다선행 조건을 blocked_by 로 걸었다
글로만 적어 두면 추적이 안 되므로 관계로 옮겼다. 이관 3건은 sub-issue(#1086·#1087·#1088) 소관이라 그쪽에 걸고, 부모에는 sub-issue 가 없는 항목만 남겼다.
afternote깊이 평탄화를 막는다. 스택 밑단 [refactor] #601 상세 데이터 계약을 타입별 모델로 분리 #821 이CHANGES_REQUESTED였는데 지적 2건은449aaf318(8/23) 로 이미 반영돼 있었고 재리뷰 요청만 안 걸린 상태였다. 걸어 뒀다 — 자식 9건이 전부 APPROVED/CLEAN 이라 이것만 들어가면 스택이 풀린다setting이관을 막는 것들. 고객지원 제공 채널과 운영 정보 확정 #783(→PR feat(setting): 고객센터 화면 구현 (#783) #882)·수신자 등록에 연락처 형식 검증·중복 검사 부재 — 문자열도 그대로 저장 #577(→PR fix(setting): 수신인 입력 검증 및 오류 처리 개선 (#577) #771)은 그 모듈을 건드리는 열린 PR 의 원 이슈이고, 참조 0건 잔재 5파일 삭제 — 도달 불가 화면 1 · 대체된 ViewModel 1 · 죽은 컴포넌트 2 #1064 는 이관 전에 지울 참조 0건 잔재다. GitHub 의존 관계는 이슈만 받아서 PR 대신 원 이슈로 걸었다PR #1051(
setting4파일)은 원 이슈 #934 가 이 모듈 밖까지 포함해서 걸지 않았다. 리뷰만 받으면 들어간다.본문 체크리스트가 sub-issue 와 어긋난다
본문은
setting담당을 1hyok 으로 적어 두었는데 sub-issue #1088 은 @koongmai 어사인이다. sub-issue 쪽이 모듈 분담(설정·타임레터 = @koongmai)과 맞으므로 그쪽이 맞다고 보고, 본문 체크리스트는 sub-issue 로 대체된 것으로 읽었다.afternote깊이 평탄화만 sub-issue 가 없어 부모에 남아 있다.선행 하나 더 — #1064
setting을 훑다가 참조 0건 잔재 5파일을 찾아 #1064 로 냈다(도달 불가 화면RecipientSetScreen, 대체된InsertPasswordViewModel+UiState, 죽은 컴포넌트 2개). 이관 전에 지우면 옮길 파일이 그만큼 줄어든다.docs: 이관 현황을 #945 실행 이슈와 담당자 정본에 맞춘다 (#945 리뷰)
Merge pull request #1062 from Afternote/docs/945-presentation-structure
OnlyReadOneBook commentedon Aug 30, 2026
추적 역할이 끝났다 — 닫는다 (2026-08-30)
이 이슈는 0825 범위 조정으로 규칙 정본과 진행만 보는 역할로 남겨 뒀다. 선행이 착륙했고 실행분은 전부 담당자 큐의 이슈로 서 있으므로 부모를 열어 둘 이유가 없다.
shared/기준·State 위치)docs/convention/presentation-package-structure.mdfeature/timeletter/presentation(파일럿)feature/mindrecord/presentationfeature/setting/presentationfeature/afternote/presentation깊이 평탄화현행 실측 (2026-08-30,
origin/develop)타입별 묶음은 세 모듈 다 그대로다. 파일 수만 갱신한다.
component35 ·viewmodel21 ·model11 ·screen10viewmodel20 ·component19 ·screen17component17 ·viewmodel11 ·screen7각 실행 이슈가 착수 시 재측정하면 된다. 규칙·근거·순서 주의(#926·#924 충돌, 이동 PR 에 다른 변경 섞지 않기)는 규칙 문서와 각 실행 이슈 본문에 옮겨져 있다.
「내 어사인인데 실제 작업은 남의 모듈」 인 부모가 큐에 남아 있으면 남은 내 일이 무엇인지 흐려진다 — #928 과 같은 처분이다.