Repository navigation
Conversation
🚧 리뷰 적체 가드 — 이 PR 을 닫습니다팀 리뷰 응답 대기 · 1건
작성자 응답 대기 · 4건
이 저장소는 팀 리뷰 응답 또는 자기 PR 의 변경요청 대응을 기다리는 PR 이 1건이라도 남아 있으면 새 PR 을 열 수 없습니다 (#1136, #1679). 각 PR 에 필요한 리뷰는 한 건입니다 — 누구든 먼저 판정을 내면 그 PR 은 모두의 목록에서 빠집니다. 승인 뒤 변경을 다시 볼 의무는 없고, 변경요청도 작성자가 같은 리뷰어에게 재요청한 뒤 실질 커밋·응답·본문 편집을 남긴 경우에만 다시 리뷰어의 몫이 됩니다. 되살리는 법위 PR 에 필요한 리뷰나 작성자 조치를 끝낸 뒤 이 PR 을 다시 여세요. 브랜치는 지워지지 않았고 커밋도 그대로입니다. gh pr reopen 1705리뷰보다 이 PR 이 급하면 |
🚧 리뷰 적체 가드 — 이 PR 을 닫습니다팀 리뷰 응답 대기 · 2건
이 저장소는 팀 리뷰 응답 또는 자기 PR 의 변경요청 대응을 기다리는 PR 이 1건이라도 남아 있으면 새 PR 을 열 수 없습니다 (#1136, #1679). 각 PR 에 필요한 리뷰는 한 건입니다 — 누구든 먼저 판정을 내면 그 PR 은 모두의 목록에서 빠집니다. 승인 뒤 변경을 다시 볼 의무는 없고, 변경요청도 작성자가 같은 리뷰어에게 재요청한 뒤 실질 커밋·응답·본문 편집을 남긴 경우에만 다시 리뷰어의 몫이 됩니다. 되살리는 법위 PR 에 필요한 리뷰나 작성자 조치를 끝낸 뒤 이 PR 을 다시 여세요. 브랜치는 지워지지 않았고 커밋도 그대로입니다. gh pr reopen 1705리뷰보다 이 PR 이 급하면 |
Sadturtleman
left a comment
There was a problem hiding this comment.
화면 구성(목록·상세·작성 3화면, 접수/답변완료 상태 구분)은 시안대로 읽히고 라우트 분리도 깔끔합니다. 다만 서버 계약이 없는 채로 프로덕션 경로에 들어가는 것이 세 갈래로 드러나 변경을 요청합니다.
지적
-
[blocking] 지어낸 문의 2건이 프로덕션 화면에 사용자 자기 이력으로 뜬다 —
InquiryUiModel.kt:51의sampleInquiries.-
src/main의 최상위val이고 프리뷰 fixture 가 아닙니다.SettingNavGraph.kt가 실제 라우트에서 그대로 넘깁니다.composable<SettingRoute.InquiryListRoute> { InquiryListScreen(inquiries = sampleInquiries, …) } composable<SettingRoute.InquiryDetailRoute> { … val inquiry = sampleInquiries.firstOrNull { it.id == id } ?: return@composable
-
설정에서 「1:1 문의」로 들어가면 쓴 적 없는 문의 2건이 보이고, 그중 하나에는 고객센터가 보낸 적 없는 답변 전문(「안녕하세요 애프터노트입니다…」)까지 붙어 있습니다. 날짜도
2025.08.09.로 고정입니다. -
프리뷰·스크린샷용이라면
@Preview곁이나 테스트 소스셋으로 옮기고, 프로덕션 라우트에는 빈 상태를 그려 주세요.
-
-
[blocking] 문의를 작성해 제출해도 아무 일도 일어나지 않는다 —
AppNavigationActions.kt의onInquirySubmitted().override fun onInquirySubmitted() { appState.navController.popBackStack() }
- 요청도 없고 오류도 없이 뒤로 갑니다. 돌아간 목록에는 1번의 가짜 2건만 있고 방금 쓴 문의는 없습니다 — 사용자는 접수된 줄 알고 답을 기다립니다.
- 이 저장소는 같은 형태를 이미 반대로 판정했습니다 — #1629 「미구현 내보내기를 성공이 아니라 실패로 닫는다」. 보낼 곳이 없으면 성공처럼 끝내지 않아야 합니다.
-
[blocking]
merge-order-guard가 red — 위 둘의 근원이다##[error]#784 이 아직 열린 #246 에 blocked — 머지 순서 위반. 선행 PR 부터 머지할 것- 가드가 저장소를 안 찍어 FE #246(닫힘)처럼 보이지만 실제 선행은
Afternote-BE#246「[feat] 고객지원 서버 계약 부재 — 1:1 문의 접수·FAQ 조회 엔드포인트 없음」이고 OPEN 입니다. 가드 판정은 맞습니다. - 접수·조회 엔드포인트가 둘 다 없어서 1·2 가 생긴 것이라, 그 계약이 오기 전에는 이 화면을 프로덕션 그래프에 붙이기 어렵습니다. 화면만 먼저 내는 것이 의도라면 그 몫을 별도 이슈로 분리해 대표 이슈를 바꾸고, 진입점은 계약이 온 뒤에 잇는 편이 안전합니다.
- 가드가 저장소를 안 찍어 FE #246(닫힘)처럼 보이지만 실제 선행은
-
[normal]
app/src/main/.../navigation/AppNavigationActions.kt은 담당 모듈이 다르다 —app/은platform(담당@1hyok)입니다. #1890 이 이 대조를 CI 게이트로 올리는 중이라 그쪽이 먼저 들어가면 red 가 됩니다. 인계·issue-assignee-exempt라벨·선행 PR 분리 중 하나로 정리해 주세요. #1578·#1706·#1710 에도 같은 사유를 남겼습니다.
|
[normal] app 모듈 소유권 — |
- InquiryListRoute/InquiryDetailRoute 가 프로덕션에서 sampleInquiries 를 실제 사용자 이력처럼 보여주던 문제를 고친다. sampleInquiries 는 InquiryScreens.kt 의 @Preview 전용 데이터로만 남기고 프로덕션 라우트에는 빈 상태를 그린다 (NoticeListScreen 이 이미 쓰고 있는 패턴과 동일). - InquiryDetailScreen 은 inquiry 를 nullable 로 받아, 조회 API 가 아직 없어 실제 항목을 찾을 수 없는 경우 "찾을 수 없음" 상태를 보여준다. - InquiryWriteScreen 의 접수 버튼은 (아직 없는) 접수 API 를 호출한 것처럼 뒤로 가지 않는다. 대신 아직 지원하지 않는 기능임을 스낵바로 알리고 화면에 남아 작성 중이던 내용을 보존한다 — #1629 에서 확립한 "미구현 기능은 성공으로 포장하지 않는다" 원칙과 동일하다. - 이제 아무것도 하지 않는 SettingNavActions.onInquirySubmitted() / AppNavigationActions 구현을 제거했다. 접수 API 가 연결되면 다시 추가한다. Afternote-BE#246 (문의 접수·조회 엔드포인트 부재) 가 열려 있는 동안에는 merge-order-guard 가 계속 이 PR 을 막을 것이다 — 이건 백엔드 이슈가 닫혀야 풀리는 별도 사안이라 이번 수정 범위에 포함하지 않았다. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
지적해주신 세 가지 중, 코드로 고칠 수 있는 두 가지를 반영했습니다. 1. 지어낸 문의 2건이 프로덕션 화면에 뜨던 문제
2. 접수해도 아무 일도 일어나지 않던 문제 3. merge-order-guard (Afternote-BE#246) 4. compile / unit test / ktlint 모두 통과 확인했습니다. 재리뷰 요청드립니다. |
1hyok
left a comment
There was a problem hiding this comment.
blocking 3건 중 둘은 head ea3f9d3 코드에서 닫힌 것을 확인했습니다.
sampleInquiries 는 InquiryScreens.kt:406 의 private val 로 내려갔고 저장소 전체 참조가 같은 파일의 @Preview 두 곳뿐입니다. 프로덕션 경로인 SettingNavGraph.kt:196 은 emptyList(), :206 은 null 을 넘기고, private 이라 그 파일에서 import 자체가 안 됩니다. 접수 버튼은 popBackStack 을 버리고 스낵바로 미지원을 알리며 작성 내용을 남깁니다. onInquirySubmitted 는 SettingNavActions 와 AppNavigationActions 양쪽에서 사라졌습니다.
남은 하나가 안 닫혔습니다. 직접 확인한 것: guard 체크가 6초에 fail 이고, gh api repos/Afternote/Afternote-FE/issues/784/dependencies/blocked_by 가 Afternote/Afternote-BE#246 을 open 으로 되돌려주며, mergeStateStatus 가 BLOCKED 입니다. 진입점은 프로덕션 그래프에 붙은 채라 리뷰에서 제시된 세 갈래(스코프 분리, 대표 이슈 교체, 진입점 후행) 중 어느 것도 적용되지 않았습니다. blocking 이 하나 열려 있어 승인하지 않습니다.
app 모듈 소유권을 issue-assignee-exempt 로 정리한 것은 맞습니다. 그 라벨은 지금 develop 에서 이미 동작합니다(validate-pr-issue-link.mjs:83, 정책 테스트 pr-issue-link-policy.test.mjs:235). #1890 을 기다릴 필요 없고, head 의 Repository Quality 가 pass 인 것이 실측입니다.
하나는 짚고 넘어갑니다. src/main 의 @Preview 는 이 PR 을 걸고넘어질 자리가 아닙니다. MainSourcePreviewKonsistTest 의 KDoc 이 setting 을 스스로 범위 밖으로 두었고, develop 의 이 모듈에 이미 @Preview 28건이 있으며, 옆 NoticeListScreen 이 표본 데이터와 emptyList() 까지 판박이입니다. 모듈이 통째로 청소할 몫이지 이 PR 이 되돌릴 것은 아닙니다.
나머지 네 건은 인라인에 달았습니다. 셋은 이 커밋이 만든 것이 아니라 첫 커밋부터 있던 것인데, #784 를 닫는 PR 이라 여기서 짚습니다.
| composable<SettingRoute.InquiryDetailRoute> { | ||
| // 문의 조회 API 가 아직 없다 (Afternote-BE#246). 실제 데이터 소스가 연결되기 전까지는 | ||
| // 지어낸 문의를 보여주는 대신 "찾을 수 없음" 상태를 그린다. | ||
| InquiryDetailScreen(inquiry = null, onBackClick = actions::onInquiryBack) |
There was a problem hiding this comment.
[normal] 상세 라우트가 도달 불가인 채로 남았습니다. InquiryListRoute 가 항상 emptyList() 를 넘기므로(:196) 목록의 LazyColumn 분기가 그려지지 않고, onInquiryClick = actions::onNavigateToInquiryDetail 로 배선은 돼 있어도 발화할 경로가 없습니다.
도달 불가 셸 자체를 지우자는 얘기는 아닙니다. 바로 위 NoticeRoute 도 notices = emptyList() 로 이미 머지돼 있고, 지우면 #784 가 요구한 화면 3종 중 하나가 없어집니다.
좁은 문제는 여기입니다. SettingRoute.kt:61 이 inquiryId: Long 을 요구하는데 이 줄은 그 인자를 한 번도 읽지 않고 무조건 inquiry = null 을 넘깁니다. 조회 API 가 생기면 반드시 고쳐야 하는 자리라 TODO 나 후속 이슈 번호를 남겨 두는 편이 낫습니다.
| ) | ||
| Spacer(Modifier.size(12.dp)) | ||
| Text( | ||
| stringResource(R.string.inquiry_add_screenshot, attachments.size, MAX_INQUIRY_IMAGES), |
There was a problem hiding this comment.
[normal] 첨부한 스크린샷이 화면에 전혀 반영되지 않습니다. 여기는 stringResource(R.string.inquiry_add_screenshot, attachments.size, MAX_INQUIRY_IMAGES) 인데 strings.xml:35 는 스크린샷 추가하기 (최대 3장) 이라 자리표시자가 없습니다. String.format 이 남는 인자를 조용히 버리므로 예외도 안 나고 개수도 안 보입니다.
attachments 를 읽는 곳이 이 버려지는 인자와 :300 의 enabled 판정뿐이라, 사진 3장을 고르면 화면은 아무 변화가 없는데 그다음부터 행이 눌리지 않고 이유가 표시되지 않습니다. 이 커밋이 만든 것은 아니지만, 미구현을 성공으로 포장하지 않는다는 이 PR 의 취지가 마지막으로 안 닿은 자리입니다.
| var type by rememberSaveable { mutableStateOf("\ud0c0\uc784\ub808\ud130") } | ||
| var title by rememberSaveable { mutableStateOf("") } | ||
| var content by rememberSaveable { mutableStateOf("") } | ||
| var attachments by remember { mutableStateOf<List<Uri>>(emptyList()) } |
There was a problem hiding this comment.
[normal] 첨부만 remember 입니다. 바로 위 제목(:221)과 내용(:222)은 rememberSaveable 이라 회전이나 프로세스 사망 복원에서 살아남는데, 첨부 목록만 사라집니다. 한 화면 안에서 보존 수명이 두 벌입니다.
선택기도 :229 의 GetMultipleContents 라 개수 제한이 걸리지 않습니다. :230 이 .take(MAX_INQUIRY_IMAGES) 로 자르므로 사용자가 5장을 고르면 3장만 남고 나머지 2장은 아무 안내 없이 버려집니다. 위 :316 지적과 합치면, 첨부는 고르는 순간부터 화면에 아무 흔적이 없습니다.
| <!-- 고객지원 --> | ||
| <string name="settings_support_faq">FAQ</string> | ||
| <string name="settings_support_inquiry">고객센터</string> | ||
| <string name="inquiry_title_bar">1:1 문의</string> |
There was a problem hiding this comment.
[normal] 새 문자열 15건이 전부 inquiry_* 인데 이 모듈의 프리픽스는 setting_ 입니다. docs/convention/resource-naming.md 의 표가 feature/setting/presentation 을 setting_(#1077)로 정하고, 문서 말미가 아직 android.resourcePrefix 가 안 걸린 모듈에도 표의 프리픽스를 쓰라고 못박습니다. 나중 리네임 PR 규모를 늘리지 않으려는 것이 이유입니다.
바로 위 :24 settings_support_inquiry 와 아래 :40 settings_support_notice 사이에 다른 프리픽스가 끼어 있는 모양이기도 합니다.
| verticalAlignment = Alignment.CenterVertically, | ||
| ) { | ||
| Text(selected, Modifier.weight(1f), style = AfternoteDesign.typography.bodySmallR) | ||
| Text("\u2304", style = AfternoteDesign.typography.bodyLargeR) |
There was a problem hiding this comment.
[normal] 드롭다운 화살표를 유니코드 글자 \u2304 로 그립니다. 본문 폰트에 그 글리프가 없으면 시스템 폴백에 맡겨져 기기마다 모양이 달라지고, 스크린 리더에는 뜻 없는 문자로 읽힙니다. core:ui 의 아이콘을 쓰는 편이 맞습니다.
같은 컴포저블에서 하나 더. :220 의 초기값 타임레터 가 :341 의 목록과 따로 하드코딩돼 있어 정본이 두 벌입니다. 목록의 첫 원소를 초기값으로 쓰면 한 벌로 줄어듭니다.
|
열린 PR 중 이 PR 과 같은 파일을 서로 다르게 고친 것이 있다. 어느 쪽이 먼저 머지되든 나중 쪽은 base 를 병합해야 통과한다 (#1750).
머지 자체는 GitHub 이 막는다 — 한쪽이 들어가면 다른 쪽은 CONFLICTING 이 되어 merge queue 에 못 들어간다. 이 코멘트는 리컨사일러가 매 실행 현재 상태로 고쳐 쓴다. 해소되면 |
설정 담당 이관 완료
이 작업은 설정 담당자
1hyok이 작성한 대체 PR #1928에서 이어갑니다. 원본 HEADea3f9d3e8ee0dbbacc45866a6070acb51da6db57와 커밋 작성 이력을 보존했고, 미해결 리뷰와 기존 검증 근거는 대체 PR에 연결했습니다. 원본은 이관에 따라 병합 없이 닫으며, 연결 이슈는 열린 상태로 유지합니다.📌𝘐𝘴𝘴𝘶𝘦𝘴
📎𝘞𝘰𝘳𝘬 𝘋𝘦𝘴𝘤𝘳𝘪𝘱𝘵𝘪𝘰𝘯
InquiryListScreen), 상세(InquiryDetailScreen), 작성(InquiryWriteScreen).SettingRoute에InquiryListRoute·InquiryDetailRoute(inquiryId)·InquiryWriteRoute를 추가하고,SettingNavActions/AppNavigationActions에 진입·뒤로가기·작성 진입·제출 콜백을 연결했습니다. 고객센터 화면의onInquiryClick = {}(no-op) 를actions::onNavigateToInquiry로 교체했습니다.inquiry_*)로 뺐습니다.Afternote-BE#246"고객지원 서버 계약 부재 — 1:1 문의 접수·FAQ 조회 엔드포인트 없음", OPEN). 문의 제공 계약 확정 후 구현 범위 재정의 #784 노트의 "서버 API가 준비되지 않은 경우 UI와 제출 계약을 분리해 작업한다"에 따라 이 PR은 화면 셸만 만들고, 목록은sampleInquiries정적 데이터, 제출 버튼은 뒤로가기만 합니다. ViewModel의 immutable state·성공/실패/로딩 표시는 백엔드 계약이 나온 뒤 별도 이슈/PR로 붙입니다.🧪 CI Test Plan
{ "androidTest": { "mode": "full", "reason": "SettingNavGraph.kt·AppNavigationActions.kt(둘 다 navigation 패키지) 에 신규 라우트 3개를 추가해 Android 런타임 경계에 닿는다. 이번 PR은 신규 계측 테스트를 추가하지 않아 selected로 좁힐 근거가 없어 full로 돌린다.", "tests": [] } }📷𝘚𝘤𝘳𝘦𝘦𝘯𝘴𝘩𝘰𝘵
문의 목록/상세/작성 3개 화면 Preview 를 파일 내
@Preview로 추가했습니다(스크린샷 테스트는 별도로 없음).💬𝘛𝘰 𝘙𝘦𝘷𝘪𝘦𝘸𝘦𝘳𝘴
InquiryWriteScreen의 문의 유형 드롭다운 항목(타임레터/마음의 기록/애프터노트/기타)이 string resource가 아니라 코드에 하드코딩돼 있습니다 — 다국어 지원 전이라 우선 넘어갔는데 필요하면 후속으로 뺄 수 있습니다.🤖 Generated with Claude Code