Skip to content

일기 임시저장이 제목·본문·기분을 모두 요구 — 미완성 보존이 불가능 #1065

Closed

Description

@Sadturtleman

📜 Overview (Required)

일기 임시저장에도 서버가 제목·본문·기분을 전부 요구한다. 미완성 내용을 보존하는 것이 임시저장의 목적인데, 정작 미완성일 때 저장할 수 없다.

실서버 실측 (2026-08-24, dev)

POST /api/v1/diary {"title":"제목만","content":"","isDraft":true,"todayMood":"SOSO"}
→ 400 {"message":"내용은 필수입니다."}

POST /api/v1/diary {"title":"","content":"<p>본문만</p>","isDraft":true,"todayMood":"SOSO"}
→ 400 {"message":"제목은 필수입니다."}

POST /api/v1/diary {"title":"제목","content":"<p>본문</p>","isDraft":true}
→ 400 {"message":"오늘의 기분은 필수입니다."}

BE 실코드도 같다 — DiaryController.create 가 @Valid 이고 DiaryCreateRequest 의 세 필드에 @NotBlank/@NotNull 이 붙어 있어 isDraft 와 무관하게 검증된다.

지금 FE 는 어떻게 하고 있나

PR #992 에서 «임시저장은 제목·본문 중 하나만 있어도 된다» 로 열었다가, 그 조건이 곧 400 이라 되돌렸다. 임시저장에도 정식 등록과 같은 세 가지를 요구한다 — 보내면 실패하는 조건을 «저장 가능» 으로 표시하면 버튼이 고장 난 것과 같기 때문이다.

기분도 마찬가지다. 종전 FE 는 미선택을 SOSO 로 채워 보냈는데, 그러면 고른 적 없는 값이 사용자 데이터가 된다 — 이어쓰기로 열면 「그냥그래」가 이미 선택돼 보이고, 주간리포트 기분 집계와 감정 분석 입력에도 그대로 들어간다. 그 폴백도 걷었다.

무엇이 필요한가

isDraft = true 일 때 검증 완화. 최소한 todayMood 는 nullable 이어야 «기분은 아직 안 정했다» 를 표현할 수 있다.

  • DiaryCreateRequest/DiaryUpdateRequest 의 @NotBlank·@NotNull 을 isDraft 조건부로
  • 또는 임시저장 전용 엔드포인트 분리

📌 Child Issue(Optional)

No response

📍 Note (Optional)

  • 이어쓰기 경로(PATCH /diary/{id})는 DiaryUpdateRequest 에 검증 애노테이션이 없어 통과한다 — 새 일기에서만 막힌다.
  • 데일리질문 임시저장은 content 만 요구해 같은 문제가 없다.
  • FE 는 서버가 완화되면 DiaryWriteUiState.missingForDraft() 를 되돌리면 된다 — 그 자리에 이 이슈 번호를 적어 뒀다.

