Skip to content

[fix] #573 데일리질문 생성·수정 응답의 식별자를 버리지 않는다 - #911

Merged
Sadturtleman merged 6 commits into
developfrom
fix/573-daily-question-response-id
Aug 24, 2026
Merged

Sadturtleman merged 6 commits into
developfrom
fix/573-daily-question-response-id

Conversation

@Sadturtleman

Copy link
Copy Markdown
Collaborator

📌𝘐𝘴𝘴𝘶𝘦𝘴

Closes #573

📎𝘞𝘰𝘳𝘬 𝘋𝘦𝘴𝘤𝘳𝘪𝘱𝘵𝘪𝘰𝘯

이슈의 수정 방향대로 응답을 DTO 로 받고 계약을 Result<Long> 으로 올렸습니다.

API      BaseResponse<Unit>  →  BaseResponse<DailyQuestionAnswerResponseDto>
domain   Result<Unit>        →  Result<Long>
data     requireStatus()     →  requireData().userDailyQuestionId

임시저장 성공 시 그 값을 draftId 로 들어, 같은 화면에서 이어 저장할 때 목록을 뒤지지 않고 PATCH 합니다.

📷 서버 계약 실측 (2026-08-23)

이슈의 2026-07-28 실측이 지금도 유효한지 확인했습니다.

POST /api/v1/daily-questions
<-- {"userDailyQuestionId":19,"content":"응답 계약 실측","isDraft":true,"receivers":[]}

PATCH /api/v1/daily-questions/19
<-- {"userDailyQuestionId":19,"content":"응답 계약 실측 수정","isDraft":true,"receivers":[]}

두 응답이 같은 스키마라는 것도 그대로입니다.

📷 앱 실측 — update() 경로가 식별자를 씁니다

1) 작성 화면에서 임시저장       → draft 목록 [(20, '<p>draft-then-save</p>')]
2) 재진입 후 정식 저장          → draft 목록 []      정식 목록 [(20, …)]

새 레코드가 만들어지지 않고 20 번이 그대로 정식 전환됩니다 — update() 가 그 식별자로 PATCH 했다는 뜻입니다.

🧪 회귀 가드

✔ 생성 응답에서 내 답변 식별자를 읽는다
✔ 수정 응답도 같은 스키마다
✔ 식별자가 없으면 실패로 드러난다      ← 기본값 0 으로 메우지 않는다

💬𝘛𝘰 𝘙𝘦𝘷𝘪𝘦𝘸𝘦𝘳𝘴

  • 검증: :feature:mindrecord:data:testDebugUnitTest + :feature:mindrecord:presentation:testDebugUnitTest + 양쪽 ktlintCheck + :app:assembleDebug BUILD SUCCESSFUL.
  • 이슈 노트의 "questionId 와 userDailyQuestionId 가 같은 값" 은 이번 실측에서도 같았습니다(둘 다 19). 두 값을 섞어 쓰지 않도록 DTO KDoc 에 근거를 남겼습니다. 다른 계정·날짜에서 갈리는지는 확인하지 못했습니다.
  • ⚠️ "같은 화면에서 이어 저장" 경로는 현재 앱 흐름에서 도달하지 않습니다. 임시저장에 성공하면 화면이 목록으로 빠져나가기 때문입니다(onWriteSubmitSuccess). draftId 대입은 그 흐름이 바뀌는 순간 바로 쓰이는 형태로 두었고, 지금 실제 이득은 재진입 시 update() 가 올바른 식별자로 PATCH 한다는 것입니다(위 실측).

Sadturtleman and others added 2 commits August 23, 2026 15:06
`createDailyQuestion`·`updateDailyQuestion` 의 반환 타입이 `BaseResponse<Unit>` 이라
서버가 내려주는 `userDailyQuestionId` 를 받아놓고 버렸다. 저장 직후 그 레코드를
가리키려면 목록을 다시 조회해 추측으로 골라야 한다.

응답 DTO(`DailyQuestionAnswerResponseDto`)를 만들어 API·domain·data 계약을 모두
`Result<Long>` 으로 올린다. 임시저장 성공 시 그 값을 `draftId` 로 들어, 같은 화면에서
이어 저장할 때 목록을 뒤지지 않고 PATCH 한다.

`userDailyQuestionId`("내 답변")와 요청의 `questionId`("질문")는 의미가 다르다.
관찰된 값이 같더라도 섞어 쓰지 않도록 DTO KDoc 에 적어 둔다.

식별자에는 기본값을 두지 않는다 — 없으면 저장 직후 흐름이 성립하지 않으므로 0 으로
메우지 않고 파싱에서 막는다.

Closes #573

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@OnlyReadOneBook OnlyReadOneBook left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

