Skip to content

수신자 없는 임시저장을 FE가 선차단 — Figma·BE 계약과 불일치 #570

Closed

Description

@OnlyReadOneBook

📜 Overview (Required)

타임레터 임시저장이 수신자 없이는 실패하고, 실패 사유가 화면에 전달되지 않는다 (2026-07-28 13:30 에뮬 런타임 실측).

실측 — 제목만 입력하고 수신자를 고르지 않은 상태에서 "임시저장" 탭

POST /api/v1/time-letters
<-- 400 {"status":400,"code":400,"message":"수신자를 선택해주세요.","data":null}

화면에는 저장에 실패했어요. 다시 시도해주세요. 만 뜬다. 서버가 알려준 구체적 사유(수신자 미선택)가 감춰져, 사용자는 무엇을 고쳐야 재시도가 성공하는지 알 수 없다 — "다시 시도" 해도 같은 실패가 반복된다.

두 가지로 나뉜다

  1. 정책 — 임시저장은 미완성 상태를 남기는 기능인데 수신자를 필수로 요구한다. 임시저장에서도 필수인지 확인이 필요하다(서버 계약이 그렇다면 화면에서 미리 안내하거나, 임시저장은 수신자 없이 허용하도록 서버와 맞춰야 한다).
  2. 안내 — 서버가 사용자에게 보여줄 만한 문구(수신자를 선택해주세요.)를 줬는데도 일반 문구로 덮어쓴다. 서버 메시지가 사용자 친화적일 때는 그대로 노출하는 편이 낫다.

📌 Child Issue(Optional)

No response

📍 Note (Optional)

Activity

  1. OnlyReadOneBook commented on Jul 28, 2026

    @OnlyReadOneBook
    CollaboratorAuthor

    2026-07-28 13:34 추가 실측 — 원인이 하나 더 확인됐습니다.

    수신자를 선택한 뒤 제목만 채우고 임시저장하면 서버가 이렇게 거절합니다.

    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 레포에도 올렸습니다.

  2. OnlyReadOneBook commented on Aug 2, 2026

    @OnlyReadOneBook
    CollaboratorAuthor

    원인 지점을 짚어 둔다.

    서버 문구를 읽지 않고 고정 문자열로 덮는다.

    ```kotlin
    // TimeLetterWriteViewModel.kt:291
    _uiState.update { it.copy(errorMessage = "저장에 실패했어요. 다시 시도해주세요.") }
    ```

    400 응답의 message("수신자를 선택해주세요.")가 여기서 버려진다. 다만 서버 문구를 그대로 노출하는 건 5xx 내부 메시지까지 새는 경로라, 애프터노트 쪽에서 쓴 방식(안내된 4xx 거절만 서버 문구 허용, 그 외는 일반 문구)을 참고하는 게 안전하다 — #621·#655 에 같은 구조가 있다.

    본문의 "임시저장에 수신자가 필수인가" 는 별개 판단이고, 이 코멘트는 안내 경로만 짚은 것이다.

  3. added a commit that references this issue on Aug 21, 2026
  4. changed the title [-]fix(timeletter): 임시저장이 수신자 없이 400 실패 — 서버가 준 사유 대신 일반 문구만 노출[/-] [+]fix(timeletter): 수신자 없는 임시저장을 FE가 선차단 — Figma·BE 계약과 불일치[/+] on Aug 22, 2026
  5. OnlyReadOneBook commented on Aug 22, 2026

    @OnlyReadOneBook
    CollaboratorAuthor

    재개 근거 — 현행 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명 필수
    • 수신자·발송일 미지정 draft를 목록에서 시안 문구로 표시
    • 수신자 없는 DRAFT와 SCHEDULED 검증을 각각 테스트
    • 서버 실패는 SAVE_FAILED, 필수값 누락은 해당 사용자 안내로 구분

    현재 계약 기준 회귀로 보고 이슈를 재개합니다.

  6. OnlyReadOneBook commented on Aug 22, 2026

    @OnlyReadOneBook
    CollaboratorAuthor

    #763 머지 이후 상태를 develop b834c11에서 재실측했습니다 (2026-08-23, 에뮬 오프라인).

    • 제목·내용만 입력하고 임시저장 탭 → 이제 서버 400이 아니라 FE가 요청 없이 선차단합니다. TimeLetterWriteViewModel.save() 공통 검증(recipientIds.isEmpty())이 register뿐 아니라 saveDraft에도 적용돼 "수신자를 선택해주세요." 스낵바만 뜨고 POST가 나가지 않습니다.
    • 즉 본문 2번(안내 문구)은 사유가 노출되는 형태로 바뀌었지만, 1번(정책 — 임시저장에 수신자가 필수인가)은 그대로 미해결입니다. 현 제목("FE가 선차단 — 계약과 불일치")이 현재 동작과 일치함을 확인했습니다.
    • 참고로 서버 응답 모델·화면 모두 수신자 없는 DRAFT를 표현할 수 있습니다(임시저장 목록이 "수신인 : 미지정"으로 정상 렌더).
  7. changed the title [-]fix(timeletter): 수신자 없는 임시저장을 FE가 선차단 — Figma·BE 계약과 불일치[/-] [+]수신자 없는 임시저장을 FE가 선차단 — Figma·BE 계약과 불일치[/+] on Aug 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:timeletter타임레터 기능 영역bugSomething isn't working

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions