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
fix(mindrecord): 주간리포트 상단 카운트와 요약 기록일수 불일치 — diaryAmount 는 1인데 week[] 에 미포함 #590
week 는 날짜 단위가 아니라 기록 단위다. 같은 날에 일기+데일리질문이면 같은 day 가 2개 담긴다.
데일리질문 원소는 isDiary:false · emotion:null 이고, diaryId 필드에 questionId(22) 가 실려 온다.
daily-question[].date 포맷은 "2026.07.29 수" 다.
이 이슈의 가설에 대해 — diaryAmount >= 1 인데 week 에 일기 원소가 없는 조합은 여전히 재현되지 않았습니다(정상 등록·임시저장 모두 일치). 다만 QA 15번의 성립 경로는 더 구체적입니다: week 에 데일리질문 원소만 담기고 일기 원소가 빠지면count { isDiary } 가 0 이 되어 "0일" 이 나옵니다. 그 상태에서도 diaryAmount 는 1 로 표시됩니다.
원인 후보를 하나 더 붙입니다. 서버가 week[] 에 담아 보내도 클라가 버리는 경로가 있습니다.
// feature/mindrecord/data/.../dto/WeeklyReportDto.kt
@SerialName("day") val day:Int=0, // 일자는 1~31 — 0 은 도메인 밖 값
day 키가 응답에 없거나 null 이면 기본값 0 이 들어갑니다. 그러면 resolveDateInWeek(monday, 0) 이 월~일 7일 창 어디에도 매칭되지 않아 null 을 돌려주고, 그 원소는 indexWeekByDate 의 mapNotNull 에서 제외됩니다. 로그도 남지 않습니다. 결과가 이 이슈의 증상과 같습니다 — diaryAmount 는 1인데 기록일수는 0.
기본값 자체는 필요합니다. kotlinx.serialization 은 기본값 없는 프로퍼티가 JSON 에 없으면 MissingFieldException 으로 응답 전체 파싱을 실패시키므로, 기본값이 그 프로퍼티를 optional 로 만듭니다(basic-serialization.md — Optional properties). 문제는 고른 값이 도메인 밖 sentinel 이라 "서버가 안 보냄" 과 "서버가 0 을 보냄" 이 구분되지 않는다는 점입니다. Int? = null 이면 부재가 타입에 드러나 매퍼 경계에서 걸리고 로그를 남길 수 있습니다.
명세로는 갈리지 않습니다. GET /api/v1/mind-record 의 WeekRecordItem 은 diaryId·day·isDiary·emotion 에 required 목록도 nullable 표기도 없습니다(2026-08-07 실측). day 가 항상 실려 오는지가 명세에 확정돼 있지 않습니다.
서버 응답을 대조하실 때 week[] 원소에 day 키가 실제로 실려 오는지를 함께 보시면 이 경로를 배제하거나 확정할 수 있습니다. 담겨 오는데도 화면에서 빠진다면 여기가 원인이고, 아예 원소가 없다면 이 이슈의 기존 가설이 맞습니다.
서버 쪽 계약 확정(day 의 required 표기 포함)은 Afternote-BE#131 로 올렸습니다.
nullable 판단 기준 일반론은 #676 에서 다루지만, 이 DTO 는 feature/mindrecord/data 소유라 그 이슈 스코프(chore(core)) 밖입니다.
같은 날에 일기와 데일리질문이 함께 있으면 DIARY 가 이긴다 — 기록 순서와 무관하다 (데일리질문을 지웠다 다시 답변해 일기보다 나중 기록으로 만들어도 type 은 DIARY 였다).
일기가 없는 날은 DAILY_QUESTION·DEEP_THOUGHT 가 실린다. 이때 diaryId 는 각각 userDailyQuestionId·deepThoughtId 다.
임시저장은 카운트·week[] 양쪽에서 제외된다.
PATCH /diary/{id} 는 date 를 무시한다(Swagger DiaryUpdateRequest 에 date 없음). 날짜를 다른 주로 옮겨 카운트와 week[] 를 갈라놓는 경로는 없다.
그래서 "불일치" 의 정체
diaryAmount 는 레코드 수, week[] 는 날짜 수로 단위가 다릅니다. 하루에 일기를 2건 쓰면 일기 2 / 1일 이 나오는데, 이건 정상 동작입니다.
그리고 diaryAmount ≥ 1 인데 그 날이 week[] 에 담기지 않는 상태는 재현하지 못했습니다. 일기가 있으면 그 날은 언제나 week[] 에 있었습니다. QA 15번의 "일기 1 … 0일" 은 이 조건으로는 만들어지지 않아, #563(일자 매칭)·#524(데일리질문 집계) 로 이미 해소된 증상일 가능성이 큽니다.
다만, 대조 중에 같은 계열의 클라 결함을 하나 찾았습니다
countRecordedDays 가 week[] 에서 isDiary 인 날만 세고 있었습니다.
val diaryDates = aggregateWeekRecordsByDate(monday, week)
.filterValues { it.isDiary } // ← DAILY_QUESTION·DEEP_THOUGHT 원소가 여기서 버려진다
.keys
데일리질문만 있는 날은 daily-question[] 로 되살아나지만, 깊은 생각만 있는 날은 어디에서도 복구되지 않습니다. 위 표의 마지막 행 상태(깊은 생각 1건)에서 화면은 이렇게 나왔습니다.
WEEKLY SUMMARY | 8월 3주차 리포트 | 2026.08.17. - 2026.08.23.
이번 주, adamtia님은 0일의 마음을 기록하셨네요.
서버 week[] 에는 8/23 기록이 있는데 요약은 "0일" 입니다 — 이슈 제목이 말하는 "카운트와 요약 기록일수 불일치" 와 같은 뿌리입니다.
수정 범위는 방어 로직이 아니라 집계 규칙으로 정했습니다. 문구가 세는 것은 "일기를 쓴 날" 이 아니라 "마음을 기록한 날" 이므로 종류를 가리지 않습니다. isDiary 는 달력 점 표시에만 계속 씁니다. PR 을 올려 두었습니다.
수정 후 같은 서버 상태에서 0일 → 1일 로 바뀌고, 같은 날 일기를 추가해도 일기 1 / 1일 로 이중 계산되지 않는 것을 확인했습니다.
Activity
OnlyReadOneBook commentedon Jul 29, 2026
서버 대조 결과입니다 (2026-07-29 12:1x, QA 계정 dev 서버 실측).
diaryAmount와week[]는 두 경로 모두 일치했습니다 — 가설한 조합은 재현되지 않았습니다.diaryAmountweek[]isDraft:false, 07-29)[{diaryId:7, day:29, isDiary:true}]isDraft:true)임시저장은 양쪽 모두에서 제외되므로 draft 여부는 원인이 아닙니다. 정상 등록 건은 양쪽에 모두 반영됩니다.
따라서 QA 15번의 조합은 다른 조건에서만 생깁니다. 아직 안 본 후보는 주 경계(일요일/월요일 등록분), 과거 날짜 등록분, 삭제된 일기의 잔여 카운트입니다.
week가 sparse 라는 전제는 그대로입니다.미대조 — QA 당시 계정(이준혁)의 07-13 주 데이터는 재현하지 못했습니다. QA 계정에는 그 주 기록이 없습니다.
OnlyReadOneBook commentedon Jul 29, 2026
추가 실측 (2026-07-29 12:3x, QA 계정 dev 서버).
week[]는 일기 전용 배열이 아닙니다.데일리질문 답변 1건을 등록하니 같은 날에 원소가 하나 더 생겼습니다.
week는 날짜 단위가 아니라 기록 단위다. 같은 날에 일기+데일리질문이면 같은day가 2개 담긴다.isDiary:false·emotion:null이고,diaryId필드에questionId(22) 가 실려 온다.daily-question[].date포맷은"2026.07.29 수"다.이 이슈의 가설에 대해 —
diaryAmount >= 1인데week에 일기 원소가 없는 조합은 여전히 재현되지 않았습니다(정상 등록·임시저장 모두 일치). 다만 QA 15번의 성립 경로는 더 구체적입니다:week에 데일리질문 원소만 담기고 일기 원소가 빠지면count { isDiary }가 0 이 되어 "0일" 이 나옵니다. 그 상태에서도diaryAmount는 1 로 표시됩니다.미대조 — 일기 원소가 빠지는 조건 자체는 아직 못 찾았습니다.
OnlyReadOneBook commentedon Aug 7, 2026
원인 후보를 하나 더 붙입니다. 서버가
week[]에 담아 보내도 클라가 버리는 경로가 있습니다.day키가 응답에 없거나 null 이면 기본값0이 들어갑니다. 그러면resolveDateInWeek(monday, 0)이 월~일 7일 창 어디에도 매칭되지 않아 null 을 돌려주고, 그 원소는indexWeekByDate의mapNotNull에서 제외됩니다. 로그도 남지 않습니다. 결과가 이 이슈의 증상과 같습니다 —diaryAmount는 1인데 기록일수는 0.기본값 자체는 필요합니다. kotlinx.serialization 은 기본값 없는 프로퍼티가 JSON 에 없으면
MissingFieldException으로 응답 전체 파싱을 실패시키므로, 기본값이 그 프로퍼티를 optional 로 만듭니다(basic-serialization.md — Optional properties). 문제는 고른 값이 도메인 밖 sentinel 이라 "서버가 안 보냄" 과 "서버가 0 을 보냄" 이 구분되지 않는다는 점입니다.Int? = null이면 부재가 타입에 드러나 매퍼 경계에서 걸리고 로그를 남길 수 있습니다.명세로는 갈리지 않습니다.
GET /api/v1/mind-record의WeekRecordItem은diaryId·day·isDiary·emotion에required목록도nullable표기도 없습니다(2026-08-07 실측).day가 항상 실려 오는지가 명세에 확정돼 있지 않습니다.서버 응답을 대조하실 때
week[]원소에day키가 실제로 실려 오는지를 함께 보시면 이 경로를 배제하거나 확정할 수 있습니다. 담겨 오는데도 화면에서 빠진다면 여기가 원인이고, 아예 원소가 없다면 이 이슈의 기존 가설이 맞습니다.서버 쪽 계약 확정(
day의required표기 포함)은 Afternote-BE#131 로 올렸습니다.nullable 판단 기준 일반론은 #676 에서 다루지만, 이 DTO 는
feature/mindrecord/data소유라 그 이슈 스코프(chore(core)) 밖입니다.Sadturtleman commentedon Aug 23, 2026
서버 응답 대조 결과 (2026-08-23, release)
이슈가 "미대조" 로 남겨 둔 부분을 실서버로 확인했습니다. 조건을 하나씩 바꿔가며
GET /mind-record응답을 직접 찍은 결과입니다.week[]의 실제 규칙week[][][{diaryId:9741, day:23, type:"DIARY", emotion:"HAPPY"}][{diaryId:9745, ...}]— 여전히 1개[{diaryId:23, day:23, type:"DAILY_QUESTION", emotion:null}][{diaryId:1, day:23, type:"DEEP_THOUGHT", emotion:null}]정리하면:
week[]는 하루 1개 (최대 7개). 레코드 배열이 아니라 날짜 배열이다.diaryId하나만 실린다.type은DIARY였다).DAILY_QUESTION·DEEP_THOUGHT가 실린다. 이때diaryId는 각각userDailyQuestionId·deepThoughtId다.week[]양쪽에서 제외된다.PATCH /diary/{id}는date를 무시한다(SwaggerDiaryUpdateRequest에date없음). 날짜를 다른 주로 옮겨 카운트와week[]를 갈라놓는 경로는 없다.그래서 "불일치" 의 정체
diaryAmount는 레코드 수,week[]는 날짜 수로 단위가 다릅니다. 하루에 일기를 2건 쓰면일기 2/1일이 나오는데, 이건 정상 동작입니다.그리고
diaryAmount ≥ 1인데 그 날이week[]에 담기지 않는 상태는 재현하지 못했습니다. 일기가 있으면 그 날은 언제나week[]에 있었습니다. QA 15번의 "일기 1 … 0일" 은 이 조건으로는 만들어지지 않아, #563(일자 매칭)·#524(데일리질문 집계) 로 이미 해소된 증상일 가능성이 큽니다.다만, 대조 중에 같은 계열의 클라 결함을 하나 찾았습니다
countRecordedDays가week[]에서isDiary인 날만 세고 있었습니다.데일리질문만 있는 날은
daily-question[]로 되살아나지만, 깊은 생각만 있는 날은 어디에서도 복구되지 않습니다. 위 표의 마지막 행 상태(깊은 생각 1건)에서 화면은 이렇게 나왔습니다.서버
week[]에는 8/23 기록이 있는데 요약은 "0일" 입니다 — 이슈 제목이 말하는 "카운트와 요약 기록일수 불일치" 와 같은 뿌리입니다.수정 범위는 방어 로직이 아니라 집계 규칙으로 정했습니다. 문구가 세는 것은 "일기를 쓴 날" 이 아니라 "마음을 기록한 날" 이므로 종류를 가리지 않습니다.
isDiary는 달력 점 표시에만 계속 씁니다. PR 을 올려 두었습니다.수정 후 같은 서버 상태에서
0일 → 1일로 바뀌고, 같은 날 일기를 추가해도일기 1 / 1일로 이중 계산되지 않는 것을 확인했습니다.fix(mindrecord): 기록일수를 일기만으로 세지 않는다
Sadturtleman commentedon Aug 24, 2026
보강 — 깊은 생각이 기획에서 완전히 제거되기로 하면서 PR #946 의 집계 규칙을 한 번 더 좁혔습니다.
위 대조에서 «깊은 생각만 있는 날이 0일로 샌다» 를 결함으로 적었는데, 그 기능 자체가 없어지므로 이제는 세지 않는 것이 맞습니다. 서버는
week[].type=DEEP_THOUGHT와deepThoughtAmount를 계속 내려주지만 앱은 무시합니다.수정 방향은 «종류를 가리지 않고 센다» → «깊은 생각만 제외하고 센다» 로 바꿨고, 종류 판단은 매퍼가
countsAsRecord로 접어 도메인에 올립니다.isDiary는 달력 점 표시 전용으로 남습니다.대조 결과 자체(«
week[]는 하루 1개인 날짜 배열», «diaryAmount ≥ 1인데week[]미포함은 재현되지 않음»)는 그대로입니다.