머지 전 1건 수정이 필요합니다. 계약·DTO·contract test 설계 방향은 좋습니다.

  1. [blocking] 인터페이스 변경이 :app 테스트 fake 한 곳을 놓쳐 머지 직후 통합 빌드가 깨집니다.

    • 이 PR이 DailyQuestionRepository.create/update를 Result<Long>로 바꿨는데(DailyQuestionRepository.kt:28,34), app/src/test/java/com/afternote/afternote_fe/screen/HomeTabViewModelTest.kt:464-469의 FakeDailyQuestionRepository override는 여전히 Result<Unit>를 반환합니다. 이 파일은 이 PR에서 변경되지 않아 머지 후에도 그대로입니다.
    • 실측: PR head(ad74e7a)에서 :app:compileDebugUnitTestKotlin 실행 →
      e: HomeTabViewModelTest.kt:464:71 Return type of 'suspend fun create(payload: DailyQuestionCreatePayload): Result<Unit>' is not a subtype of the return type of the overridden member '... Result<Long>' ...
      e: HomeTabViewModelTest.kt:469:8 Return type of 'suspend fun update(id: Long, payload: DailyQuestionUpdatePayload): Result<Unit>' is not a subtype of ...
      
    • 현재 CI가 이걸 못 잡는 이유: "Run Unit Tests"가 Gradle 이전 단계인 develop 정책테스트(supply-chain-policy.test.mjs — lint.yml setup-java 캐싱 모순, 전 PR 공통)에서 죽어 Kotlin 컴파일에 도달하지 못합니다. 본문의 검증 목록(:feature:mindrecord:* 테스트 + :app:assembleDebug)도 :app 테스트 소스는 컴파일하지 않습니다.
    • 수정: 해당 fake의 create/update 반환 타입만 Result<Long>로 바꾸면 됩니다(둘 다 본문이 unexpected(...)라 시그니처만 수정). create(payload:) 구현은 저장소에 4곳뿐이고 나머지 3곳은 이미 갱신돼 있는 걸 확인했습니다.
  2. [normal] 새 동작(draftId 보존)을 단언하는 테스트가 없습니다.

    • DailyQuestionWriteViewModel.kt:173의 draftId = if (isDraft) savedId else null이 이 PR의 목적인데, DailyQuestionWriteViewModelTest 5개 시나리오에는 create/update 성공 경로가 없습니다(fake의 19L 반환은 createCallCount == 0 단언에만 쓰임). 본문 스스로 이 경로가 현재 앱 흐름에서 도달 불가라고 밝힌 만큼 회귀를 잡을 수단은 테스트뿐입니다 — 임시저장 성공 후 draftId == savedId, 정식 저장 성공 후 draftId == null 단언 추가를 권합니다.

검증:

  • PR head에서 :feature:mindrecord:data:testDebugUnitTest + :feature:mindrecord:presentation:testDebugUnitTest 로컬 통과, :app:compileDebugUnitTestKotlin 로컬 실패(위 원문)
  • 이슈 #573 실측 스키마와 DTO·KDoc 대조, requireData()의 오류 경로(status!=200 → ApiException → Result.failure, data null 계약 위반도 예외) 확인 — 크래시 경로 없음
  • contract test가 실측 응답 원문을 쓰고 프로덕션 Json과 동일한 ignoreUnknownKeys로 미선언 필드를 무시함을 확인, userDailyQuestionId 무기본값 설계라 누락 검증이 실질적
  • create/update/getList 호출부 전수 추적(DraftListViewModel·GetHomeSummaryUseCase·DiaryWriteViewModel 파급 없음), 임시저장→onSubmitSuccess 화면 이탈 경로의 본문 서술 정확성 확인

OnlyReadOneBook and others added 2 commits August 23, 2026 16:40
#573 이 DailyQuestionRepository.create/update 를 Result<Long> 으로 올리면서
app 모듈의 fake 도 함께 따라가야 한다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@OnlyReadOneBook OnlyReadOneBook left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

반영 커밋(9f88772f) 기준 재리뷰했습니다. [blocking] 이 처방대로 정확히 수정돼 승인합니다 — HomeTabViewModelTest의 FakeDailyQuestionRepository.create/update 반환 타입만 Result<Long>로 올렸고 본문은 그대로 unexpected(…) 입니다.

검증:

  • PR head(9f88772, develop 머지 포함)에서 :app:testDebugUnitTest --tests '*HomeTabViewModelTest*' 로컬 통과 — 이전 리뷰에서 실패 원문을 남겼던 게이트(:app:compileDebugUnitTestKotlin 경유)가 green 입니다.
  • exact-HEAD CI 전부 green. develop 에 #913(lint.yml 캐시 소유권) 머지 후로는 "Run Unit Tests"가 정책테스트 단계를 넘어 실제 Gradle 컴파일·테스트까지 도달해 성공합니다 — 이전 리뷰에서 "CI가 이걸 못 잡는다"고 했던 공백 자체가 develop 쪽에서 해소된 것도 확인했습니다.
  • 실기동 QA·시안 대조 해당 없음: 이번 델타는 테스트 fake 시그니처 2줄이라 런타임 거동·UI 변화가 없습니다.

[normal](임시저장 성공 후 draftId == savedId, 정식 저장 후 null 단언 테스트)은 미반영이지만 비차단 제안으로 남깁니다 — 현재 도달 불가 경로의 회귀 방지 수단이 테스트뿐이라는 사정은 그대로라, 후속에서 붙일 가치는 여전합니다.

# Conflicts:
#	feature/mindrecord/data/src/main/kotlin/com/afternote/feature/mindrecord/data/repositoryimpl/DailyQuestionRepositoryImpl.kt
#	feature/mindrecord/presentation/src/main/kotlin/com/afternote/feature/mindrecord/presentation/viewmodel/DailyQuestionWriteViewModel.kt
#	feature/mindrecord/presentation/src/test/kotlin/com/afternote/feature/mindrecord/presentation/viewmodel/DailyQuestionWriteViewModelTest.kt
# Conflicts:
#	feature/mindrecord/presentation/src/test/kotlin/com/afternote/feature/mindrecord/presentation/viewmodel/DraftListDeleteTest.kt
@Sadturtleman
Sadturtleman merged commit 9bfbf82 into develop Aug 24, 2026
12 checks passed
@Sadturtleman
Sadturtleman deleted the fix/573-daily-question-response-id branch August 24, 2026 08:04
@github-actions

Copy link
Copy Markdown
Contributor

🚀 QA 배포 권장

QA 포인트

이 판단은 배포를 자동 실행하지 않습니다. deploy일 때 Release Distribution을 수동 실행하세요.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(mindrecord): 데일리질문 생성·수정 응답의 userDailyQuestionId 를 BaseResponse<Unit> 으로 버림

2 participants