Repository navigation
fix(mindrecord): 일기 본문 이미지도 fileKey 로 바꿔 보낸다 (#1016) - #1120
Conversation
서버는 본문 img src 에서 fileKey 를 받아 staging→permanent 로 옮기고 전체 URL 로 다시 쓴다. 전체 URL 을 그대로 보내면 그 앞에 호스트를 한 번 더 붙여 403 이 된다. 데일리질문에는 이 변환이 있었는데(#549) 일기 경로에만 없었다. 두 화면이 같은 규칙을 쓰도록 치환을 HtmlText 의 toWireContent(uploadedImageUrls) 로 올리고 데일리질문 쪽 사본을 지운다. 이미 저장된 영구 URL 은 건드리지 않는다 — 이번 작성에서 받은 URL 만 정확히 치환한다. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
서버 복구 후 같은 일기 생성 API 에 두 형태를 보내 비교했다. 전체 URL → 저장값에 호스트가 두 번 붙고 CDN 403 fileKey → permanent URL 로 정상 저장, CDN 200 어긋나 보였던 어제 관측은 #958 브랜치에서 나온 것이었다 — 그 브랜치의 에디터는 이미 fileKey 를 넣는다. assumptions 문서의 보류 항목을 근거로 대체한다. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
두 PR 이 DiaryWriteViewModel.uploadImage() 의 onSuccess 를 같이 건드려 충돌했다. 의미가 다투는 게 아니라 같은 줄을 고친 것이라, 양쪽을 그대로 합쳤다. - #1120 이 넣은 uploadedImageUrls 기억은 유지하되 담는 값을 uploaded.fileUrl 로 맞춘다 - #1120 이 추가한 DiaryWriteImageKeyTest 의 fake 를 UploadedFile 로 적응 (fileKey 는 역산 결과와 같은 값이라 단언은 그대로 통과) 역산(toUploadedFileKey) 자체를 걷어내는 것은 이 PR 범위가 아니다 — #1125 로 분리했다. 검증: :feature:mindrecord:presentation:testDebugUnitTest, :app:compileDebugUnitTestKotlin, :app:compileDebugAndroidTestKotlin BUILD SUCCESSFUL
1hyok
left a comment
There was a problem hiding this comment.
승인
일기 본문 이미지의 fileKey 변환 누락을 데일리질문과 같은 규칙 하나로 닫았다. 실측·회귀 가드 모두 충분하고, 공통화 위치(HtmlText.kt)도 맞다.
내가 따로 확인한 것
uploadedImageUrls.clear() 가 안전한지 BE 실코드로 검증했다. 이 줄이 이 PR 에서 제일 위험할 수 있는 자리였다 — 서버가 임시저장에서 승격을 건너뛴다면, 비운 뒤 이어 쓰는 흐름에서 치환이 풀려 전체 URL 이 나간다.
// DiaryService.java:48 createDiary — isDraft 분기 없이 무조건 탄다
mindRecordContentMediaService.prepareContentForSave(userId, request.getContent())
// MindRecordContentMediaService.java:24 → S3Service.promoteReferencedMediaInHtml임시저장에서도 staging→permanent 승격이 일어난다. 게다가 DiaryWriteScreen.kt:72 의 LaunchedEffect 가 Succeeded 를 보면 곧바로 onSubmitSuccess() 로 화면을 뜨므로, 「임시저장 뒤 화면에 머물다 다시 등록」 흐름이 일기에는 아예 없다. 비우는 게 맞다.
그 밖에:
Proxy로UserRepository를 세운 방식은 이 모듈의 선례를 따랐다 (WeeklyReportEmotionAnalysisTest.kt:226이 같은 모양). 새로 들인 관행이 아니다.- 브랜치가 androidTest 게이트(
:app:compileDebugAndroidTestKotlin)를 갖고 있다 — 묵은 브랜치의 숨은 부채는 없다. - 실서버 재실측은 하지 않았다. 본문의 A/B 실측이 이슈 전제와 BE 실코드 양쪽에 들어맞고, 아래 지적은 어느 쪽도 실측으로 갈리지 않는다.
시안 대조
해당 없음 — 본문 직렬화 규칙만 바뀌고 화면에 보이는 것은 그대로다.
머지 전 주의 — #1121 과 텍스트 충돌한다
두 PR 이 docs/qa/assumptions.md 끝에 각자 새 절을 붙인다. git merge-tree 실측:
CONFLICT (content): Merge conflict in docs/qa/assumptions.md
Auto-merging .../DiaryWriteViewModel.kt ← 코드는 자동 병합된다
코드는 안 부딪히고 문서만 부딪힌다. 나중에 들어가는 쪽이 해소해야 하고, 충돌 상태로 두면 그 PR 은 CI 가 아예 안 돈다. 먼저 넣을 쪽을 정해 두면 된다.
| content = state.content.toWireContent(uploadedImageUrls), | ||
| isDraft = isDraft, | ||
| todayMood = mood, | ||
| imageUrl = state.imageUrl, |
There was a problem hiding this comment.
본문은 fileKey 로 바뀌는데 이 필드만 전체 URL 그대로 나간다. 같은 요청 안에서 같은 이미지가 두 형태로 실린다.
지금은 서버가 imageUrl 을 버리므로(#1024 실측 — 요청에 실어도 저장 응답이 null) 무해하고, #1124 가 이 줄을 걷어낸다. 그래서 blocking 으로 잡지 않는다.
다만 이 PR 이 #1124 보다 먼저 develop 에 들어가면 그 사이 동안 남는다. 두 건을 붙여 머지하거나, 순서가 벌어질 것 같으면 여기서 함께 걷는 편이 낫다 — 나중에 서버가 이 필드를 받기 시작하면 방금 본문에서 고친 것과 똑같은 호스트 중복이 이 자리에서 재현된다.
Closes #1016
실측으로 전제를 확정했다
같은 일기 생성 API 에 두 형태를 보내 저장 결과와 CDN 응답을 비교했다 (2026-08-25, dev 서버).
img srchttps://…cloudfront.net/mindrecords/staging/13/bbc4…pnghttps://…cloudfront.net/https://…cloudfront.net/mindrecords/permanent/13/bbc4…pngmindrecords/staging/13/e5de…pnghttps://…cloudfront.net/mindrecords/permanent/13/e5de…png호스트가 두 번 붙는다 — 이슈가 말한 그대로다.
promoteReferencedMediaInHtml이 치환 맵에키 → 영구 URL을 먼저 넣고 순서대로replace하므로, 본문이 전체 URL 이면 그 뒷부분(키에 해당하는 substring) 만 영구 URL 로 바뀐다.무엇을 바꿨나
데일리질문에만 있던 변환(#549)을 일기에도 넣고, 두 화면이 같은 규칙 하나를 쓰도록
HtmlText로 올렸다.uploadedImageUrls.clear()— 서버가 permanent 로 옮겼으니 더는 치환 대상이 아니다.실기동 확인
에뮬레이터에서 일기에 사진을 붙여 등록했다.
diaryId 41544로 남아 있고, 호스트 중복 없이 permanent 로 옮겨졌다.회귀 가드
DiaryWriteImageKeyTest2건 — 방금 업로드한 이미지의src가 fileKey 로 나가는지, 이미 저장된 영구 URL 은 그대로 두는지.검증
testDebugUnitTest:app:assembleDebug·:app:compileDebugAndroidTestKotlindiaryId 41544)docs/qa/assumptions.md의 보류 항목은 이 실측으로 대체했다.