진행률 검증 보고에서 확정한 결정 반영 (사용자 위임):
- [계산 수정] 하루 단위 다짐의 주/월 집계를 **방향 무관 수행일 기록만** 합산 — 목표량(scaledTarget)이 수행일 수 환산인데 '이하 유지'만 비수행일 기록까지 값에 섞여 분모·분자가 어긋나던 비대칭 해소 (월수금 1시간 이하 다짐이 목요일 시청으로 한도 초과 표시되던 문제). atLeast의 하루 기여 캡·마감 창 클립은 기존 유지
- [표시 수정] 수행일 아닌 날(요일·날짜 다짐의 쉬는 날, 기간 밖 custom)의 '하루' 게이지를 '수행일 아님' 상태로 — 쉬는 날 기록은 주/월 집계에 안 잡히는 값이라 퍼센트(예 133%)로 보여주면 "오늘 채웠다"는 오해 유발. 목표 탭 행·모음 카드(문구+빈 바), 위젯 ③(문구·누적값 숨김)·②(— 대시)·④(링 흐림, 스냅숏 isRestDay), 시리 '오늘' 조회("오늘은 수행일이 아니에요") 공유. 워치·잠금화면 점은 공간 제약으로 수치 유지(문서화)
- [의도 확정·유지] atMost 하루 게이지의 환산 한도 페이스 경고 / 다짐 생성 이전 기록 인정 / 월 경계 주 혼입 / 적용일 없는 달 0% / custom 종료 후 게이지 — CLAUDE.md §4.2에 트레이드오프로 명시
- 검증: -progressSelfTest 37건 ALL PASS(E 비수행일 제외·M 비대칭 수정·N 기간 밖 판정 신규), 목표 탭 스크린샷(달리기 월수금: 하루 '수행일 아님'/주간 0%/월간 7%), 위젯 미리보기 렌더 무결, Debug·Store·워치 3스킴 빌드 성공
- 도움말 '진행률 읽는 법' 전면 보강(수행일 집계·페이스 캡·이하 유지 이분법+하루 경고) en/ja 완비, 신규 키 2종('수행일 아님', 시리 응답) IOS·위젯 카탈로그 클린(763/213키)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
- 보고된 버그: 주 2회 다짐을 목요일에 1회 수행 → 목표 탭 하루 진행률 350% (1 ÷ 주목표 2/7). 주기와 다른 span의 환산 목표는 페이스 가이드일 뿐인데 초과분까지 퍼센트로 표기되던 왜곡
- 수정: spanProgress에서 '이상 달성'이면서 환산 목표 span일 때 값을 목표에서 캡 (usesScaledTarget 분기) — 자기 주기 span(하루 다짐의 '하루' 200% 등)과 특정 기간 다짐(환산 없음)은 초과 표기 유지, '이하 유지'는 값 무캡(UI 초과 판정·페이스 경고 유지). 게이지(ratio)·달성 판정·연속·목표 종료 판정은 원래 캡·별도 경로라 무영향 — 바뀌는 것은 퍼센트 문구뿐
- 검증 도구 신설: -progressSelfTest (DEBUG) — 인메모리 컨테이너에 12시나리오·33검증(보고 케이스, 주간/월간/요일 스케줄/마감/atMost/특정 기간/잔존 deadline/무기록 + 목표 합산 회귀) 구성해 손계산 기대값과 대조, ALL PASS. 설정·날짜 고정이라 언제 실행해도 동일 판정
- 화면 확인: 목표 탭 '꾸준한 달리기'(주 2시간) 하루 233%→100%, 주간 67%·월간 30% 유지, 매일 다짐 117%/133%(자기 주기)·atMost·마감 다짐 표기 불변
- 도움말 '진행률 읽는 법'에 페이스 기준 설명 추가(en/ja 완비), CLAUDE.md §4.2 규칙·§14 인자 기재
- §2.3 l10n 루틴 강화: stringsdata를 Objects-normal/arm64로 한정 — x86_64·Release 등 낡은 구성 파일이 수정 전 문구를 계속 추출시키는 오염 발견·수정
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
- CSV 열 이름도 언어별 현지화 (파일명 현지화 b17a199의 후속, 사용자 결정) — 스프레드시트에서 열 이름은 곧 UI. 값의 rawValue(time/count, inProgress 등)는 데이터라 언어 무관 유지
- 기존 키 최대 재사용(이름/시각/수량/메모/방향/종료일/꼬리표/즐겨찾기/시작/종료 + '추적 방식' — ko 헤더만 '추적방식'→'추적 방식'으로 공백 하나 추가됨), 신규 10키(행동id/만든날/초/내용/시작일/상태/달성기준%/대상/주기/목표량) en/ja 완비 — 카탈로그 761키 missing/stale 0
- 검증(시뮬레이터 실헤더): en "id,Name,Tracking type,Tags,Favorite,Created" 등 5파일, ja "id,名前,計測方式,タグ,お気に入り,作成日" 등 5파일, ko 회귀 정상. Debug·Store 빌드 성공
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
- 내보내기 파일명을 언어별로 현지화 — 수신 환경(PC·클라우드·메일)이 한글 파일명을 지원하지 않을 수 있음 (사용자 결정). ko는 기존 그대로("하루다님-기록-…"), en/ja는 라틴 접두 "HaruDanim-" + 그 언어의 종류 단어 (History/記録, Diary/日記, Stats/統計, Actions/アクション 등)
- 대상 전부: 기록·통계 리포트 PNG(ExportSnapshot.fileName + 슬러그 3종), 일기 PDF·스티치 PNG(슬러그 3종 포함), CSV 5종(행동·목표·다짐은 기존 키 재사용, 시간기록·횟수기록 신규 키). CSV 헤더는 데이터로 보고 한국어 유지
- 카탈로그 신규 11키 en/ja 완비(751키 missing/stale 0), CLAUDE.md §7에 규칙 기재
- 검증(시뮬레이터 실파일명): en CSV 5종 "HaruDanim-Actions/TimeRecords/CountRecords/Goals/Quest.csv", en 리포트 "HaruDanim-History-2026-07-16.png", iPad en 일기 "HaruDanim-Diary-2026-07-15~2026-07-16.pdf"(기간 슬러그), ko 회귀 "하루다님-행동.csv" 등 5종 그대로. Debug·Store 빌드 성공
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
- ⑥ 현재 진행 중 위젯의 종료 버튼 탭이 인텐트 대신 앱 열기로 새던 원인 = 버튼 라벨(정지 아이콘)에 붙어 있던 invalidatableContent() — §10에 문서화된 금지 패턴(invalidatable 래스터 서브트리는 별도 레이어로 분리돼 Button(intent:) 히트 영역에서 빠짐, ③ 링 실기기 버그와 동일 기전)을 이 버튼만 어기고 있었음
- 아이콘의 invalidatableContent() 한 줄 제거 (외형·레이아웃 불변) — 탭 접수 깜빡임 피드백은 바로 옆 타이머 텍스트의 invalidatableContent가 기존대로 담당(①③과 같은 패턴). 소형·중형 대표 카드·대형 나열 행 모두 같은 NowRunningStopButton이라 한 번에 수정
- CLAUDE.md §10 경고문에 ⑥ 재현 사례 병기
- 검증: Debug·Store·워치 3스킴 빌드 성공, 위젯 미리보기 렌더 수정 전과 동일. 히트 영역 자체는 홈 화면 UI라 실기기 탭 확인 필요
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
- 페이스 편집기에 3번째 목표부터(다짐은 첫 목표의 2개까지만) 안 뜨던 원인 = recommendations()의 prefix(2) 하드캡 — 워치는 컴플리케이션 파라미터 편집 UI가 없어 추천 목록이 곧 선택지의 전부라, 캡에 걸린 목표·다짐은 페이스에 추가할 방법 자체가 없었음 (보고된 13개 = 현재현황 1 + 목표 2×3기간 + 다짐 2×3기간과 정확히 일치)
- 목표·다짐 달성률 둘 다 상한 제거: 진행 중 목표 전부 × 3기간, 다짐 전부 × 3기간 나열
- 워치 앱이 스냅숏을 적용할 때 invalidateConfigurationRecommendations() 호출 추가 — 이후 아이폰에서 목표를 새로 만들어도 시스템 임의 재조회를 기다리지 않고 목록에 자동 반영
- CLAUDE.md §11에 "추천 목록 = 선택지 전부, 상한 금지" 규칙 명시
- 검증: 워치·Debug·Store 3스킴 빌드 성공, 워치 심 -complicationPreview 렌더 정상 (추천 목록 자체는 페이스 편집 UI라 헤드리스 확인 불가 — 실기기 확인 필요)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
- §6.4 연속 달성에 명시: 미래 시각 기록(수동 입력)은 진행률·게이지에 즉시 반영되지만 연속 계산은 now까지만 집계 — 선기록으로 연속이 미리 쌓이지 않게 하는 의도된 동작(사용자 결정, 고치지 말 것)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
- 모음 탭 그룹에 도움말 2개 추가: '짧은 기록 무시'(측정 시작·종료 다음 — 3초~1분 기준, 위젯·워치·시리 종료에도 적용됨을 안내), '기록에 메모 남기기'(길게 누르기 메뉴 다음 — 행동별 토글·건너뛰기·기기 로컬 저장·기록 탭 노란 표시·수정 시 메모 편집 안내)
- 새 문자열 3키 en/ja 번역 채움 (설정 항목명은 기존 카탈로그 번역 'Ignore short sessions'/'Show note prompt when recording' 그대로 인용, 제목 '짧은 기록 무시'는 기존 키 재사용)
- 검증: -helpPreview ko/en 스크린샷 — 두 주제 모두 의도한 위치에 렌더
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
- §14 설정/기타 행에 코드에는 있으나 표에 빠져 있던 -widgetRenderMode accented|vibrant 보충
- §14 seedDemo 기대값(아침 루틴 연속 1일)에 실행 시각 전제 명시 — 시드 기록이 고정 시각이라 오전 7:30 이전 실행 시 연속 0일이 정상 (전수 점검 중 새벽 실행에서 확인)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
- 기록 탭 목록의 진행 중 세션 표기 "진행 중"이 문자열 보간 안 String 리터럴이라 영어·일본어 UI에 한국어로 노출되던 것 수정 — String(localized:)로 기존 카탈로그 키 재사용 (시뮬레이터 en "In progress" / ko "진행 중" 스크린샷 검증)
- 같은 패턴 3곳 동일 수정: 꼬리표 편집 미리보기 행 "미리 보기"(String 삼항), 시리 다짐 엔티티 부제 "목표 없음"(?? 폴백), 워치 행동 목록 제목 "꼬리표 없음"(String 파라미터) — 전부 기존 번역 키 재사용이라 카탈로그 변경 없음(xcstringstool sync 무변화 확인)
- 검증: Debug·Store·워치 3스킴 빌드 성공, 시리 인텐트 스모크 테스트 10/10, streak-dump 수치 손검산 일치
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
- §1에 '현재 상태 (2026-07-16)' 행 추가 — 기능 동결, RC 커밋 f05e611, 실기기 이상 없음, 사업자 승인 대기
- §2.2 자주 쓰는 시뮬레이터에 워치 UDID 2종(watchOS 11.5 / 26.2) 기재
- 문서 버전 v2.1 (2026-07-16)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
출시 전 최종 점검에서 발견한 문서 어긋남 정리:
- §2.1/2.2: 워치·위젯 개별 스킴 존재 명시 + 워치 UI 검증 방법(워치 스킴 →
watchOS 26 시뮬레이터 + -complicationPreview) 추가 — 이번에 실제 검증한 경로
- §10 ③: 누적값 라벨 설명에 마감 시각 다짐의 창 안 값(spanRawValue) 예외 반영
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
다짐 편집기를 여는 검증용 런치 인자 추가 (DEBUG 전용, §14 관례).
마감 시각이 있는 다짐을 우선 열어 새 마감 UI(토글·시간 선택·footer)의
스크린샷 검증이 CLI로 가능해진다. 없으면 첫 다짐의 편집기를 연다.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
하루 단위 다짐에 '마감 시각까지만 집계' 옵션 추가 (최소판 설계):
- 모델: Quest.deadlineMinutes(-1=없음) 필드 1개 — CloudKit 안전(기본값), 주기가
하루 단위가 아니면 값이 남아도 무시(hasDeadline이 주기·범위를 함께 검사)
- 의미론: 마감 = 그날 집계 창의 끝. dayMeasurementRange(forKey:) 단일 구현을
주기 범위(current/judgment)·주/월 span 하루 루프(spanValue)·연속 버킷팅
(perDayValues)·위젯 누적 라벨(spanRawValue)·일기 카드가 공유한다.
원본 기록은 불변 — 마감 뒤 기록은 남되 그 다짐에만 미집계. 시간형은 기존
겹침 클리핑이 마감을 걸친 세션을 부분 인정(추가 코드 0). '이하 유지'는
마감까지 한도 안이면 그날 달성으로 고정.
- 경계 규칙: 마감은 그 논리적 하루(24h) 안에서 그 시계 시각의 등장 지점 —
하루 시작보다 이른 시각은 다음 달력일 새벽, 시작과 같은 시각은 +24h(온전한
하루)로 0길이 창이 수학적으로 불가능(에디터 검증 불필요, 오류 상태 없음)
- 의도된 최소화: '마감 지남' 전용 표시 없음(게이지 값이 마감 시점에 연속이라
위젯 타임라인 마감 경계 불필요 — 위젯·워치·시리는 코드 변경 0으로 자동 일관),
연속 달성은 값 클리핑만(오늘 놓친 끊김 반영은 내일부터 — 유예 규칙 유지),
주간/월간/기간 마감은 미지원
- UI: 다짐 에디터 토글+시간 선택(하루 단위만, footer 설명), 주기 문구에
"· 오전 8:00까지" 표기(목표 탭·시리 요약·CSV 자동 반영), 일기 카드
"하루 목표 · 오전 8:00까지", 도움말 항목 추가, ko/en/ja 번역
- 검증: seedDemo에 마감 다짐 시드(창 안/밖/어제 실패 케이스) — 하루 100%
(창 밖 기록 포함 시 200%가 되는 함정 통과), 주간 29%(=2/7)·월간 6%(=2/31)
수기 계산과 정확 일치, streak-dump 연속 1일(어제 실패로 끊김) 확인,
마감 없는 다짐 전부 기존 수치 유지(경로가 hasDeadline 가드로 완전 동일),
일기 카드 1회/1회(원본 합계는 그대로), 영어 로케일 "By 8:00 AM" 렌더,
Debug·Store 빌드 성공, 카탈로그 9종 missing/stale 0
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
루트 .gitignore의 **/xcuserdata/ 규칙보다 먼저 커밋돼 계속 추적되던
Expiranner의 Xcode 사용자 상태 파일(UserInterfaceState.xcuserstate,
xcschememanagement.plist)을 인덱스에서만 제거 — 로컬 파일은 유지되고
이후 변동이 git status에 잡히지 않는다.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
'하루 시작 시간'이 자정보다 늦게 설정된 경우의 논리적 하루 경계 버그 2건:
- 달력: monthAnchor(자정 키)를 monthRange(containing:)에 그대로 넣어
매달 1일에 이전 달 그리드가 그려지고 헤더(현재 달)와 불일치했다.
키를 dayRange(forKey:).lowerBound로 실제 시각으로 변환해 전달
(기록·통계 탭이 쓰는 기존 패턴). monthSummary 카운트도 동일 수정.
- 내보내기: '날짜 지정'(MultiDatePicker)의 선택일(자정 Date)을 dayKey(for:)에
넣어 전날 일기가 내보내졌다. DiaryEntry.dayKey가 "달력일의 자정"이므로
선택 달력일의 startOfDay를 키로 직접 사용 — 하루 시작 시간이 몇 시든 안전.
'구간 지정'도 같은 원리로 통일(표시된 달력일 = 내보내는 일기 날짜 보장).
CLAUDE.md §4.1에 재발 방지 규칙 추가: 자정 키를 dayKey(for:)/~Range(containing:)에
재투입 금지, 달력 UI 선택일은 startOfDay를 키로 직접 사용.
검증: 하루 시작 00:00/06:00/18:00 전부 수치 검증(수정 전 06:00에서 이전 달·전날
재현 확인), Debug·Store 빌드 성공, iPad 시뮬레이터에 하루 시작 06:00 주입 후
달력(7월 헤더·그리드 일치, 마커 2건)과 내보내기 시트("일기를 쓴 날 2일") 확인.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
전체 코드 점검 중 발견한 번역 카탈로그 정리:
- IOS 카탈로그의 stale 항목 2건 삭제 — "다른 행동 %lld개도 함께 추적 중"은
위젯 타깃 전용 문자열(위젯 카탈로그에 번역 완료 상태로 존재)이고,
"프리미엄 상태 (테스트)"는 DEBUG 전용 문구
- DEBUG 프리미엄 토글 라벨을 Text(verbatim:)으로 — 개발용 문구는 카탈로그로
추출하지 않는 컨벤션(§15-6)에 맞춤 (같은 섹션의 다른 문구와 동일)
- CLAUDE.md l10n 루틴 수정: 카탈로그마다 자기 타깃의 stringsdata만 sync하도록
경로 필터 추가 — 전 타깃을 한꺼번에 넣으면 위젯 전용 문자열이 IOS 카탈로그에
미번역으로 재유입되던 오염의 근본 원인 제거 (이번 stale의 발생 경로)
검증: 전 카탈로그(9개) missing/stale 0건, 카탈로그 의미 diff = stale 2건 삭제뿐
(번역 변경 없음), Debug·Store 스킴 빌드 성공
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
페이지 추가 시트의 '내 양식' 목록에서 한 쪽짜리 양식(사진·1쪽 PDF) 행이
왼쪽(썸네일·이름)만 눌리고 오른쪽 절반은 반응하지 않던 문제 수정.
DiaryTemplateRowLabel이 내용물 폭만 차지해 plain 버튼의 contentShape도
그 좁은 라벨에만 적용됐던 것 — 라벨을 frame(maxWidth: .infinity)로 행
전체 폭으로 넓힌 뒤 contentShape(Rectangle())를 적용해 행 어디를 눌러도
동작하게 했다. 여러 쪽 PDF 행(NavigationLink)은 원래 전체 폭이 눌려
변경 없음.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
③ 다짐 진행률 위젯에서 링·중앙 아이콘 영역을 누르면 인텐트 대신 앱이
열리던 실기기 버그 수정. 원인은 링 ZStack(도형+아이콘)에 붙인
invalidatableContent() — invalidatable로 표시된 래스터 서브트리는 별도
레이어로 분리되며 Button(intent:)의 히트 영역에서 빠져, 셀 단위
contentShape(.rect)로도 살아나지 않는다. 정상 동작이 확인된 ① 위젯과
같은 패턴(텍스트 값에만 invalidatableContent)으로 통일하고, 탭 접수
피드백은 퍼센트·누적값 줄이 계속 담당한다. CLAUDE.md §10에 도형·아이콘
ZStack 금지 규칙 추가.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
접근성 감사 ③ — 전 화면의 아이콘 전용 버튼과 텍스트 없는 시각
요소에 보이스오버 라벨 부여 (시각 UI 변화 없음):
- 모음 탭: 행동 버튼 셀을 label(이름)+value(측정 중/오늘 누적)로
한 덩어리 낭독 — 아이콘·타이머가 따로 읽히지 않음. 진행 중 행의
정지 버튼 "측정 종료".
- 기록 탭: 날짜 이동 화살표(이전/다음 날짜), 내보내기, 기록 필터,
필터 칩 해제 버튼. 타임테이블의 색 블록·횟수 점은 "행동 이름 +
시각(구간)" verbatim 라벨로 낭독 가능하게.
- 통계 탭: 기간 이동 화살표(이전/다음 기간), 내보내기, 통계 필터,
필터 해제.
- 행동/꼬리표/목표 탭: + 추가 버튼(행동/꼬리표/목표 추가), ⋯ 메뉴.
- 일기: 달 이동 화살표(이전/다음 달), 내보내기, ⋯ 메뉴, 기분 타일
("오늘 기분"), 할 일 삭제 버튼.
- ⑥ 현재 진행 중 위젯: 종료 버튼 "측정 종료".
- CLAUDE.md §15에 컨벤션 추가: 아이콘 전용 버튼 accessibilityLabel
필수, 복합 셀은 label+value 한 덩어리, 텍스트 없는 시각 요소는
verbatim 라벨.
신규 문구 9종 ko/en/ja 번역 + 위젯 카탈로그 '측정 종료' 번역 복사
(전 카탈로그 missing 0/stale 0). Debug·Store 빌드 성공, 접근성
수식어는 시각 렌더링에 영향 없음(스모크 런치 확인). 실기기에서
보이스오버 켜고 핵심 흐름(행동 시작/종료·날짜 이동) 낭독 확인 권장.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
배포 잔여 ①-(2) + 성능 백로그 ② 처리:
1) ITSAppUsesNonExemptEncryption=NO (IOS/Info.plist)
OS 표준 암호화(HTTPS·iCloud)만 사용 — 면제 선언으로 업로드마다
뜨는 수출 규정 질문 생략. 빌드 산출물 plist에서 키 확인.
2) 기록·통계·일기 기록 조회를 날짜 범위로 제한 (전량 로드 제거)
예전에는 4개 화면(기록/통계/일기 요약/일기 내보내기)이 모든
TimeSession·CountEntry를 @Query로 올려 메모리에서 걸렀다 —
기록이 수만 건으로 쌓이면 탭 진입·날짜 이동이 느려지는 구조.
- HistoryRecordsView 신설: 선택 날짜가 속한 '주' 범위만 조회
(목록·타임테이블 두 모드를 한 쿼리로 커버). 하루 경계 걸침·
진행 중 세션은 "시작 < 범위끝 AND (종료 없음 OR 종료 > 범위
시작)" 겹침 조건으로 포함. 날짜가 바뀌면 새 조건으로 재생성
(SwiftData 동적 쿼리 패턴). 내보내기 시트도 이 범위 데이터 사용.
- StatsChartsView 신설: 기간(하루/주/월) 범위 조회 + **1회 버킷
집계**(StatsData) — 조회된 기록을 splitByDay로 한 번만 순회해
행동별·하루별 버킷을 만들고 모든 카드(꺾은선·막대·표·꼬리표
집계)가 공유. 카드마다 Aggregator로 전체 기록을 재순회하던
O(카드×행동×기록) 비용 제거. 집계 규칙은 기존과 동일.
- DiarySummaryPage: 해당 날짜 범위만 조회하는 init 추가.
- DiaryExportSheet: 전량 @Query 대신 렌더 대상 날짜별 on-demand
fetch로 전환.
3) -seedBulk DEBUG 인자 신설: 과거 500일 약 1만 건(세션 2,032 +
횟수 8,039 실측) 생성 — 규모 검증용.
검증: 변경 전/후 스크린샷 비교 — 주간 타임테이블(자정 걸침 세션
포함)·월간 통계 차트가 픽셀 단위 동일(집계 등가성), 벌크 1만 건
상태에서 월간 통계 즉시 렌더 + 벌크 시리즈 정상 표시. Debug·Store
빌드 성공, 카탈로그 missing 0/stale 0(신규 문구 없음). CLAUDE.md
§1·§6.5·§6.6·§14 갱신.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
배포 잔여 ①-(1) 처리 — 자동 갱신 구독 심사 필수 요건:
- Docs/PRIVACY.md 신설: 개인정보처리방침 ko/en/ja 3개 국어.
핵심 내용 — 개인정보 수집 없음(서버·계정·광고·분석 SDK 없음),
모든 데이터는 기기 + 사용자 본인의 iCloud 비공개 DB에만 저장
(개발자 접근 불가), 결제는 App Store 처리, 권한(캘린더·사진·
알림) 용도 명시, 데이터 삭제 방법, 문의처 songyc.eng@gmail.com.
→ github.com/notalentprogrammer/HaruDanim 저장소 main 브랜치에
PRIVACY.md로 업로드하면 앱에 박힌 링크가 활성화된다.
- 결제 화면(PremiumView)에 '약관과 정책' 섹션 추가:
개인정보처리방침(위 GitHub URL) + 이용약관(Apple 표준 EULA —
커스텀 EULA 미제공 시 자동 적용되는 표준 계약으로 갈음, 3.1.2 허용).
외부 링크 화살표 표시, 신규 문구 4종 ko/en/ja 번역.
- CLAUDE.md §1 배포 잔여 갱신 (남은 코드 측 작업은
ITSAppUsesNonExemptEncryption 1건, ASC 등록 시 앱 설명에도
두 링크 기재 + 앱 개인정보 보호 '데이터 수집 안 함' 선택 메모).
검증: Debug·Store 빌드 성공, iPad 시뮬레이터 결제 화면에서
섹션·링크·푸터 표시 확인. 카탈로그 missing 0 / stale 0.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
재분석에서 나온 잔여 항목 일괄 처리:
1) 판정 하루 키 엣지 (A)
judgmentReference가 종료일 '정오'를 경유해 논리적 하루를 찾던
것을 달력일 키 직접 조회로 변경 — '하루 시작 시간'을 12시 이후로
설정한 경우에도 판정 범위가 전날로 밀리지 않는다.
2) 주기 중간 종료 판정 (B — 설계 결정: 경과일 비례)
종료 판정 전용 QuestProgress.judgment(asOf:) 신설, 판정 평균
(questAchievementRatio)이 current() 대신 사용:
- 값은 기준 시점까지의 누적으로 제한 — 종료일 이후 같은 주기의
기록이 판정에 섞이지 않음
- 주간/월간/특정 기간 다짐의 목표량·한도를 주기 내 경과일 비율로
축소 — 수요일에 끝나는 목표의 주간 다짐이 남은 4일치 미달로
깎이지 않고, '이하 유지' 한도도 같은 비율이라 대칭적으로 공정
- 하루 단위 다짐은 축소 없음 (그날 목표는 온전히 채워야 달성)
- 수동 종료(manualFinish)도 같은 함수를 타므로 주중 수동 종료의
주간 다짐이 공정하게 판정됨. 표시 연산(combinedSpanRatio·
spanProgress)은 불변.
검증: 주간 2시간 다짐 목표를 주 시작일(월)에 종료 →
화요일 기록 40분이 배제되고 비례 목표(≈17분) 기준으로 판정됨을
DB에서 확인 (처음 실패는 '설치 직후 첫 실행 인자 무시' 시뮬레이터
특성이 원인 — 코드 문제 아님, §2.2 문서화된 사항).
3) 양식 렌더 트레이드오프 (C)
- 백그라운드 렌더 실패 시 renderedScale을 되돌려 다음 기회(줌·
재표시)에 재시도되게 함
- 썸네일 겸 첫 표시 플레이스홀더 해상도 320→512px — 본 렌더
도착 전의 흐릿함 완화 (저장 증가는 수십 KB 수준)
- 양식 관리의 사용 중 페이지 수를 행마다 재스캔하지 않고 1회 집계
빌드: Debug·Store·워치 3스킴 성공. CLAUDE.md §4.3에 주기 중간
종료 판정 규칙 추가. 신규 사용자 문구 없음(카탈로그 변경 없음).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
전체 재분석에서 확정한 4건 + 양식 개선 2건:
1) 목표 자동 판정 기준 시점 (핵심 수정)
기존에는 판정이 "실행되는 시점의 현재 주기" 기준이라, 종료일
며칠 뒤에 앱을 열면 목표 기간 밖의 데이터로 달성/미달성이
갈렸다. 이제 자동 판정(evaluateIfEnded)은 **종료일이 속한
논리적 하루의 마지막 순간**(judgmentReference) 기준 — 늦게
실행해도, 종료일을 과거로 고쳐도 종료일까지의 기록으로 판정.
(하루 시작 시간 설정으로 기준이 미래가 되는 경우 now로 상한)
수동 종료는 종료일 없는 목표 전용이므로 기존대로 "지금" 기준.
목표 편집 시 종료일 변경 처리: 진행 중 목표는 저장 즉시 판정,
완료된 목표의 종료일을 바꾸면 '진행 중'으로 재개 후 재판정
(미래/없음 → 진행 중 복귀, 다른 과거 날짜 → 그 시점 기준 재판정).
검증: -endGoalYesterday로 어제 종료 → 종료일 기준 '달성' 판정 확인.
2) 워치 컴플리케이션 지역화 2건
- 다짐 달성률 rectangular의 기간 라벨("하루/주간/월간")이 String
파라미터라 미추출 → en/ja에서 한국어 노출 → String(localized:)
- 빈 상태 문구("목표 없음"/"다짐 없음") 동일 문제 → 추출 + 워치
앱/워치 위젯 카탈로그에 en/ja 번역 추가 (타깃별 stringsdata로
sync — 카탈로그 오염 없음, 전 카탈로그 missing 0)
3) 배포 체크리스트: CloudKit 프로덕션 스키마 배포 항목을 CLAUDE.md
§1에 추가 (DiaryTemplate 등 새 레코드 타입은 출시 전 대시보드
Deploy Schema to Production 필수)
4) 일기 양식 렌더 개선
- 첫 렌더 비동기화: 저장된 썸네일을 플레이스홀더로 즉시 깔고
본 렌더(2×)를 백그라운드로 — 복잡한 벡터 PDF도 페이지 넘김이
걸리지 않음
- 비활성 페이지 고해상도 강등: 화면 밖 페이지는 래스터를 2×로
상한(allowsHighResolution) — TabView가 이웃 페이지를 유지해도
양식 여러 장의 메모리 사용을 절약, 활성 복귀 시 원래 배율 복원
검증: 양식 페이지 2× 프로그램 줌에서 점 노트 선명(회귀 없음),
시드 필기 페이지 획 유지 확인.
빌드: Debug·Store·워치 스킴 모두 성공. 도움말(목표 판정 문구
갱신 — 종료일 기준·재판정 규칙 안내)과 CLAUDE.md §4.3 갱신,
문구 수정 stale 1건 삭제 및 ko/en/ja 번역 완료.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
일기 노트 페이지 양식(속지) 기능 (합의된 설계 그대로):
- 모델: DiaryTemplate 신설(원본 externalStorage — 여러 쪽 PDF도
통째 1개만 저장 + pageCount) + DiaryPage.templateID/
templatePageIndex(기본값 있는 새 필드, uuid 문자열 참조 —
CloudKit 규칙·동기화 순서에 안전). 스키마에 등록.
- 양식 관리: 달력 툴바에서 진입 — PDF(파일, ≤20MB)·사진 가져오기,
이름 변경·삭제(사용 중 페이지 수 경고 → 빈 캔버스 폴백, 필기 보존),
첫 쪽 썸네일 저장. 쪽 상한 24쪽(초과분 안내).
- 페이지 추가: 양식이 있으면 [빈 캔버스/줄 노트/내 양식] 선택 시트,
여러 쪽 PDF는 2단계 쪽 썸네일 선택(지연 생성). 양식이 없으면
기존처럼 즉시 추가 — 흔한 경로의 반응성 유지.
- 렌더: 페이지 논리 좌표(768×1024)에 aspect-fit — 필기 좌표계 불변.
PDF는 벡터 원본을 보존하고 줌 종료 시 현재 배율로 백그라운드
재래스터(펜슬 캔버스 선명도 훅에 함께 연결 — 확대해도 흐림 없음).
이미지는 가져올 때 긴 변 3072px 리샘플(필기 래스터 상한 3×와 동일).
양식 페이지는 줄 노트 토글 숨김(상호 배타), 양식만 깔린 페이지도
작성함 취급(hasContent). PencilKit 캔버스 코드는 건드리지 않음.
- 내보내기(PDF/PNG)에도 양식 배경 동일 반영.
검증(iPad 시뮬레이터, -diarySeedTemplate 등 신규 DEBUG 인자):
양식 관리·페이지 선택 시트·양식 페이지 렌더(2× 프로그램 줌에서
점 노트 선명) 스크린샷 + 이미지 내보내기 산출물에 양식 포함 확인.
Debug·Store 빌드 성공, 신규 문자열 22종 ko/en/ja(missing 0).
도움말 '나만의 양식(속지)' 항목 추가, CLAUDE.md §3·§6.7·§14 갱신.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
일기 요약 페이지 개선 2건:
1) 캘린더 일정 블록 가시성
기존 옅은 채움(0.14)+실선 외곽선은 배경과 겹쳐 잘 안 보였다.
구분 방향은 유지하되(꼬리표 색과 캘린더 색이 같아도 헷갈리지 않게)
구분 수단을 '농도'에서 '스타일'로 변경 — 채움을 0.3으로 올려
또렷하게 하고, 행동 블록(불투명 채움)과는 점선 테두리(1.5pt)로
구분한다. 화면과 일기 내보내기(PDF/PNG)가 같은 뷰를 쓰므로 함께 반영.
2) '이 날의 목표' 필터
카드 우상단에 타임테이블 필터와 같은 모양의 필터 버튼 추가 —
그날 진행 중인 목표 중 보고 싶은 것만 선택(숨긴 개수 노란 배지).
선택은 날짜별로 DiaryEntry.hiddenGoalIDs(uuid 문자열, 기본값 있는
새 필드 — CloudKit 규칙 준수)에 저장되어 기기 간 동기화에 안전.
시트는 전체 선택/해제 + 개별 체크(캘린더 일정 선택과 동일 패턴),
열람 전용(프리미엄 만료)에서는 버튼 숨김, 빈 엔트리 정리 조건에도
목표 필터 선택 보존 추가. 모두 숨기면 안내 문구 표시.
검증: Debug·Store 빌드 성공, iPad 시뮬레이터에서 점선 캘린더 블록·
필터 버튼·팝업(첫 목표 숨김 → 카드 제외 + 배지 1) 스크린샷 확인.
신규 문자열 ko/en/ja 번역(missing 0, 문구 수정 stale 1건 삭제).
DEBUG 인자 -diaryHideFirstGoal/-diaryShowGoalFilter 추가.
도움말(일정·필터 항목)과 CLAUDE.md(§3·§6.7·§14) 갱신.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
전체 코드 최종 점검(보고)에서 지시받은 A·B·D 항목 처리:
A. 행동 수정 시 추적 방식 변경 잠금
기존 행동을 수정할 때 추적 방식(시간↔횟수) 피커가 활성화되어
있어 도움말("추적 방식은 바꿀 수 없으니")과 어긋났고, 바꾸면
기존 기록이 화면·통계에서 보이지 않는 것처럼 되는 문제.
→ 수정 모드에서 피커 비활성 + "만들 때만 선택할 수 있어요"
푸터 안내(ko/en/ja). 생성 시에는 기존과 동일.
B. 주차 라벨 지역화 2건
- 통계 탭 월간 주차별 꺾은선 x축 "N주차"가 String(localized:)
없이 하드코딩 — en/ja에서 한국어 노출 (내보내기와 불일치)
- ⑤ 행동 통계 위젯 주 단위 라벨 "N주" — 같은 문제 + 앱과 표기
불일치 → 둘 다 기존 번역 키 "%lld주차"(Week %lld/第%lld週) 사용
D. 결제 화면 기능 목록에 '제어 센터에서 실행' 항목 추가(ko/en/ja,
도움말·CLAUDE.md와 일치) + Widgets/InfoPlist.xcstrings의
CFBundleName을 IOS와 동일하게 shouldTranslate=false 처리.
C(시리 문구 미번역 의심)는 오탐 확인 — AppShortcuts 카탈로그는
stringSet(발화 변형) 구조로 ko/en/ja 모두 translated 상태.
검증: Debug·Store 빌드 성공, 영어 실행 통계 월간 화면에서
"Week 1~5" 표시 확인, 결제 화면에 제어 센터 항목 표시 확인,
전 카탈로그 missing 0·stale 0. CLAUDE.md §6.2 갱신.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
새 홈 위젯 ⑥ '현재 진행 중'(HaruNowRunningWidget, 소형/중형/대형):
- 측정 중이 아니면 빈 상태 안내("지금 측정 중인 행동이 없어요")
- 측정이 시작되면 대표 행동(설정 '대표 시간 기준' — 다이나믹
아일랜드와 같은 규칙)의 꼬리표 색 배경 위에 이름·시작 시각·
실시간 타이머(Text(style:.timer))·종료 버튼을 표시
- 여러 개 측정 중이면 소형/중형은 "+N개 함께 추적 중", 대형은
함께 측정 중인 행동을 줄로 나열하고 각각 종료 가능(4개 초과분은
"외 N개"), 대표 하나뿐이면 오늘 누적(실시간)·시작 시각 카드
- 종료는 기존 RunActionIntent(시간형 토글) 재사용 — 짧은 기록
무시 규칙·프리미엄 게이트·히트 영역(contentShape) 규칙 동일 적용
- 타임라인은 ①과 같은 예산 전략(주기 폴링 없음, 날짜 경계 안전망),
탭 즉시 피드백(invalidatableContent), 틴트/클리어 렌더링 모드 대응
- 갤러리 미리보기는 측정 중이 아니어도 샘플로 모습 표시
검증: Debug·Store 빌드 성공, 앱 내 위젯 미리보기(-widgetPreview,
앵커 R/RL/RM/RE)로 소·중·대형/여러 개/빈 상태 스크린샷 확인.
l10n: 신규 문자열 ko/en/ja 번역(IOS·Widgets 카탈로그 missing 0,
stale 0 — 문구 수정으로 생긴 stale 1건 삭제, 잘못 stale로 남아
있던 위젯 전용 키 3건은 정상 상태로 복구). 도움말 위젯 항목과
CLAUDE.md §10에 ⑥ 추가.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
다른 기기(아이폰↔아이패드)에서 측정을 시작/종료해도 사용 중인
기기에는 반영되지 않고, 모음 탭 새로고침 버튼을 눌러도 그대로이던
버그 수정. 앱을 나갔다 들어와야만 반영되던 증상의 원인.
원인: 푸시 엔타이틀먼트(aps-environment)는 있었지만
UIBackgroundModes에 remote-notification이 없어 CloudKit의
"데이터 바뀜" 무음 푸시가 앱에 전달되지 않았다. Core Data+CloudKit은
이 푸시로 가져오기(import)를 트리거하므로, 없으면 앱 실행/포그라운드
복귀 때만 가져온다. 새로고침 버튼은 로컬 스토어 재조회일 뿐이라
가져오기 전에는 옛 데이터만 보였다.
수정: iOS 타깃에 IOS/Info.plist 신설(UIBackgroundModes:
remote-notification)하고 INFOPLIST_FILE로 지정 — 생성 Info.plist
(GENERATE_INFOPLIST_FILE=YES)와 병합된다. IOS 동기화 그룹에
membershipException을 추가해 plist가 리소스로 중복 복사되지 않게 함.
검증: Debug·Store 빌드 성공, 두 빌드 산출물 Info.plist에
UIBackgroundModes=[remote-notification]과 기존 생성 키(표시 이름·
Live Activity) 병합 확인, 시뮬레이터 콜드 스타트 정상. 기기 간
동기화 도착은 실기기 2대에서 확인 필요.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
Xcode가 카탈로그를 다시 저장하며 생긴 포맷 변화(콜론 앞 공백,
키 정렬 순서)만 반영. 키 추가/삭제 0, en/ja 번역 값 변경 0을
스크립트로 비교 확인함.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
- 매장 선택 → 연/월 → 월 캘린더(날짜별 제품 사진 썸네일) → 날짜 상세 플로우로 전면 재작성
- 스캔 플로우: 촬영 → 재촬영/사용 → 그 달 날짜만 선택 → 저장 후 카메라 자동 복귀 (손전등 지원)
- 날짜 상세 다중 선택 삭제 (전체 선택/해제 + 일괄 삭제 확인)
- 다크 전용 민트 테마, SwiftData 모델(Store ↔ ProductRecord, 원본+썸네일 분리 저장)
- 밝은 민트 앱 아이콘(SVG 원본 포함) + 런치 스크린/인앱 스플래시
- CLAUDE.md 새 구조 기준으로 재작성
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
인터랙티브 위젯(①행동 실행·③다짐 진행률)에서 셀의 일부 지점을
누르면 인텐트가 실행되지 않고 앱이 열리던 버그 수정.
원인: .plain 스타일 Button은 라벨의 투명한 영역(Spacer로 벌어진
공간, 여백, 링 안쪽)을 탭 판정에서 제외하는 경우가 있어, 해당
지점의 탭이 버튼에 잡히지 않고 위젯 기본 동작(앱 열기)으로 샜다.
수정: 두 위젯의 버튼 라벨 끝에 .contentShape(.rect)로 히트 영역을
셀 프레임 전체로 명시 — 아이콘·글자·프로그레스 링은 물론 셀 안
빈 공간까지 어디를 눌러도 인텐트가 실행된다. 시각적 변화 없음.
(③의 꼬리표 대상 다짐 셀은 표시 전용이라 기존대로 앱 열기)
검증: Debug·Store 빌드 성공, 위젯 미리보기 스크린샷으로 레이아웃
무영향 확인. CLAUDE.md §10에 히트 영역 규칙 추가.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
전체 점검에서 발견한 저위험 문제들 일괄 수정:
- 워치 실행 명령 처리 경로에 ControlCenter.reloadAllControls() 추가
(DataChange.commit과 동일 경로 유지 — 워치에서 시작/종료 시
아이폰 제어 센터 토글이 낡은 상태로 남던 문제)
- 컴플리케이션 전용 전송 상태 키에 측정 시작 시각 포함
(같은 행동을 종료 직후 디바운스 안에 재시작하면 상태 변화로
인식하지 못해 컴플리케이션 타이머가 갱신되지 않던 엣지)
- 설정 탭 버전 표기를 하드코딩("1.0") 대신 번들
CFBundleShortVersionString에서 읽도록 변경
- '대표 시간 기준' 설명의 낡은 문구 "(Live Activity 지원은 추후
추가 예정)" 제거 — 실제 용처(다이나믹 아일랜드·잠금화면·워치
컴플리케이션)로 갱신, en/ja 번역 포함
- 카탈로그 stale 항목 22개 정리 (IOS 20 + Widgets 2 — 과거 문구
수정 때 남은 죽은 키), CLAUDE.md l10n 루틴에 stale 청소 단계 추가
- CLAUDE.md 남은 배포 작업에 코드 측 잔여 2건(약관 링크,
ITSAppUsesNonExemptEncryption) 명시
검증: Debug·Store·워치 3스킴 빌드 성공, 전 카탈로그 missing 0,
인텐트 스모크 테스트 10개 통과, 스트릭 덤프 정상(시작일 하한 유지),
설정·모음 탭 스크린샷 확인.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
아이패드 일기 노트에서 필기 후 핀치줌하면 획이 사라지고, 다시 그리는
동안엔 잠깐 보였다가 획을 떼면 또 사라지던 버그 수정.
원인: 줌 배율이 바뀔 때마다 SharpPencilCanvasView가 PencilKit 내부의
모든 서브레이어에 contentsScale 변경 + setNeedsDisplay()를 강제했는데,
PencilKit의 획 타일 레이어는 렌더러가 contents를 직접 채우는 방식이라
setNeedsDisplay()가 기존 픽셀만 지우고 다시 그려 주지 않음. 그리는
동안엔 라이브 렌더로 보이다가 canvasViewDrawingDidChange →
applySharpness에서 다시 지워짐.
수정: 배율 적용을 뷰 수준 contentScaleFactor 재귀로 한정하고 레이어
직접 조작·setNeedsDisplay 제거 — PencilKit이 자기 타이밍에 새 배율로
재렌더링해 획이 유지되면서 선명도(5916e7의 목적)도 유지된다.
검증(iPad 시뮬레이터): 시드에 필기 획 2줄 추가 + -diaryZoomScale
런치 인자(프로그램 줌) 신설 → 수정 전 2배 줌에서 획 소실 재현,
수정 후 동일 조건에서 획 유지·선명 확인.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
글래스 버블 메뉴가 닫힌 상태에서 FAB를 0.35초 안에 빠르게 두 번 누르면
설정한 탭으로 바로 이동하는 옵션. 첫 탭을 지연시키는 더블탭 제스처 인식은
메뉴 열림 반응성을 해치므로, 첫 탭은 즉시 메뉴를 열고 두 번째 탭에서만
분기한다 — 더블탭 시 버블이 피어나다 FAB로 흡수되며 화면이 바뀌는 연출.
- 설정(내비게이션, 버블 모드 전용): '두 번 눌러 바로 이동' 토글 +
'이동할 탭' 피커 + 푸터 설명. settings.radialDoubleTapTab
(rawValue, 빈 값=꺼짐, 기기 로컬)
- 검증용 런치 인자 -radialDoubleTapTest (2초 뒤 더블탭 재현) —
통계 탭 이동 스크린샷으로 확인
- 도움말: 버블 메뉴 항목에 더블탭 문장 추가 + 누락돼 있던
'홈 화면·잠금화면 위젯' 사용법 항목 신설
- l10n 6개 문자열 ko/en/ja, CLAUDE.md §6·§6.8·§14 갱신
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
③ 다짐 진행률 위젯에서 '이하 유지' 다짐은 시작부터 링이 가득 차 있고
문구도 '오늘 한도 지킴'뿐이라 지금 몇 회/몇 시간 했는지 알 수 없던 문제.
퍼센트(또는 한도 지킴/초과) 문구와 연속 달성 문구 사이에 위젯 옵션의
진행률 기간 기준 실제 누적값 한 줄을 추가한다 ("1시간 20분" / "3회").
'이상 달성' 다짐에도 동일하게 표시. 주간·월간 진행률 캡과 무관한
원본 누적값이며, 다른 위젯(②④)과 나머지 레이아웃은 그대로.
- QuestCellSnapshot.valueLabel 추가 (spanRange 원본 값 포맷)
- QuestProgress.spanRange(_:now:) 헬퍼 추출
- 위젯 미리보기에 '이하 유지(소형)' 행 신설 (앵커 CM)
- l10n: '0분' ko/en/ja (IOS·Widgets 카탈로그)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
'이하 유지' 다짐은 기록 없는 날도 달성으로 집계되므로 연속 계산이
목표가 생기기 전 과거(스캔 상한 400일)까지 거슬러 올라가 '연속 401일'로
표시되던 버그 수정. 연속은 행동이 아니라 '목표 안 다짐'의 달성이므로
하한 = 목표 시작일:
- 하루 단위: 시작일이 속한 논리적 하루부터만 센다
- 주간/월간: 시작일이 걸친 부분 주기까지 포함, 그 이전 주기에서 중단
검증: 시드에 재현 목표(스크린 타임 관리, 3일 전 시작 + 초과 없는 이하
유지 다짐) 추가 → 기대값 연속 4일 확인. -streakDump 런치 인자 신설
(전 다짐의 연속 계산 결과를 Documents/streak-dump.txt로 덤프).
부수: 도움말에 '연속 달성 표시' 항목 추가(ko/en/ja). 지난 기능들의
문자열이 위젯·워치·InfoPlist 카탈로그에 미번역으로 남아 있던 것을
채움(제어 센터·연속 표기·즐겨찾기·캘린더 권한 문구) — l10n 루틴이
IOS 카탈로그만 확인하던 함정을 CLAUDE.md §2.3에 명시.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
제어 센터/잠금화면 하단/액션 버튼에 배치할 수 있는 '행동 실행' 컨트롤:
- 행동 하나를 골라(미선택 시 배치 첫 행동) 시간형은 시작/종료 토글,
횟수형은 탭마다 +1 (토글 표시는 꺼짐으로 복귀)
- 전용 ToggleActionControlIntent(SetValueIntent + LiveActivityIntent) —
앱 프로세스 실행이라 제어 센터에서 시작해도 다이나믹 아일랜드가 바로 뜸.
단축어 앱에는 숨김(isDiscoverable=false), 프리미엄 게이트 적용
- DataChange.commit / IntentStore.performWrite에
ControlCenter.reloadAllControls() 추가 — 앱/위젯/시리/워치 어느 경로로
측정 상태가 바뀌어도 컨트롤 토글 표시가 따라온다
시뮬레이터에는 제어 센터에 컨트롤을 추가할 수단이 없어 빌드·인텐트
메타데이터 등록 확인까지 검증 (실기기에서 배치·토글 확인 필요).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
첫 실행의 빈 모음 탭이 안내 문구뿐이던 것을 개선:
- 도메인 개념 한 줄 소개 + '첫 행동 만들기'(행동 추가 시트 직행)
- '예시 행동으로 시작해 보기' — 즉시 써 볼 수 있는 예시 세트
(꼬리표 생활·건강 + 독서/운동/물 마시기) 생성. 행동 추가와 같은
경로(LocalPrefs 배치 등록 + DataChange.commit)를 쓰며 언제든 수정·삭제 가능
깨끗한 설치 상태 스크린샷으로 확인.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
설정 → 데이터 → '데이터 내보내기': 행동·시간 기록·횟수 기록·목표·다짐을
CSV 5개 파일로 만들어 공유한다 (백업·이동·스프레드시트 분석용).
- 가공 없는 원본 값, 시각은 ISO 8601, 필드 이스케이프 처리,
엑셀 한글 인식용 UTF-8 BOM
- 무료 사용자도 사용 가능 (iCloud 백업이 없는 무료 사용자의 백업 수단)
- 검증용 -dataExportPreview(화면 직행)·-dataExportRun(자동 생성 후
Documents 복사) 추가. 시뮬레이터에서 5개 파일 생성·내용 확인
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
- 텍스트 상자 요소: 노트 페이지 툴바에 '텍스트' 추가 — 키보드로 쓰는
글 상자를 배치 요소로 올린다 (배치 모드에서 이동·크기 조절, 선택 시
'글 수정'으로 내용·색 편집, 내보내기에도 그대로 렌더).
DiaryPageItem에 text 필드 추가(kind .text, CloudKit 기본값 규칙 준수)
- 페이지 순서 변경: ⋯ 메뉴 → '페이지 순서 변경' 시트에서 노트 페이지를
드래그로 재배열 (요약 페이지는 항상 첫 장)
- 프리미엄 만료 후 열람 허용: 이미 쓴 일기가 있으면 잠금 화면 대신
달력을 열람 전용으로 연다 — 안내 배너 + 일기 있는 날짜만 활성,
진입만으로 엔트리를 만들지 않고, 기분/할일/필기/필터/캘린더 등
모든 편집 UI 비활성 (environment diaryReadOnly로 전파).
일기를 쓴 적 없는 미구매 사용자는 기존 잠금 안내 유지
검증(iPad): 시드된 노트 페이지에서 텍스트 상자 렌더·툴바 확인,
-premium NO에서 배너/날짜 비활성/편집 UI 숨김 스크린샷 확인
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
- 워치 첫 화면 최상단에 '즐겨찾기' 항목 추가 — 앱에서 즐겨찾기한 행동을
태그를 거치지 않고 한 탭 만에 연다. WatchActionInfo.isFavorite는
optional로 실어 구버전 캐시 스냅숏도 그대로 디코딩된다.
- 워치 스냅숏 전송 디바운스(350ms): 모든 커밋마다 목표×다짐×3기간
진행률을 전부 재집계하던 것을, 연타 중에는 마지막 상태 한 번만
계산해 보내도록 변경 (명령 응답 경로의 즉시 스냅숏은 그대로).
iOS·watchOS 스킴 빌드 확인.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7