Activity

  1. OnlyReadOneBook commented on Aug 24, 2026

    @OnlyReadOneBook
    Collaborator

    서버 이슈로 올렸습니다 — Afternote/Afternote-BE#243. 이 이슈에 blocked_by 로 걸어 뒀습니다.

    BE 이슈를 파면서 확인된 두 가지를 옮겨 둡니다.

    • 타임레터는 이미 분리돼 있습니다. BE#83 → PR fix: 마음의 기록 오류 수정 #219(2026-08-22 머지)에서 DTO 의 필수 애노테이션을 걷고 TimeLetterService.validateForScheduled(...) 로 상태별 검증을 나눴습니다. 지금은 임시저장 계약이 도메인마다 갈린 상태입니다 — 타임레터 DRAFT 는 필수값 없음, 데일리질문은 content 만, 일기만 제목·본문·기분 전부.
    • todayMood 필수는 BE#132 에서 정해진 건인데, 그때는 정식 저장만 놓고 본 결정이라 임시저장 구분이 논의되지 않았습니다. BE#243 에 그 후속임을 적었습니다.

    서버가 완화되면 DiaryWriteUiState.missingForDraft() 를 되돌리면 됩니다.

  2. Sadturtleman commented on Aug 25, 2026

    @Sadturtleman
    CollaboratorAuthor

    재확인 (2026-08-25) — 서버 동작 그대로입니다. 세 케이스 모두 같은 400 이 재현됩니다.

    {"title":"제목만","content":"","isDraft":true,"todayMood":"SOSO"}   → 400 내용은 필수입니다.
    {"title":"","content":"<p>본문만</p>","isDraft":true,"todayMood":"SOSO"} → 400 제목은 필수입니다.
    {"title":"제목","content":"<p>본문</p>","isDraft":true}             → 400 오늘의 기분은 필수입니다.
    

    FE 쪽은 이 조건을 그대로 반영한 상태이고(canSaveDraft == canSubmit), 근거를 DiaryWriteUiState KDoc 에 실측 응답째로 박아 뒀습니다. 그래서 FE 에서 더 할 수 있는 것이 없습니다 — 이 이슈는 BE 검증 완화(또는 임시저장 전용 엔드포인트)를 기다리는 상태입니다.

    BE 가 isDraft=true 에서 완화해 주면 FE 는 두 줄이면 됩니다.

    // 지금
    fun missingForDraft(): Int? = missingForSubmit()
    // 완화 후 — 제목·본문 중 하나만 있으면 저장, 기분은 nullable 로 보낸다
    fun missingForDraft(): Int? = if (title.isBlank() && content.isHtmlBlank()) R.string.… else null

    참고로 기분 폴백은 되살리지 않는 편이 좋습니다. 미선택을 SOSO 로 채우면 고른 적 없는 값이 사용자 데이터가 되고(이어쓰기 화면에 「그냥그래」가 선택된 채로 뜹니다), 주간리포트 집계·감정 분석 입력에도 그대로 들어갑니다. BE 완화 때 todayMood 를 nullable 로 받아 주시는 쪽이 맞습니다.

  3. Sadturtleman commented on Aug 27, 2026

    @Sadturtleman
    CollaboratorAuthor

    재실측 (2026-08-27, dev) — 서버 계약 그대로입니다

    이슈 등록(08-24) 뒤 3일이 지나 다시 쟀습니다. 네 조건 모두 변화 없습니다.

    보낸 것 응답
    {"title":"…","content":"","isDraft":true,"todayMood":"SOSO"} 400 내용은 필수입니다.
    {"title":"","content":"<p>…</p>","isDraft":true,"todayMood":"SOSO"} 400 제목은 필수입니다.
    {"title":"…","content":"<p>…</p>","isDraft":true} 400 오늘의 기분은 필수입니다.
    {"title":"…","content":"<p>…</p>","isDraft":true,"todayMood":null} 400 오늘의 기분은 필수입니다.
    셋 다 채움 (대조군) 200 성공

    todayMood: null 을 명시해도 같은 400 입니다 — 키 누락과 명시적 null 이 구분되지 않으므로, FE 가 「기분 미정」을 표현할 수단이 지금은 없습니다.

    FE 쪽은 더 할 일이 없습니다

    이건 FE 가 우회할 수 있는 종류가 아닙니다.

    • 완화해서 보내면 사용자가 「임시저장」을 눌렀을 때 400 이 뜹니다. 저장 가능하다고 표시해 놓고 실패시키는 것이라 지금보다 나쁩니다(fix(mindrecord): 작성·탭 상호작용 7건을 고친다 #992 에서 한 번 그랬고 되돌렸습니다).
    • 기분을 SOSO 로 채우면 고른 적 없는 값이 사용자 데이터가 됩니다. 이어쓰기에서 「그냥그래」가 선택된 채로 열리고, 주간리포트 기분 집계·감정 분석 입력에도 그대로 들어갑니다.

    현재 DiaryWriteUiState.missingForDraft() 가 세 가지를 요구하는 건 이 서버 계약을 정확히 반영한 것이고, 서버가 완화되는 순간 그 함수 하나만 되돌리면 됩니다(그 자리에 이 이슈 번호가 적혀 있습니다).

    필요한 것 — BE 변경

    DiaryCreateRequest 의 @NotBlank/@NotNull 을 isDraft 조건부로 바꾸거나(예: @Valid 그룹 분리), 임시저장 전용 엔드포인트를 두는 쪽입니다. 최소한 todayMood 는 nullable 이어야 「아직 안 정했다」를 표현할 수 있습니다.

    참고로 이어쓰기(PATCH /diary/{id})는 이미 통과합니다 — DiaryUpdateRequest 에는 검증 애노테이션이 없어서, 같은 앱 안에서 새 일기만 막히고 수정은 안 막히는 비대칭이 있습니다. 데일리질문 임시저장도 content 만 요구해 문제가 없습니다. 일기 생성 경로 하나만 다릅니다.

    BE 이슈로 올려 두는 게 맞아 보이는데, 제가 Afternote-BE 에 등록할까요? 아니면 이쪽에서 계속 추적할까요?

    실측용으로 만든 임시저장(diaryId=41552)은 삭제했습니다.

  4. changed the title [-]fix(mindrecord): 일기 임시저장이 제목·본문·기분을 모두 요구 — 미완성 보존이 불가능[/-] [+]일기 임시저장이 제목·본문·기분을 모두 요구 — 미완성 보존이 불가능[/+] on Aug 28, 2026
  5. added
    pr-open이 이슈를 구현하는 PR 이 열려 있다 — base 가 기본 브랜치가 아니어도 드러낸다
    on Sep 7, 2026
  6. removed
    pr-open이 이슈를 구현하는 PR 이 열려 있다 — base 가 기본 브랜치가 아니어도 드러낸다
    on Sep 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:mindrecord마음의 기록 기능 영역bugSomething isn't working

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions