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
{{ message }}
Repository navigation
refactor(afternote): 응답 DTO 보정형 기본값 정리 — 누락 계약을 빈 값으로 은폐하지 않는다 (#789·#790 애프터노트 판) #957
#789(mindrecord)·#790(timeletter)가 잡은 결함 — 서버가 항상 채우는 응답 키를 보정형 기본값(false·0·""·emptyList())으로 메워 계약 누락을 정상 빈 값으로 은폐 — 이 feature/afternote 에 그대로 남아 있다. PR #933 리뷰 중 전수 조사(develop 6123a68a 기준)에서 응답 DTO 보정형 기본값 13건을 확인했다.
제외(정당한 기본값): 요청 DTO 의 receivers = emptyList() 2건(AfternoteDto.kt L24·L35) — "미선택 = 빈 배열 전송" 의도라 #933 의 receiverIds 판단과 일관된다.
진행 방식
#789→#933 이 확립한 판단 절차를 그대로 따른다: 문서 required 가 아니라 실서버 응답 실측으로 각 키의 상시 존재를 확인한 뒤 기본값을 걷어내고, 키-하나당-테스트-하나의 계약 테스트로 실패 방향을 고정한다. 값이 조건부인 필드는 nullable 유지(명시적 null 파싱), 값 집합이 열린 enum 성 필드는 값만 관대하게.
즉 #932 는 #933 이 만들어 낸 상태를 근거로 그 PR 을 되돌리자고 말하는 구조였습니다.
파일별로는 mindrecord 4건만 어긋났고(WeeklyReportDto 14→3, DiaryDto 9→1, MindRecordDto 14→7, DailyQuestionDto 10→7), 나머지 10개 파일 수치와 총계 245 · Request 109 는 정확했습니다.
이에 따라 #932 에서 nullable·기본값 처방(문제 1)을 삭제하고, 계약 근거 주석과 afternote 매퍼 명명 정리만
남기도록 재작성했습니다. 이제 nullable·기본값 판단은 #676(기준) → #789 · #790 · 이 이슈(적용)로 단일 방향입니다.
이 이슈에 직접 영향 있는 것 하나 — #932 의 매퍼 항목이 feature/afternote/data/mapper/ 명명·배치 정리로 좁혀졌는데,
같은 모듈 DTO 를 이 이슈가 건드리므로 한 PR 로 묶는 편이 충돌이 적습니다.#932 작업 순서에도 그렇게 적어 뒀습니다.
이 이슈에서 13건의 기본값을 걷어내려면 필드별로 "서버가 이 키를 항상 보내는가" 를 실서버 응답으로 판정해야 합니다.
그 판정을 KDoc 으로 같이 남기면 됩니다 — 새로 조사할 일이 아니라 이미 하는 조사를 코드에 적어 두는 것입니다.
양식은 DiaryDto.kt 를 따릅니다.
같은 모듈에서 이 이슈가 안 건드리는 2파일(ReceiverAuthDto.kt · LeaveMessageBlockDto.kt)은 #932 에 남겨 뒀습니다.
보정형 기본값이 0건이라 이 이슈의 대상이 아니고(이미 non-null 로 엄격), 주석만 없는 상태입니다.
참고로 feature/afternote/data/mapper/ 명명 정리(#932)도 같은 모듈이라 이 이슈 PR 과 묶으면 충돌이 적습니다.
AfternoteDetailDto.createdAt 이 이 이슈와 직접 맞물립니다. BE 응답에 없는 필드인데 = "" 로 메워 두고, AfternoteDetailMapper.kt:39가 formatDateFromServer(createdAt) 로 포맷합니다 — 항상 빈 문자열입니다.
이 이슈가 잡은 createdAt/updatedAt= "" 7건 중 createdAt 은 기본값을 떼는 게 아니라 필드를 지우는 쪽입니다.
isDraft 는 BE 가 requiredMode = REQUIRED 로 선언해 항상 보내는데 FE 상세 DTO 에 필드 자체가 없습니다 — #808 이 필요로 하는 값입니다.
receivers 는 non-null 로 좁히면 됩니다. BE AfternoteService.getDetailAfternote() 가 카테고리 분기 전에 toList() 로 조립해 세 분기 모두 같은 값을 넣습니다 — null 분기가 없어 수신자가 없으면 빈 배열입니다.
⚠ 는 클래스명이 달라 필드 유사도로 매칭한 쌍이라 대응 관계부터 확인해 주세요. AfternoteSongDto ↔ SongRequest 처럼 요청 record 에 매칭된 건은 실제 응답 타입을 다시 찾아야 합니다.
엔드포인트는 ApiService 와 Swagger 에, nullable 근거는 BE @Schema(description) 에 이미 있습니다.
FE 가 KDoc 으로 복제하면 정본이 둘로 갈리고, BE 가 바뀔 때 FE 주석만 낡아 거짓이 됩니다.
실제로 그렇게 됐습니다 — Detail.kt 에 있던 계약 설명 주석(카테고리별 non-null 표, ReceiverRequest 는 이 필드 하나뿐(2026-08-02 Swagger 실측), name·relation·phone 은 실리지 않아 빈 문자열)이
전부 현재 계약과 어긋나 #676 에서 삭제됐습니다. receivers 는 전 카테고리 공통이고, BE #81 이 닫히며
name·relation 은 이제 옵니다.
남길 가치가 있는 주석은 명세를 봐도 모르는 FE 판단뿐입니다 — wire 이름과 도메인 이름이 다른 이유,
실패 폭 때문에 명세와 달리 기본값을 두는 결정 같은 것. 그건 Swagger 어디에도 없으니까요.
Activity
OnlyReadOneBook commentedon Aug 23, 2026
Note 의 선행 판단 사항("#676·#932 와의 조율")이 #932 쪽에서 해소됐습니다. 이 이슈는 #676 기준 확정만 기다리면 됩니다.
#932 를 실측 대조한 결과, 그 이슈의 근거 수치가
origin/develop이 아니라 머지되지 않은 PR #933 브랜치(
refactor/789-dto-defaults) 기준이었습니다. 같은 스크립트를 세 리비전에 돌린 결과입니다.6123a68a(develop)refactor/789-dto-defaults(PR #933, 미머지)즉 #932 는 #933 이 만들어 낸 상태를 근거로 그 PR 을 되돌리자고 말하는 구조였습니다.
파일별로는 mindrecord 4건만 어긋났고(
WeeklyReportDto14→3,DiaryDto9→1,MindRecordDto14→7,DailyQuestionDto10→7), 나머지 10개 파일 수치와 총계 245 · Request 109 는 정확했습니다.이에 따라 #932 에서 nullable·기본값 처방(문제 1)을 삭제하고, 계약 근거 주석과 afternote 매퍼 명명 정리만
남기도록 재작성했습니다. 이제 nullable·기본값 판단은 #676(기준) → #789 · #790 · 이 이슈(적용)로 단일 방향입니다.
이 이슈에 직접 영향 있는 것 하나 — #932 의 매퍼 항목이
feature/afternote/data/mapper/명명·배치 정리로 좁혀졌는데,같은 모듈 DTO 를 이 이슈가 건드리므로 한 PR 로 묶는 편이 충돌이 적습니다. #932 작업 순서에도 그렇게 적어 뒀습니다.
OnlyReadOneBook commentedon Aug 23, 2026
#932 에서 주석 3건을 이 이슈로 넘깁니다 — #790 에 timeletter 2건을 넘긴 것과 같은 논리입니다.
이 이슈가 손대는 세 파일이 곧 계약 근거 주석이 없는 파일입니다.
AfternoteDto.ktReceiverAfternoteDto.ktMusicDto.kt이 이슈에서 13건의 기본값을 걷어내려면 필드별로 "서버가 이 키를 항상 보내는가" 를 실서버 응답으로 판정해야 합니다.
그 판정을 KDoc 으로 같이 남기면 됩니다 — 새로 조사할 일이 아니라 이미 하는 조사를 코드에 적어 두는 것입니다.
양식은
DiaryDto.kt를 따릅니다.같은 모듈에서 이 이슈가 안 건드리는 2파일(
ReceiverAuthDto.kt·LeaveMessageBlockDto.kt)은 #932 에 남겨 뒀습니다.보정형 기본값이 0건이라 이 이슈의 대상이 아니고(이미 non-null 로 엄격), 주석만 없는 상태입니다.
참고로
feature/afternote/data/mapper/명명 정리(#932)도 같은 모듈이라 이 이슈 PR 과 묶으면 충돌이 적습니다.OnlyReadOneBook commentedon Aug 23, 2026
#676 재정의로 afternote 몫 9건이 나왔습니다 (BE
0fb9e0b실코드 대조).AfternoteDetailDtoAfternotedetailResponsecreatedAtisDraftReceivedAfternoteDetailDtoReceivedAfternoteDetailResponsecredentialsReceiverEmailAuthVerifyDtoReceiverEmailAuthVerifyResponseaccessCodeAfternoteListItemDto⚠AfternoteResponseisDraftAfternoteSongDto⚠SongRequestidAfternoteDetailReceiverDto⚠UserPatchReceiverResponseemailReceiverAuthPresignedUrlDto⚠PresignedUrlResponsecontentLengthmaxContentLengthAfternoteDetailDto.createdAt이 이 이슈와 직접 맞물립니다. BE 응답에 없는 필드인데= ""로 메워 두고,AfternoteDetailMapper.kt:39가formatDateFromServer(createdAt)로 포맷합니다 — 항상 빈 문자열입니다.이 이슈가 잡은
createdAt/updatedAt= ""7건 중createdAt은 기본값을 떼는 게 아니라 필드를 지우는 쪽입니다.isDraft는 BE 가requiredMode = REQUIRED로 선언해 항상 보내는데 FE 상세 DTO 에 필드 자체가 없습니다 — #808 이 필요로 하는 값입니다.receivers는 non-null 로 좁히면 됩니다. BEAfternoteService.getDetailAfternote()가 카테고리 분기 전에toList()로 조립해 세 분기 모두 같은 값을 넣습니다 — null 분기가 없어 수신자가 없으면 빈 배열입니다.OnlyReadOneBook commentedon Aug 23, 2026
앞서 넘긴 "계약 근거 주석" 몫을 철회합니다. 하지 않으셔도 됩니다.
엔드포인트는 ApiService 와 Swagger 에, nullable 근거는 BE
@Schema(description)에 이미 있습니다.FE 가 KDoc 으로 복제하면 정본이 둘로 갈리고, BE 가 바뀔 때 FE 주석만 낡아 거짓이 됩니다.
실제로 그렇게 됐습니다 —
Detail.kt에 있던 계약 설명 주석(카테고리별 non-null 표,ReceiverRequest 는 이 필드 하나뿐(2026-08-02 Swagger 실측),name·relation·phone 은 실리지 않아 빈 문자열)이전부 현재 계약과 어긋나 #676 에서 삭제됐습니다. receivers 는 전 카테고리 공통이고, BE #81 이 닫히며
name·relation 은 이제 옵니다.
남길 가치가 있는 주석은 명세를 봐도 모르는 FE 판단뿐입니다 — wire 이름과 도메인 이름이 다른 이유,
실패 폭 때문에 명세와 달리 기본값을 두는 결정 같은 것. 그건 Swagger 어디에도 없으니까요.
#932 는 afternote 매퍼 명명 정리만 남기고 축소했습니다.