You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
POST /api/v1/time-letters
--> {"title":"draft QA letter","status":"DRAFT","receiverIds":[9]}
<-- 400 {"status":400,"code":1304,"message":"정식 등록 시 제목, 본문, 발송일시는 필수입니다."}
클라는 status:"DRAFT" 를 정확히 보냈는데도 정식 등록 검증이 적용됩니다. 본문과 발송일시까지 모두 채우자 200 으로 저장됐습니다(id 29, status DRAFT).
즉 임시저장에도 제목·본문·발송일시·수신자가 전부 필수라 정식 등록과 조건이 같고, 안내 문구는 "정식 등록 시" 라고 나와 오해를 부릅니다. 서버 쪽 판정이 필요해 보여 BE 레포에도 올렸습니다.
400 응답의 message("수신자를 선택해주세요.")가 여기서 버려진다. 다만 서버 문구를 그대로 노출하는 건 5xx 내부 메시지까지 새는 경로라, 애프터노트 쪽에서 쓴 방식(안내된 4xx 거절만 서버 문구 허용, 그 외는 일반 문구)을 참고하는 게 안전하다 — #621·#655 에 같은 구조가 있다.
본문의 "임시저장에 수신자가 필수인가" 는 별개 판단이고, 이 코멘트는 안내 경로만 짚은 것이다.
changed the title [-]fix(timeletter): 임시저장이 수신자 없이 400 실패 — 서버가 준 사유 대신 일반 문구만 노출[/-][+]fix(timeletter): 수신자 없는 임시저장을 FE가 선차단 — Figma·BE 계약과 불일치[/+]on Aug 22, 2026
BE main@4d891ea2도 DRAFT는 수신자 없이 저장할 수 있고, SCHEDULED만 수신자를 필수로 검증합니다.
반면 FE develop@b834c110은 save() 진입에서 상태와 무관하게 recipientIds.isEmpty()를 차단합니다. TimeLetterWriteViewModelTest도 “수신자 없는 임시저장 - 생성 API를 호출하지 않음”을 기대해 현재 불일치를 고정하고 있습니다.
PR #763이 과거 서버 400을 FE 선차단으로 바꾸며 이 이슈를 닫았지만, 현재 서버 계약과 최종 시안 기준에서는 수신자 없는 DRAFT가 다시 요구됩니다.
#763 머지 이후 상태를 develop b834c11에서 재실측했습니다 (2026-08-23, 에뮬 오프라인).
제목·내용만 입력하고 임시저장 탭 → 이제 서버 400이 아니라 FE가 요청 없이 선차단합니다. TimeLetterWriteViewModel.save() 공통 검증(recipientIds.isEmpty())이 register뿐 아니라 saveDraft에도 적용돼 "수신자를 선택해주세요." 스낵바만 뜨고 POST가 나가지 않습니다.
즉 본문 2번(안내 문구)은 사유가 노출되는 형태로 바뀌었지만, 1번(정책 — 임시저장에 수신자가 필수인가)은 그대로 미해결입니다. 현 제목("FE가 선차단 — 계약과 불일치")이 현재 동작과 일치함을 확인했습니다.
참고로 서버 응답 모델·화면 모두 수신자 없는 DRAFT를 표현할 수 있습니다(임시저장 목록이 "수신인 : 미지정"으로 정상 렌더).
Activity
OnlyReadOneBook commentedon Jul 28, 2026
2026-07-28 13:34 추가 실측 — 원인이 하나 더 확인됐습니다.
수신자를 선택한 뒤 제목만 채우고 임시저장하면 서버가 이렇게 거절합니다.
클라는
status:"DRAFT"를 정확히 보냈는데도 정식 등록 검증이 적용됩니다. 본문과 발송일시까지 모두 채우자 200 으로 저장됐습니다(id 29, status DRAFT).즉 임시저장에도 제목·본문·발송일시·수신자가 전부 필수라 정식 등록과 조건이 같고, 안내 문구는 "정식 등록 시" 라고 나와 오해를 부릅니다. 서버 쪽 판정이 필요해 보여 BE 레포에도 올렸습니다.
OnlyReadOneBook commentedon Aug 2, 2026
원인 지점을 짚어 둔다.
서버 문구를 읽지 않고 고정 문자열로 덮는다.
```kotlin
// TimeLetterWriteViewModel.kt:291
_uiState.update { it.copy(errorMessage = "저장에 실패했어요. 다시 시도해주세요.") }
```
400 응답의
message("수신자를 선택해주세요.")가 여기서 버려진다. 다만 서버 문구를 그대로 노출하는 건 5xx 내부 메시지까지 새는 경로라, 애프터노트 쪽에서 쓴 방식(안내된 4xx 거절만 서버 문구 허용, 그 외는 일반 문구)을 참고하는 게 안전하다 — #621·#655 에 같은 구조가 있다.본문의 "임시저장에 수신자가 필수인가" 는 별개 판단이고, 이 코멘트는 안내 경로만 짚은 것이다.
Merge pull request #763 from Afternote/fix/570
[-]fix(timeletter): 임시저장이 수신자 없이 400 실패 — 서버가 준 사유 대신 일반 문구만 노출[/-][+]fix(timeletter): 수신자 없는 임시저장을 FE가 선차단 — Figma·BE 계약과 불일치[/+]OnlyReadOneBook commentedon Aug 22, 2026
재개 근거 — 현행 Figma·BE 계약과 FE 선차단 불일치
2026-08-22 기준 현행 최종 Figma의 임시저장 목록은 수신자와 발송일이 미지정인 항목을 명시적으로 표현합니다.
지정되지 않았습니다.-BE
main@4d891ea2도DRAFT는 수신자 없이 저장할 수 있고,SCHEDULED만 수신자를 필수로 검증합니다.반면 FE
develop@b834c110은save()진입에서 상태와 무관하게recipientIds.isEmpty()를 차단합니다.TimeLetterWriteViewModelTest도 “수신자 없는 임시저장 - 생성 API를 호출하지 않음”을 기대해 현재 불일치를 고정하고 있습니다.PR #763이 과거 서버 400을 FE 선차단으로 바꾸며 이 이슈를 닫았지만, 현재 서버 계약과 최종 시안 기준에서는 수신자 없는 DRAFT가 다시 요구됩니다.
완료 조건
DRAFT는 수신자 없이 생성 가능SCHEDULED는 기존처럼 수신자 최소 1명 필수SAVE_FAILED, 필수값 누락은 해당 사용자 안내로 구분현재 계약 기준 회귀로 보고 이슈를 재개합니다.
OnlyReadOneBook commentedon Aug 22, 2026
#763 머지 이후 상태를 develop
b834c11에서 재실측했습니다 (2026-08-23, 에뮬 오프라인).TimeLetterWriteViewModel.save()공통 검증(recipientIds.isEmpty())이register뿐 아니라saveDraft에도 적용돼 "수신자를 선택해주세요." 스낵바만 뜨고POST가 나가지 않습니다.[-]fix(timeletter): 수신자 없는 임시저장을 FE가 선차단 — Figma·BE 계약과 불일치[/-][+]수신자 없는 임시저장을 FE가 선차단 — Figma·BE 계약과 불일치[/+]