'이하 유지' 다짐은 기록 없는 날도 달성으로 집계되므로 연속 계산이
목표가 생기기 전 과거(스캔 상한 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
첫 실행의 빈 모음 탭이 안내 문구뿐이던 것을 개선:
- 도메인 개념 한 줄 소개 + '첫 행동 만들기'(행동 추가 시트 직행)
- '예시 행동으로 시작해 보기' — 즉시 써 볼 수 있는 예시 세트
(꼬리표 생활·건강 + 독서/운동/물 마시기) 생성. 행동 추가와 같은
경로(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
다짐 단위 '연속 달성' 표기 추가 (QuestProgress.streak → QuestStreakInfo):
- 하루 단위 다짐: 적용일만 세는 연속 계산 — 매일이면 연속 일수,
'매주 수요일'이면 수요일들만 이어서 센다 (4주 연속 = 연속 4일)
- 주간/월간 다짐: 주기 전체 달성 여부로 연속 N주/N달
- 특정 기간 다짐: 반복이 없어 표시하지 않음
- 진행 중인 오늘/이번 주기는 '이상 달성'이면 미달이어도 끊기지 않고
건너뛰며, 채웠으면 포함. '이하 유지'는 한도를 넘는 순간 끊김
- 성능: 기록을 논리적 하루 키로 1회 버킷팅해 O(기록수+일수),
소급 상한 400일
표기(기존 디자인·데이터는 그대로 두고 추가만, 0이면 숨김):
- 목표 탭 다짐 행: 이름 옆 불꽃 + "연속 N일" 배지 (노랑)
- 위젯 ③ 다짐 진행률: 퍼센트 아래 한 줄
- 위젯 ④ 다짐 현황: 이름 아래 작은 글씨
- 위젯 ② 목표+다짐 구성: 퍼센트 아래 6.5pt — 연속 표기가 있을 때만
행 높이 14→19 (적응 채움이 자동 반영)
- 문구는 '스트릭' 대신 "연속 N일/주/달" (en은 streak, ja는 N日連続)
문구 정정: '몇째 주 요일' → '몇 번째 요일' — 구현(weekdayOrdinal)은
달력의 주차가 아니라 "그 달의 n번째 ◯요일"이므로 편집 화면 픽커와
주기 요약 문구를 실제 동작에 맞게 수정 (동작 변경 없음). en/ja 번역 포함.
검증: 시드 데이터로 목표 탭 배지 손계산 대조(독서 연속 3일 — 3일 전
기록 없음 / 영상 시청 어제 한도 초과로 연속 1일 등 전부 일치),
위젯 ②③④ 미리보기 스크린샷으로 레이아웃 넘침 없음 확인,
missing: [], Debug·Store 스킴 빌드 성공.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
시리 단축어 점검에서 나온 추천 수정 일괄 적용:
- StartTimeActionIntent·StopTimeActionIntent가 LiveActivityIntent 채택 —
시리/단축어의 백그라운드 실행에서도 Live Activity 시작이 허용되어
앱을 열지 않아도 다이나믹 아일랜드에 측정이 표시된다.
RunActionIntent(위젯 버튼)는 확장 프로세스 응답성 튜닝을 유지하기 위해
의도적으로 제외.
- 행동 이름 파라미터 문구 추가: "시리야, 하루 다님에서 독서 측정 시작"처럼
되묻지 않고 한 번에 실행. 어휘 갱신을 위해 앱 시작 시
updateAppShortcutParameters() 호출 (새 행동은 다음 실행부터 인식).
- IOS/AppShortcuts.xcstrings 신설 — 시리 문구 ko/en/ja 지역화.
빌드 로그의 --no-app-shortcuts-localization가 사라지고 root.ssu.yaml에
en/ja 발화가 포함되는 것 확인.
- RunActionIntent isDiscoverable=false — 생 UUID 파라미터라 사용자가 조합할
수 없는 위젯 전용 동작을 단축어 앱·스포트라이트에서 숨김 (위젯 버튼은
그대로 동작).
- 결제 화면 기능 목록에 '시리 단축어' 추가. 이 과정에서 featureRow가
String 파라미터라 기능 목록 6줄 전체가 미지역화였던 버그 발견 —
LocalizedStringKey로 바꾸고 en/ja 12개 문자열 번역.
검증: -intentSmokeTest 9개 시나리오 전부 통과(LiveActivityIntent 전환 후
재확인), 프리미엄 화면 렌더링 확인, Debug·Store 스킴 빌드 성공.
남은 확인: 시리 음성 인식·백그라운드 Live Activity 실표시는 실기기 필요.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
시리 단축어 기능 점검:
- 도움말(프리미엄 그룹)에 '시리·단축어로 기록하기' 항목 추가 — 그동안
도움말에 시리 단축어 안내가 없었다. en/ja 번역 포함
- DEBUG 검증용 -intentSmokeTest 런치 인자 추가: 인텐트 6종의 perform()을
앱 안에서 9개 시나리오(시작/중복 방지/종료/횟수 추가/타입 방어/조회
3종/프리미엄 게이트)로 실행하고 결과를 Documents/intent-smoke-test.txt에
남긴다. 시뮬레이터 실행 결과 9개 전부 통과
- CLAUDE.md §12·§14에 검증 방법과 현재 한계(AppShortcuts 지역화 미구성,
'선택 안 함' 센티널의 단축어 앱 노출) 기록
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
글래스 버블 메뉴를 시스템 리퀴드 글라스(glassEffect) 기반으로 재구축.
컨셉(FAB → 부채꼴 유리 구슬, 엄지 반경 ~150pt, 바깥 탭 닫기, 순서 설정)은
그대로 두고 유리 질감·연출·성능을 올렸다.
유리: material 흉내(ultraThinMaterial + 그라데이션 + 테두리) 대신
.glassEffect(.regular.interactive()) — 배경 굴절·빛 반사·눌림 시머까지
시스템이 그린다. 현재 탭은 초록 틴트 유리.
연출: 2단계 — 삽입 순간 FAB 유리에서 모핑으로 부풀어 나온 뒤(bloomed)
스태거 바운스 스프링으로 아치에 흩어진다. GlassEffectContainer 근접
블렌딩으로 FAB를 벗어날 때 유리가 늘어나다 물방울처럼 분리. 닫힘은
지연 없이 흡수. 그라데이션 딤 + 메뉴 뒤 초록 빛 무리 + 햅틱.
성능(버벅임): 예전엔 블러 14장(버블 7 + 라벨 알약 7) + 그림자 14개가
각각 애니메이션됐다. 라벨을 구슬 안에 넣어 유리 요소를 8개로 줄이고
GlassEffectContainer가 한 패스로 일괄 렌더링, 커스텀 그림자 제거.
주의점 기록: 컨테이너 안 유리 요소는 glassEffect 뒤 opacity/scale이
콘텐츠에 온전히 적용되지 않아(접힌 상태 내용물 비침) 숨김은 계층
제거(if expanded), 이동은 offset으로만 처리.
검증: 접힘·펼침(라이트/다크) 스크린샷으로 유리 굴절·라벨 가독성·
콘텐츠 누출 없음 확인. Debug·Store 스킴 빌드 성공.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
일기 상세는 진입만 해도 DiaryEntry를 생성(loadEntry)해서, 열람만 한
날짜의 빈 엔트리가 스토어와 CloudKit에 계속 쌓였다. 달력 화면
onAppear에서 완전히 빈 엔트리만 정리한다 (상세에서 달력으로 돌아올
때마다 실행되고, 이 수정 이전에 쌓인 빈 엔트리도 함께 청소됨).
보존 조건을 엄격히 판정:
- hasContent(기분·할 일·내용 있는 페이지)는 물론
- 달력 마커에 안 잡히는 캘린더 일정(calendarEventIDs)·타임테이블
필터(hiddenActionIDs) 선택이 있으면 보존
- 아직 내용 없는 노트 페이지를 만들어 둔 날도 보존 (페이지 0개일 때만 삭제)
검증(iPad 시뮬레이터, 스토어 직접 조회):
- 열람만 하고 나간 빈 엔트리 → 달력 재진입 시 삭제 (1건 → 0건)
- 타임테이블 필터만 설정한 엔트리 → 정리 후에도 보존, 재진입 시
필터 배지(1)와 숨김 상태 유지 확인
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
꼬리표 순서 변경 시트와 즐겨찾기 토글(리스트 스와이프·상세 화면)이
DataChange.commit 없이 autosave에만 의존해, 저장 확정이 지연되고
꼬리표 순서를 쓰는 워치 앱 그룹핑이 다음 커밋 시점까지 낡은 순서로
남을 수 있었다.
- TagOrderSheet: 드래그마다가 아니라 시트가 닫힐 때 1회만 커밋
('완료'와 스와이프 내리기 모두 onDisappear 경로) — 위젯 리로드 연발 방지
- 즐겨찾기 토글 2곳: 변경 즉시 커밋
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
CLAUDE.md v2.0 — 기획서(v1.0)를 폐기하고 실제 구현 기준의 현행 명세로 전면 재작성:
프로젝트 구조·빌드/검증 루틴·도메인 모델(CloudKit 규칙)·집계/판정 규칙·데이터 계층
(LocalPrefs/DataChange)·화면별 상세·내보내기·프리미엄/StoreKit·위젯 6종·워치·시리·
DEBUG 런치 인자·작업 컨벤션까지 새 세션이 이 문서만으로 파악 가능하게 정리.
동작 보존 범위의 안전 수정 3건:
- Color.hexString: 와이드 컬러(P3) 성분을 0...1로 클램프 — 음수/1 초과 값이
%02X를 거치며 자릿수 깨진 hex가 태그·목표 색으로 저장되던 잠재 버그 방지
- 일기 타임테이블 필터: 선택 즉시 명시적 save — 캘린더 일정 선택 경로와 동일하게
영속을 보장 (autosave 의존 제거)
- 통계 평균 "%.1f회"가 String(format:)이라 영어·일본어에서도 '회'로 노출되던 것을
Format.countAverage로 지역화 (en "times" / ja "回", 카탈로그 동기화 포함)
Debug·Store(Release) 스킴 빌드 검증 완료.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
일기 타임테이블에서 그날 기록된 행동 중 원하는 것만 골라 볼 수 있게.
캘린더 일정 선택과 마찬가지로 날짜별로 저장되고 내보내기에도 반영된다.
- DiaryEntry.hiddenActionIDs (행동 uuid 문자열, 날짜별·동기화 안전)
- 타임테이블 카드 우상단에 필터 버튼 추가 (숨긴 개수 배지, 캘린더 버튼 옆)
- 기존 RecordFilterSheet 재사용 — 그날 기록된 행동만 꼬리표별로 나열
- 필터는 타임테이블에만 적용, 기록 목록·요약 통계는 전체 유지
(ExportSnapshot.replacingTimetableSections로 내보내기도 동일 규칙)
- 도움말 갱신: 목표 달성 판정 기준, 일기 타임테이블 일정·필터 항목
- en/ja 번역 추가 (Live Activity의 미번역 문자열 3건도 함께 보충)
- 검증용 런치 인자 -diaryShowActionFilter, -diaryHideFirstAction 추가
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
목표 종료 판정이 '다짐 전체 달성'으로 고정되어 있던 것을, 목표를 만들 때
달성 판정 기준(%)을 정할 수 있게 확장. 다짐들의 평균 달성률(달성=100%,
미달성=현재 주기 진행률)이 기준 이상이면 달성 완료로 판정한다.
- Goal.achieveThresholdPercent (기본 100 = 기존 동작 유지, CloudKit 호환)
- evaluateIfEnded/manualFinish가 questAchievementRatio ≥ 기준으로 판정
- 목표 추가/수정 화면에 '달성 판정 기준' 슬라이더 (10~100%, 5% 단위)
- 수동 종료 안내 문구에 기준이 100% 미만이면 해당 기준 표기
- 검증용 런치 인자 -goalShowEditor 추가
- 그 외 진행률 표시·연산은 변경 없음
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
- 실기기에서 drawingPolicy .pencilOnly — 손가락은 절대 필기되지 않고,
확대 상태에서 한 손가락으로 페이지를 상하좌우 이동(팬)한다. 이동/확대
제스처는 allowedTouchTypes=direct로 손가락 전용이라 펜슬 획을 뺏지 않음
(시뮬레이터는 입력 수단이 없어 anyInput 유지). 배치 모드에선 한 손가락을
요소 드래그에 양보(팬 두 손가락)
- 선명도 재수정: SharpPencilCanvasView가 목표 래스터 배율(기기 스케일 ×
현재 줌, 상한 ×3)을 뷰+레이어 트리에 유지하고, 획을 그릴 때마다·레이아웃
때마다 재적용 — PencilKit이 새 획 렌더 레이어를 기본 해상도로 만들어
흐려지던 문제와, 기존 1.5배 슈퍼샘플링의 다운샘플 소프트닝을 함께 제거
(화면 픽셀과 1:1 매칭이 가장 선명)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
- DiaryEntry.calendarEventIDs: 날짜별로 어떤 캘린더(EventKit) 일정을 넣을지
따로 저장 — 오늘은 포함, 내일은 미포함 같은 선택이 가능
- 타임테이블 카드 우상단 캘린더 버튼(+선택 개수 배지) → 일정 선택 팝업:
그날의 일정 목록에서 전체 선택/해제 또는 개별 체크, 권한 미허용 시 설정
이동 안내. 종일 일정은 제외, 하루 경계에 걸치면 잘라서 표시
- 일정은 행동 블록과 구분되는 외곽선+은은한 채움 스타일(캘린더 색)로 렌더,
일기 내보내기(PDF/이미지)에도 동일하게 포함 — 내보내기 요약도 화면과
같은 24시간 타임테이블로 통일
- NSCalendarsFullAccessUsageDescription 추가, 새 문자열 en/ja 번역
- 검증 인자: -diarySeedEvents YES, -diaryShowCalendarPicker YES
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
- 모음 탭 왼쪽 위 새로고침 버튼(RefreshButton/AppRefresh): 루트 뷰 identity
리셋으로 모든 @Query를 재조회(앱 재시작과 같은 효과) + 라이브 액티비티·
위젯·워치 스냅숏 동기화. 다른 기기의 iCloud 변경이 화면에 늦게 보일 때
재시작 없이 반영. iPhone·iPad 공통, Release(스토어) 빌드에도 포함
- 설정 → 지원 → 도움말(HelpView): 기본 개념/모음 탭/목표/기록·통계/동기화/
프리미엄 공통 + iPhone은 화면 구성(탭바·버블 메뉴·다이나믹 아일랜드)과
애플워치(기록·컴플리케이션·동기화) 섹션, iPad는 일기 섹션. 접이식 주제별
구성, 새 문자열 59개 en/ja 번역
- 검증 인자: -helpPreview YES
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
- 'Haru_Danim-Store' 공유 스킴 추가: Release 구성으로 실행해 DEBUG 코드
(프리미엄 테스트 토글·검증용 런치 인자)가 전부 빠진 '스토어에 올릴
그대로'의 앱을 실기기에서 확인. StoreKit 로컬 구성은 유지되어 실제 결제
시트가 뜨되 돈은 청구되지 않는다
- 실구매/복원 시 DEBUG 테스트 토글 강제 모드를 자동 해제(실권한 우선),
개발용 섹션에 '토글 강제 해제' 버튼과 동작 설명 footer 추가
- Localizable.xcstrings는 Xcode 직렬화 포맷 정규화
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
기존 StoreKit 2 골격(상품 3종·구매·복원·권한 주입) 위에 실사용 경험 완성:
- PremiumStore.currentPlan: 현재 이용 중인 대표 플랜(평생 > 만료 먼 구독)
추적, 구매·복원 후 위젯 타임라인 즉시 갱신
- 프리미엄 화면: '이용 중인 플랜' 섹션(플랜 이름·다음 갱신일·평생 안내),
구독 관리 시트(manageSubscriptionsSheet), 구독 중 평생 이용권 전환 안내,
년 구독 절약률·평생 '한 번 결제' 배지, 자동 갱신·해지·복원 안내 문구
- 잠금 안내 개선: 행동/목표/다짐 무료 한도 알림에 '프리미엄 알아보기'
버튼 + PremiumSheetView 모달, 아이패드 일기 잠금 화면에도 버튼 추가
- 기능 소개에 '아이패드 일기' 추가, 새 문자열 en/ja 번역
가격(월 5,000/년 50,000/일회성 80,000)은 HaruDanim.storekit(로컬 테스트)과
App Store Connect에서 각각 수정 가능. DEBUG 강제 토글은 그대로 유지.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
'오늘 기분'을 카드의 주인공인 200pt 정사각형 타일로 재배치 — 사진은 꽉
채우고(이모지는 우하단 배지), 이모지만 있으면 크게 가운데, 비어 있으면
'탭해서 남기기' 플레이스홀더. 오른쪽에 이모지/사진/지우기 캡슐 버튼 열.
새 문자열 en/ja 번역 추가.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
글래스 버블 메뉴의 탭 이름이 맨 글자(그림자만)라 라이트 모드 밝은 배경
위에서 잘 안 보였음 → 구슬과 같은 ultraThinMaterial 캡슐 배경 + 화이트
보더 + 소프트 섀도를 붙여 라이트/다크 어디서나 읽히게 함.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
- 일기 상세 메뉴에 '첫 화면 구성' 시트 추가: 7개 섹션(오늘 기분/요약
지표/이 날의 목표/오늘 할 일/타임테이블/기록 상세/통계 막대)을
드래그로 순서 변경, 스위치로 표시/숨김 (모든 날짜 공통 적용)
- DiarySummaryPage가 설정 순서대로 렌더링, 숨긴 섹션 제외. 와이드
레이아웃은 타임테이블 표시 중일 때만 2컬럼(타임테이블 왼쪽 전담)
- 기존 '오늘 기분 표시' 토글은 새 숨김 목록으로 1회 이관
- 검증 인자: -diaryShowConfig YES, -diary.sectionOrder/-diary.hiddenSections
- 새 문자열 en/ja 번역 추가
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
- 첫 페이지를 '하루 정리' 화면으로 개편: 기록 유무와 무관한 24시간 고정
타임테이블(trimHours 옵션), 그 날짜에 진행 중이던 목표들의 다짐별 진행
현황 카드(하루 다짐은 그날 실적, 주간/월간/기간 다짐은 그 날짜까지 누적,
'이하 유지'는 한도 게이지로 구분), 기록 상세·통계 막대 재배치
- 노트 페이지: UIScrollView 기반 핀치줌(두 손가락, fit~4배, 배치 모드에선 잠금)
- 줄 노트 줄 간격 설정(좁게/보통/넓게/아주 넓게, 페이지별 저장·내보내기 반영)
- 새 문자열 en/ja 번역 추가
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
- 달력(작성일 마커: 기분 이모지/연필 점) → 날짜별 일기, 이번 달 작성 수 표시
- 첫 페이지: 날짜·오늘 기분(이모지/사진, 끄기 옵션)·할 일 체크리스트(스크리블 입력)·
타임테이블·통계(내보내기 스냅숏 재사용으로 화면·내보내기 일치)
- 노트 페이지: PencilKit 캔버스(도구 팔레트) + 줄 노트 배경 + 사진/도형(사각형·원·화살표·선)
배치 모드(드래그·핀치), 페이지 무한 추가 — 논리 크기 768×1024 고정으로 WYSIWYG 내보내기
- 내보내기: 구간/복수 날짜(MultiDatePicker) → PDF 1개 또는 날짜별 세로 스티치 PNG
- SwiftData 모델 4종(CloudKit 호환 패턴) 스키마 추가, PremiumFeature.diary,
iPhone 탭 컨텍스트(탭바·더보기·라디얼)에서 일기 제외, en/ja 번역 39건
- 검증 인자: -diarySeed/-diaryOpenToday/-diaryPage N/-diaryShowExport/-diaryExportRun pdf|image
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
- 카탈로그 4종 xcstringstool sync + stale 키 64개 제거
- 버블 메뉴·위젯 5종·이미지 내보내기 신규 문자열 en/ja 전량 번역
- StatsTabView 카드 제목·RecordFilterSheet 제목이 String 파라미터라 미현지화되던 것을 LocalizedStringKey로 수정
- HistoryView 필터 칩 문자열 String(localized:) 누락 수정
- 위젯 익스텐션 InfoPlist.xcstrings 신설(표시 이름 현지화), iOS에 사진 권한 문구 ko/en/ja 추가, 워치 ja 앱 이름 'Haru Danim'으로 통일
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
The vertical capsule stack reached ~414pt up the screen, putting the top
tabs out of thumb range. Replace it with 'Glass Bubbles': liquid-glass
orbs that fan out from the FAB along a semicircular arc whose radius
(~152pt, clamped to screen width) keeps every tab inside the natural
thumb sweep from the bottom-center pivot.
- Each bubble: ultraThinMaterial circle + top white gradient (specular
light) + white 0.4 hairline + soft shadow; label with shadow below.
Current tab rendered as green glass with white symbol.
- Entrance: bubbles fly from the FAB to their arc slot while rotating
-40deg -> 0 with a snappy spring (response 0.32, damping 0.72) and a
per-item 0.03s stagger, like droplets bursting in sequence; collapse
snaps back with no delay. All transform-only (offset/scale/opacity/
rotation) so no per-frame blur recomputation.
- Struct renamed FloatingCapsuleMenu -> GlassBubbleMenu; storage key and
NavStyle.radial rawValue unchanged for compatibility.
- Settings copy updated: nav style now '글래스 버블 메뉴' with a
description of the fan-out and one-handed reach; order editor renamed
'버블 메뉴 순서' with left-to-right arc wording.
Verified: clean rebuild (stale incremental link produced an old binary
despite BUILD SUCCEEDED; wiped DerivedData), expanded-arc screenshot
shows all 7 bubbles within thumb radius with legible labels, and the
settings screen shows the new name/description.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
Widget system rebuilt as 5 independent widgets, each with its own
WidgetConfigurationIntent registered in the WidgetBundle:
- ① ActionRun: multi-action selection, value display option (day/week/
month/hidden), full tag-color cells; small 1 / medium 4 (2x2) / large
4 big cells or 8 compact cells (2x4) via largeStyle. Unfilled slots
render as dashed blank cells.
- ② GoalProgress: multi-goal selection; medium [2 goals | goal+top
quests], large [4 goals | 2x goal+quests | 1 goal + all quests] via
medium/largeStyle. New QuestBarRow / GoalWithQuestsCellView.
- ③ QuestRing: multi-quest selection + span; surface-card ring (tag
color) with centered icon, name and "오늘 N%" text; interactive run
via RunActionIntent; small 1 / medium 2 / large 4 (2x2).
- ④ QuestStatus (display-only): goal selection + span; rings with name
only (no %), goal icon+name top-left; small 4 (2x2) / medium 8 (4x2) /
large [16 (4x4) | 4 goals | 2 goals] via largeStyle.
- ⑤ StatsChart: multi-action selection capped per family (2/4/6) +
3 span modes; same design scaled by family.
Common foundation:
- Theme option revived on every intent: match app / light fixed / dark
fixed (WidgetThemeOption AppEnum) applied through widgetAppTheme(_:)
with proper iOS 17 containerBackground; non-fullColor rendering modes
(tinted/clear/accented) keep the Color.clear + semantic-color defense
so content never goes white-on-white.
- Providers are family-aware (capacity by size) and slot-pad selections
(WidgetStore.slots); defaults fill from existing data so fresh widgets
never look empty.
- Interactive path unchanged: RunActionIntent(actionID:) +
IntentStore.performWrite -> reloadAllTimelines.
Floating menu polish:
- All glass capsules now share a uniform width (longest label wins,
locale-proof) for a tidy popped-up list.
- Settings strings updated: nav style renamed to '플로팅 글래스 캡슐'
with description matching the capsule popup, order editor retitled
'캡슐 메뉴 순서' with bottom-to-top wording.
Verified: BUILD SUCCEEDED (iPhone 17 Pro sim); widget preview harness
extended with per-variant scroll anchors and all 15 layout variants
screenshot-checked, including forced accented mode (legible translucent
cells) and blank-slot rendering; capsule menu and settings text
screenshot-checked.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
Replace the single semicircle dome + arc-arranged icons (which distorted and
pushed labels outside the fan) with independent floating glass capsules that pop
up in a vertical stack from the FAB.
- Each tab is now a self-sizing Capsule: icon + label with generous padding so
text can never overflow; ultraThinMaterial background, thin white translucent
border (.stroke white 0.4), and a soft drop shadow for a floating glass look.
- Current tab gets a subtle green tint behind the content.
- Removed the heavy DomeShape glass fan and its scale/opacity blur transition
plus all per-item arc math; appearance is driven purely by offset + scale +
opacity under one snappy spring (response 0.3, damping 0.7), so no per-item
blur passes and no progressive frame drops.
- Renamed RadialMenu -> FloatingCapsuleMenu; RadialTabView / settings keys /
nav-style routing unchanged.
Verified: BUILD SUCCEEDED (iPhone 17 Pro sim) and expanded-state screenshot
confirms all 7 capsules render legibly with text fully inside each pill, no
distortion, current tab highlighted.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
On a tinted/transparent (or iOS 18 accented) home screen, the Action Run
widget turned into a solid white block with invisible content, while the
other widgets rendered fine. Cause: only the Action Run cell paints an opaque
tag-color background (WidgetTintedCellBackground) with hardcoded
.foregroundStyle(.white) text on top. In any non-.fullColor rendering mode
the system re-interprets that opaque fill toward white and the white text
disappears — classic white-on-white. The other widgets already use the
adaptive AppTheme.surface plus semantic .primary/.secondary text, which is
why they were unaffected.
Fix, confined to ActionRunCellView:
- Read @Environment(\.widgetRenderingMode). In .fullColor keep the tag-color
fill + white text (unchanged). In accented/vibrant, drop the opaque fill to
a faint translucent tint and render content with the semantic .primary color
so the system's tint keeps a clear foreground/background contrast.
- No hardcoded .white survives on the tinted path; the container background is
still owned by widgetAppTheme()'s .containerBackground(for: .widget) (clear
in non-fullColor so the system glass shows through), so this composes safely
with iOS 18 home-screen customization.
The Live Activity's white-on-tint icon (HaruDanimWidgets) is intentionally
left as-is — Live Activities always render full color and aren't subject to
home-screen widgetRenderingMode.
Verified in the in-app widget preview with a new DEBUG affordance
(-widgetRenderMode accented|vibrant, added to WidgetPreviewScreen): forcing
accented mode, the Action Run cells now show legible dark icons/labels/values
on a faint tint instead of blank white. Build succeeds.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
Widget configuration — delete the multi-slot pickers entirely
--------------------------------------------------------------
Every home/lock widget exposed 3–4 separate entity slots (action1–4,
goal1–4, quest1–4, secondGoal) regardless of family, cluttering the
long-press config screen with slots a given size never renders. Replaced
that with a single anchor selection per widget that self-configures by size
family (the view already prefixes by family; providers now build the
candidate list from one selection):
- ActionRun (A): one anchor Action → fills following actions (main-tab order)
up to the family's count.
- GoalBars (B): one anchor Goal → fills following goals up to the count.
- QuestRing (C): one Goal → renders that goal's quests, sized by family.
- GoalQuestGrid (D): one Goal (dropped secondGoal) → its quests; large now
shows up to 16 rings of the single goal.
- Stats: one anchor Action → plus following actions on the same chart.
New WidgetStore helpers actionsFrom/goalsFrom/questsOfGoal centralize the
"anchor + following / goal's quests" logic; the None sentinel is ignored
gracefully so clearing falls back to sensible defaults. No @Model, timeline,
or reload/sync logic touched.
Floating radial menu (iPhone) — performance + glassmorphism
-----------------------------------------------------------
Each of the ~7 icons and ~7 labels had its own .ultraThinMaterial, so the
expanded menu ran ~15 separate blur passes that re-rendered every frame as
content scrolled behind them — the source of the progressive frame drops.
Now a single unified glass dome (one DomeShape filled with .ultraThinMaterial)
sits behind the whole fan and is the only blur; icons are lightweight symbols
(only the current tab gets a solid green chip) and labels are plain text with
a legibility shadow. The dome is styled per glassmorphism: a soft white
top-to-bottom gradient overlay, a thin white.opacity(0.2) border, and a soft
shadow; the FAB gets the same gradient/border treatment.
Animation is snappier and lighter: the per-item implicit spring animations
with staggered delays are gone — one withAnimation(.easeOut ~0.24 open /
.easeIn ~0.18 close) drives the whole fan, and the press style uses a short
easeOut instead of a spring.
Verified in the simulator: build succeeds; the expanded menu renders the
single glass dome with all tabs and no crash (light/dark, expanded/collapsed);
the refactored C/D widgets render from a single selected goal, self-sized by
family.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
Radial menu icon order (iPhone floating nav only):
- Settings → 내비게이션 gains a '반원 메뉴 순서 편집' link (shown only when the
radial style is selected) that opens a drag-to-reorder list of all 7 tabs.
- Order is stored device-local via @AppStorage(SettingsKeys.radialTabOrder)
(not CloudKit-synced); RadialMenu reads it through AppTab.radialOrder(from:),
which always yields the full tab set and appends any missing/unknown value in
default spec order — so partial or legacy strings can never drop a tab.
- iPad/Mac sidebars and the watch target are untouched (they never read the key).
History timetable date step:
- The date header </> buttons now jump by a full week (7 days) when the
timetable is in '일주일' view, and by 1 day otherwise (list / daily timetable).
- The calendar popover and '오늘' still set the date directly, so those paths and
record loading are unaffected.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
Adds an alternative iPhone navigation style, switchable in Settings, that
replaces the bottom tab bar with a single center floating button which fans
all tabs out into an upper 180° semicircle.
- Settings → 내비게이션: pick 기본 하단 탭 바 / 중앙 플로팅 반원 메뉴.
Stored device-local via @AppStorage(SettingsKeys.navStyle) (not synced);
the 탭바 구성 section auto-hides in radial mode since all tabs are shown.
- iPhone (Compact) only: RootNavigationView branches on NavStyle. iPad/Mac
sidebar and the watch target are untouched.
- Radial menu (RadialNavigationView): glass FAB at bottom-center over a
tab-bar-hidden TabView (per-tab navigation state preserved). Tapping the
FAB blooms all 7 tabs into an upper 180° arc with per-icon name labels;
tapping an icon routes immediately and closes; tapping the FAB or the
dimming scrim closes. Current tab is highlighted.
- Drops the 더보기 indirection in radial mode via AppRouter.allTabsDirect,
so cross-tab routing (openHistory/openStats) selects tabs directly.
- Liquid Glass (.ultraThinMaterial) styling on the FAB, icons and labels.
- Overlay is kept top-most in the ZStack with hit-testing gated to the
expanded state, so scrolling grid content can never intercept the button.
- DEBUG: -navStyle radial / -radialExpanded YES launch args for simulator
verification (no way to tap widgets/overlays via simctl).
Scope: iPhone navigation only; no changes to iPad/Mac sidebar, the watch
app, core data/models, or widget code.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
- IntentStore now recreates the ModelContainer on demand in the widget
extension (IntentStore.refresh()), called before every AppIntent
perform() and every provider's makeEntry(). Fixes stale/blank widget
buttons and double-toggle bugs caused by the extension process
reading an old in-memory snapshot after CloudKit remote changes.
- Replaced the fixed 15/30-minute polling Timeline policy (which burns
WidgetKit's daily reload budget across 6 widget kinds) with
WidgetRefresh.timeline: idle widgets wait until the next logical-day
boundary since value changes are already pushed via
reloadAllTimelines, while widgets showing a live ratio (a currently
running quest/goal) get pre-computed future entries so progress
rings and bars keep advancing without extra reloads.
- Removed the per-widget "위젯 테마" (match app / light / dark / liquid
glass) configuration option from all 5 home-screen widgets. It
duplicated the same enum five times, and the liquid-glass variant's
custom background/scheme override fought the system's own
vibrant/tinted rendering in tinted Home Screens, which was part of
the "블랙 화면"/렌더링 오류 reports. Widgets now simply follow the
app's own theme setting (WidgetAppearance.appScheme), which is what
"앱 테마와 일치" already defaulted to.
- Added shared gallery/placeholder sample data (ActionCellSnapshot,
QuestCellSnapshot, GoalSnapshot, StatsChart sample points) so the
widget gallery and redacted placeholders show a realistic shape
instead of an empty/blank card.
- Unified empty-state UI via WidgetEmptyView across all 5 widgets.
Scope: Widgets/*, Shared/HaruDanimIntents.swift (widget-facing
IntentStore only), IOS/Views/WidgetPreviewScreen.swift (DEBUG preview
tool). No changes to app core data models, sync, or view logic.
위젯 동기화 크래시 수정:
- DataStore: CloudKit 미러링을 메인 앱 프로세스 전담으로 분리.
위젯 등 앱 확장(.appex)은 CloudKit 엔타이틀먼트가 없고 메모리·수명
제약으로 미러링 설정이 크래시/행을 유발하므로, 확장 프로세스는 항상
같은 App Group 스토어 파일을 로컬 전용(cloudKitDatabase: .none)으로
연다. 확장이 쓴 변경은 메인 앱이 히스토리로 집어 CloudKit에 내보냄
- CloudSyncMonitor 신설: 메인 앱이 NSPersistentStoreRemoteChange
(다른 기기의 CloudKit 가져오기·위젯 인텐트의 쓰기)를 디바운스로 받아
라이브 액티비티 → 위젯 타임라인 → 워치 스냅숏 순으로 즉시 갱신
- 인터랙티브 위젯(AppIntent)의 컨테이너 매핑 점검: IntentStore.commit이
저장 직후 reloadAllTimelines를 이미 보장함을 확인·문서화
모음 탭 목표 진행 현황 카드 개선:
- '다짐별로 보기'의 상위 3개 제한 제거 — 모든 다짐 확인 가능
- 화면 균형을 위해 접힘/펼침 UX 적용: iPhone은 3개, iPad는 6개까지
접힌 상태로 보여주고 '다짐 N개 더 보기' 버튼으로 카드 안에서 펼침
(카드 탭 이동과 충돌하지 않는 독립 버튼, 스냅 애니메이션)
- DebugSeed: 접힘/펼침 검증용 4번째 다짐 추가, -expandGoalCard 인자 추가
검증: iPhone 17 Pro·iPad Pro 11 시뮬레이터에서 접힘/펼침 렌더링과
사이드바 레이아웃 확인, 전체 타깃(iOS·워치·위젯) 빌드 성공
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
- Add Shared/LocalPrefs.swift: device-local UI preferences stored in App Group
UserDefaults (never synced by iCloud), read identically by app, widgets,
watch snapshot, and App Intents on the same device
- Move to local storage: main-tab action button order (UUID array), pinned
goal-progress cards on the main tab, goal quest-list collapse state, and
per-action memo-prompt popup — reordering or repinning on iPhone no longer
touches the iPad and vice versa
- Defense logic: actions not in the local order list (e.g. newly received via
CloudKit from another device) are automatically appended to the end, sorted
by legacy sortOrder then creation date
- One-time migration adopts existing @Model values (sortOrder, showsOnMain,
isCollapsed, promptsForNote) into local prefs at launch; model properties
stay in place so the CloudKit schema is untouched and records keep syncing
- Data remains fully synced: actions, goals, quests, sessions, count entries,
statistics, and goal/tag/quest list order are untouched by this change
- Verified in simulator: legacy data migrates losslessly, grid renders from
local order, unknown action lands at the end; iOS+watch+widgets build clean
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
- Add SidebarRootView: iPad/Mac (Designed for iPad) uses a NavigationSplitView
sidebar listing all 7 tabs, sharing every existing screen (rootView) untouched
- Branch by device idiom (DeviceLayout.isPad) so iPhone keeps its tab bar UI,
logic, and Live Activity behavior pixel-for-pixel, including landscape
- AppRouter gains sidebar mode: cross-tab routing (기록 확인/통계 보기) selects
the target tab directly instead of detouring through the More tab
- Hide iPhone-only settings on iPad/Mac: 탭바 구성 section and the main grid's
per-row column picker are meaningless with a sidebar/adaptive grid
- Main tab wide-screen layout: pinned goal cards flow in an adaptive grid
(340-520pt cards) instead of full-width paging; action buttons auto-fill
columns at 150-220pt so nothing stretches on large displays
- Verified on iPad Pro 11" simulator (sidebar, settings, stats routing,
timetable) and iPhone 17 Pro (unchanged tab bar); both build clean
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
- 목표 하루 진행률은 오늘이 수행일인 다짐만 모수로 계산 (요일·날짜 지정으로
오늘 쉬는 다짐은 분모에서 제외, QuestProgress.isScheduled 신설)
- 오늘 수행할 다짐이 하나도 없는 날은 0% 대신 100%(완료 상태)로 표기
- 주간/월간 진행률은 기존대로 전체 다짐 기준 유지
- 이벤트 기반 위젯 새로 고침: 앱 내 모든 핵심 Mutation(측정 시작/종료,
횟수 추가, 기록 추가·수정·삭제, 행동·꼬리표·목표·다짐 CRUD, 순서 변경,
목표 상태 변경)의 끝단에서 DataChange.commit() 호출 — 저장 즉시 확정 후
Live Activity·위젯 타임라인·워치 스냅숏을 한 번에 동기화
- 주기적 백그라운드 새로 고침 없이 변경 시점에만 갱신해 WidgetKit
업데이트 예산 절약 (타이머 표시는 기존 Text(style: .timer)로 시스템이
자체 렌더링하므로 타임라인 소모 없음)
- 하루 시작 시간·주 시작 요일 설정 변경 시에도 위젯 집계 갱신
- 시뮬레이터 검증: 월·수·금 다짐이 있는 목표의 토요일 하루 진행률이
33%가 아닌 50%(오늘 수행 다짐 2개 평균)로 표시됨 확인
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
- 글라스 테마: 틴트 셀 불투명도 0.5→0.72, 테두리 강화로 흰 텍스트 대비 확보
- 글라스 테마 전용 텍스트 그림자(glassTextShadow) 추가 — 홈 위젯 5종 셀 콘텐츠에 적용
- widgetRenderingMode != .fullColor(홈 화면 틴트/클리어)일 때 커스텀 배경·강제
컬러 스킴을 끄고 시스템 바이브런트 렌더링에 맡기도록 분기
- 잠금화면 위젯: AccessoryWidgetBackground + widgetAccentable + .primary 전경색으로
비브런트/악센트 렌더링에서 시인성 확보
- 미리보기 하네스: 글라스 테마가 시스템 컬러 스킴을 따르도록 수정
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
- 홈 위젯 5종에 contentMarginsDisabled() 적용: 시스템 기본 베젤 제거,
여백은 각 뷰가 직접 관리 (다중 셀 10pt, 콘텐츠형 13pt)
- 소형(단일 셀) 위젯은 셀이 위젯 전체를 여백 없이 채움 — 셀 배경/테두리가
ContainerRelativeShape로 위젯 모서리에 정확히 맞음 (A·B·C 위젯)
- 다짐 현황(D) 위젯 간격 개선: 링 그리드 행 간격 6→12, 열 간격 4→8,
섹션 간격 6→10, 대형 목표 2개 간격 10→16, 링-이름 간격 확대
- 미리보기 하니스도 여백 제거를 반영해 실제 렌더링과 일치
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
- 언어 설정 실적용: 변경 시 AppleLanguages 오버라이드 저장, 재시작 안내 footer
- 자동 추출되지 않던 일반 문자열(탭 이름, 픽커 라벨, 상태 뱃지, 포매터,
삼항 문구, 심볼 카테고리 등)을 String(localized:)로 전환
- 위젯·워치 앱·컴플리케이션 타깃에 Localizable.xcstrings 신설
(중복 리소스 방지 pbxproj 예외 추가), xcstringstool sync로 키 추출
- 4개 카탈로그 전체 키(고유 430개)에 en/ja 번역 주입
- 영어의 긴 횟수 단위("times")가 잘리지 않도록 모음 탭 셀 축소 허용
- 검증: -AppleLanguages "(en)"/"(ja)"로 모음 탭·설정 화면 확인
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
- StoreKitEntitlementProvider: Transaction.currentEntitlements 기반 실권한
조회 + Transaction.updates 이벤트 반영. 앱 시작 시 PremiumManager.bootstrap
으로 주입 (확장 타깃은 기존 PremiumGate 캐시 그대로)
- PremiumStore: 상품 로드/구매/복원 (월·년 구독 + 평생 이용권 3종)
- PremiumView: 실구매 UI (상품 목록·가격·구매 복원, 미로드 시 재시도 폴백)
- DEBUG 강제 프리미엄(-premium, 테스트 토글) 중에는 StoreKit 결과가
덮어쓰지 않도록 보호
- HaruDanim.storekit 로컬 테스트 구성(월 5,000 / 년 50,000 / 일회성 80,000원,
ko·en·ja 현지화) + 메인 스킴에 연결 → Xcode 실행으로 결제 흐름 테스트 가능
- 남은 것: App Store Connect에 productID 3종 등록만 하면 실결제 연결 완료
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
- AppGroup.defaults를 단일 인스턴스(static let)로 변경: 접근마다 새
UserDefaults를 만들어 @AppStorage(store:) 관찰이 끊기던 문제 수정
→ 설정에서 테마를 바꾸면 재시작 없이 즉시 적용됨
- 위젯 containerBackground에 강제 컬러 스킴을 직접 지정: 시스템이
배경을 위젯 환경으로 그려 라이트/다크 고정·앱 테마 일치가 실제
위젯에서 무시되던 문제 수정
- 테마 변경 시 위젯 타임라인 갱신 (앱 테마와 일치 옵션 즉시 반영)
- 리퀴드 글라스 실구현: 머티리얼+하이라이트 배경(GlassWidgetBackground),
유리 테두리 셀(WidgetCellBackground), 색이 비치는 틴트 셀
(WidgetTintedCellBackground, 행동 실행 위젯 적용)
- 검증 인자 -themeAutoToggle YES 추가 (3초 후 테마 반전)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
- 홈 위젯 5종(행동 실행/목표 진행률/다짐 진행률/다짐 현황/통계) 설정에
'위젯 테마' 옵션 추가
- 앱 테마와 일치: 앱의 라이트/다크 설정을 따름 (테마 키를 App Group으로 이관해
위젯이 읽을 수 있게 함)
- 라이트/다크 고정: 컬러 스킴 강제 + 해당 모드 팔레트
- 리퀴드 글라스: 반투명 머티리얼 배경 + 표면 셀도 머티리얼로 변형해
유리 질감 위에서 가독성 유지
- DEBUG 미리보기가 테마를 재현하도록 개선 (-widgetTheme light|dark|glass,
글라스는 그라데이션 배경 위에 렌더링)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
- 행동 실행(A): 소형1/중형3/대형4칸, Button(intent:)로 앱 없이 즉시 실행,
측정 중 실시간 타이머 + 노란 테두리, 표시 기간(오늘/이번 주/이번 달) 옵션
- 목표 진행률(B): 하루/주간/월간 가로 진행바, 소형1/중형2/대형4
- 다짐 진행률(C): 원형 링 + 기간 옵션, 단일 행동 다짐은 눌러서 실행,
'이하 유지'는 한도 지킴/초과로 표현
- 다짐 현황(D): 목표명 + 원형 링 그리드 (소형 2x2 / 중형 최대 8 / 대형 목표 2개)
- 통계: 행동 최대 3개 꺾은선 그래프, 앱 통계 탭과 동일 산식·색,
소형은 '한 달 일별' 제외 (스펙 §8.3)
- 잠금화면: circular/rectangular/inline, 표시 방식 3종(게이지/숫자/다짐 점)
- 전 위젯 프리미엄 게이트 (미결제 시 잠금 안내)
- DEBUG 미리보기 화면: -widgetPreview YES|lock, -widgetPreviewScroll B|C|D|S
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
- DataStore: App Group 컨테이너의 HaruDanim.store 사용, 기존 default.store 1회 자동 이관
- 프리미엄 + 동기화 토글 시 CloudKit(.private) 구성으로 컨테이너 생성, 실패하면 로컬 폴백
- CloudKit 요건(모든 관계 optional)에 맞춰 to-many 관계를 optional 저장 + 기존 이름
접근자로 리팩터링 (originalName 매핑으로 기존 데이터 유지)
- Tag/Action/Goal/Quest에 uuid 추가 (시리 단축어·위젯·워치 식별자) + 중복 보정
- 모델 레이어(Models/Settings/DayMath/QuestProgress/Formatters/Theme)를 Shared/로 이동
— 위젯 확장과 공유
- 집계 설정(주 시작 요일·하루 시작 시간·대표 시간·짧은 기록 무시)을 App Group defaults로
이관해 위젯·워치와 공유, 설정의 '기기 간 동기화' 토글 활성화
- Goal.combinedSpanRatio 공용화 (모음 탭 카드·위젯·시리가 동일 산식 사용)
- DEBUG 검증 인자: -cloudSync YES, -settingsScrollPremium YES
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
- Implement drag-and-drop functionality for users to reorder the active goals list
- Ensure the custom order of goals is persistently saved and loaded
- Filter out completed goals from the main active list to reduce visual clutter
- Add a 'View Completed Goals' button to navigate to a dedicated screen for finished items