From 8b1236d6a9e93d3144ca0d4eead3cabf330f5f97 Mon Sep 17 00:00:00 2001 From: songyc macbook Date: Sun, 23 Aug 2026 11:18:57 +0900 Subject: [PATCH] =?UTF-8?q?feat(1.5-p9):=20=EA=B1=B4=EA=B0=95=20=EB=8B=A4?= =?UTF-8?q?=EC=A7=90=20=ED=91=9C=EC=8B=9C=20=EC=83=89=20=E2=80=94=20Quest.?= =?UTF-8?q?healthColorHex(=EA=B8=B0=EB=B3=B8=20=EB=B6=84=ED=99=8D=3D?= =?UTF-8?q?=EB=B9=88=20=EA=B0=92),=20=ED=8E=B8=EC=A7=91=EA=B8=B0=20?= =?UTF-8?q?=EC=83=89=20=EC=84=A0=ED=83=9D,=20=EB=B9=8C=EB=93=9C=207?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - targetColor 건강 분기: 빈 값=시스템 분홍(다크 적응), 지정 시 hex — 단일 지점이라 목표 탭·모음·일기·위젯·워치 자동 반영 - 편집기 건강 섹션 '다짐 색'(프리셋 12+피커), 저장 시 기본색은 ''로·행동/꼬리표 전환 시 '' 정규화 - 타임테이블 블록 색과 별개, 시드 걸음 다짐에 #3E7CB1(대비 렌더 검증+스키마 내보내기 트리거) - QA: 일기 목표 카드에서 걸음=파랑·나머지=분홍 대비 실측, 편집기 렌더, 61건 ALL PASS, 3종 빌드 그린, l10n 0/0 - ⚠️ CloudKit 스키마 추가 — 콘솔 Deploy가 빌드 7 설치보다 선행 필수(CLAUDE.md·plan §12 후속 3) Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01WtZwRRjbtM9pZJDM4FkTq6 --- myApp/HaruDanim/CLAUDE.md | 6 +-- myApp/HaruDanim/Docs/plan-1.5.md | 7 ++++ .../Haru_Danim.xcodeproj/project.pbxproj | 16 ++++---- myApp/HaruDanim/IOS/Core/DebugSeed.swift | 13 +++++- myApp/HaruDanim/IOS/Localizable.xcstrings | 22 ++++++++-- myApp/HaruDanim/IOS/Views/HelpView.swift | 2 +- .../HaruDanim/IOS/Views/QuestEditorView.swift | 40 +++++++++++++++++++ .../Marketing/AppStore/whats-new-1.5.txt | 6 +-- myApp/HaruDanim/Shared/Models.swift | 10 ++++- 9 files changed, 102 insertions(+), 20 deletions(-) diff --git a/myApp/HaruDanim/CLAUDE.md b/myApp/HaruDanim/CLAUDE.md index 1c1e4f8..ce5a7e6 100644 --- a/myApp/HaruDanim/CLAUDE.md +++ b/myApp/HaruDanim/CLAUDE.md @@ -19,7 +19,7 @@ | 번들 ID | `com.yechan.HaruDanim` / App Group `group.com.yechan.HaruDanim` / CloudKit `iCloud.com.yechan.HaruDanim` | | 수익 모델 | 부분 유료화. 무료 한도(행동 10·목표 2·목표당 다짐 3) + 프리미엄 결제 시 해제 | | 결제 상품 | `com.yechan.HaruDanim.premium.monthly`(월 4,400원) / `.yearly`(년 44,000원) / `.lifetime`(77,000원) — **ASC 등록·판매 중(실제 가격, 2026-07-28)**. 로컬 테스트 구성(HaruDanim.storekit)도 동일 가격. 가격은 코드에 없고 `product.displayPrice`로 동적 표기, 년 구독 절약률 배지도 동적 계산 | -| 현재 상태 (2026-08-22) | **버전 1.5 (빌드 5) — 소킹 사용자 요구·실측 수정 전부 반영 완료(2026-08-22 밤), TestFlight 재업로드·소킹 재개. 사용자 예고: 기능 수정은 이것으로 종료(이후는 버그·오류 수정만)**. ✅**동기화 정지 이슈 해결 확인(2026-08-22 밤, 사용자 실기기)**: 일기에 도형·텍스트 상자(DiaryPageItem)가 있으면 그 기기의 CloudKit 동기화 전체가 정지하던 문제(내보내기 대기열 직렬 — 거부된 아이템 뒤로 전부 막힘) — 원인은 **1.3의 DiaryPageItem 스타일 필드 10종이 프로덕션 스키마에 없었던 것**(1.0 출시 때가 마지막 배포였고, 1.3 이후 개발 빌드가 iCloud 내보내기를 한 적이 없어 개발 스키마에도 미생성이었음). 해결 절차 실행: 시뮬 519869F7(사용자 iCloud 로그인·재인증)에서 일기 요소 시드 포함 전체 내보내기로 개발 스키마 필드 생성(success·error nil) → 사용자가 콘솔 재배포 → **도형·텍스트 상자 있는 상태의 동기화 왕복 정상 확인(사용자)**. 교훈: **새 모델 필드는 배포 전 '개발 빌드로 그 타입 레코드를 실제 내보냈는지'까지 확인할 것** — 콘솔 diff에 타입 이름이 떠도 필드가 전부 실렸는지 봐야 한다. 업로드 검증 실측 2건: 빌드 1=ITMS-90683(HealthKit 엔타이틀먼트 보유 시 읽기 전용이어도 `NSHealthUpdateUsageDescription` 필수 — 쓰기 사유 3언어 추가, 쓰기 요청이 없어 표시될 일 없음), 빌드 2=ITMS-90626(**앱 인텐트 메타데이터에 'iPhone' 단어 금지** — 신규 컴플리케이션 인텐트·위젯 설명에서 '하루 다님 앱'으로 교체. 화면 뷰 문구의 iPhone은 스캔 대상 아님[1.4 전례]) → **빌드 3**으로 재업로드. **1.5 추가분(빌드 4, 2026-08-22 — 소킹 중 사용자 요구, 스키마 무변경·전부 로컬 설정/표시 계층)**: ⑦**아이폰 일기 탭 개방**(§6.7 — AppTab.phoneCases 개방[radialOrder 필터 제거·버블 8개 자동 배치 확인], 노트 필기는 맥 '그리기' 토글 문법 재사용[DeviceLayout.isPhone 신설, drawingPolicy anyInput, 가로 스크롤 도구 줄, 배치↔그리기 상호 배타 — 아이패드 경로 무변경], 일기 잠금 설정 전 기기 노출) ⑧**일기 하루 정리 '건강 데이터' 카드**(§6.7 — DiarySection.health[케이스 마지막이라 기존 사용자 목록 끝에 추가], DiaryHealthCard: 지표 선택 시트 공용화[HealthMetricPickerSheet Binding화], 저장은 기기 로컬 diary.healthMetrics[비면 타일 선택 상속], 맥은 목록·화면 모두 숨김, 인쇄 요약에 값 줄 DiaryPrintHealthRow 동승) ⑨**일기 타임테이블 수면·운동 실구간 블록**(§6.7 — **HealthIntervals 신설**[App Group health.intervals.v1, 400일, 실구간을 논리적 하루로 분할 저장·병합, CloudKit 금지 동일], refreshRecent/백필이 유지, ExportSnapshot.injectingHealthBlocks 주입[캘린더 전례·최하층 렌더 healthBlockView 반투명+실선], 지표 고정색 수면 인디고·운동 주황, 필터 시트 '건강 데이터' 토글[RecordFilterSheet showsHealthSection — 전 날짜 공통 diary.timetableHealthHidden, 기본 켬]+**맥 안내 문구**, 일기 필터 버튼 상시 노출로 변경, 내보내기 렌더러 동일 주입) ⑩**수면 표시 구간 설정**(§6.8 — SleepWindowPrefs[LocalPrefs]: 전체 스펙+요일별 7종[켤 때만], 설정 → 건강 데이터 → '수면 표시 구간'[SleepWindowSettingsView — 시작=끝이면 24시간 창], 평문 'sleep' 캐시 키=그날 유효 구간 값으로 변경[타일·일기 카드 공유], 백필 서명에 요일 매핑 포함[배정만 바뀌어도 재백필], **새 수면 다짐 기본 구간을 여기서 시드**) ⑪일기 목표 카드의 건강 다짐 값 단위 실측 수정("8,432회/8,000보"→지표 단위 — DiaryGoalsCard.valueLabel healthTarget 분기) ⑫**소킹 실기기 실측 버그 2건 수정(빌드 5)**: ⓐ더보기 탭 안 일기 달력에서 날짜 탭이 조용히 무시됨 — `AppRouter.morePath`가 `[AppTab]` 고정 타입이라 Date 푸시 불가 → **NavigationPath로 변경**(회귀 감시 인자 `-morePushDiaryToday`, 라디얼·사이드바는 원래 무사) ⓑ수면 블록이 수면 단계(코어·렘) 로우데이터대로 칸칸이 갈라짐 → **10분 이하의 깸은 이어 붙여 한 덩어리로**(DiaryHealthTimetable.sleepDisplayMergeGap — 표시 전용, 값 무영향. 20분쯤 깼다 자면 나뉘는 게 맞다는 사용자 규칙) ⑬**기록 탭 타임테이블에도 수면·운동 블록**(하루·주간 — DiaryHealthTimetable.blocks 단일 공급 지점·숨김 토글 공유[기록 필터 시트에도 건강 섹션], 내보내기는 `injectingHealthBlocks(forDayKeys:math:)`로 하루·주간 주입 + trim 표시 범위를 블록만큼 확장) ⑭**타임테이블 표시 색 설정**(설정 → 건강 데이터 → '타임테이블 표시 색' — 수면·운동 ColorPicker, 기본 인디고·주황[빈 값], 전 타임테이블·내보내기 공통 적용, 인자 `-healthColorPreview`) ⑮**버블 찌그러짐 실측 수정(빌드 6, 2026-08-23)**: 일기 버블 추가로 8개가 되자 이웃 간격(~9.6pt)이 유리 합체 판정 거리(18pt) 안으로 들어와 정지 상태에서도 원들이 서로를 향해 늘어남 — `glassBlendSpacing` 18→6(펼침 상태 정원 분리, FAB 모핑은 겹침 구간이라 유지. 마케팅 06-bubble 3언어 재촬영). 검증: 61/20/27/10 ALL PASS(26.5), 3종 빌드 그린, 전 카탈로그 missing/stale 0, 시각 QA(아이폰 요약·건강 카드·타임테이블 블록·노트 도구 줄·버블 8개·수면 구간 화면·아이패드·맥 분기·18.5). 스토어 자료: whats-new-1.5에 일기 확장 절 추가·설명 3언어 일기 항목 갱신. 신규 인자 `-sleepWindowPreview`(§14), `-seedHealthCache`가 실구간(수면 자정 분할+달리기)도 시드. 계획·결정 이력은 `Docs/plan-1.5.md`(전 섹션 ✅구현 완료). 1.5 내용: ①**워치 '행동 기록' 컴플리케이션**(§11 — 행동 편집 옵트인+표시 기간 5종[하루/이번 주/이번 달/지난 7일/지난 30일, 롤링은 rollingRange 재사용], 측정 중 노란 타이머, 탭=워치 앱 미니 행동 화면 push[뒤로가기=메인], recommendations 상한 없음) ②**모음 탭 건강 데이터 타일**(무료, §6.1 — 걸음·운동·수면 등 8지표 선택·순서, 접기, 연결 CTA[명시적 탭 권한], 안내 시트, 즐겨찾기·나머지·건강 3섹션 순서 설정[§6.8], 맥은 섹션 숨김) ③**건강 다짐**(프리미엄, §4.2·§6.4 — 8지표+운동 종목 20종[workout. 인코딩], 수면은 다짐별 수면 구간[기본 21:00~09:00]을 '구간 끝이 속한 논리적 하루'에 통귀속[겹침 분할과 다른 의도된 예외], 하루 단위 전용·마감 시각 미지원, QuestProgress 값 공급 단일 지점 3곳만 분기[수학 무변경 — 기존 49건 그린이 증거], HealthCache[App Group, 400일, ⚠️5.1.3: 값은 CloudKit 저장 금지 — 정의만 동기화]·백필·부트스트랩, 데이터 없는 기기는 모수 제외+'데이터 없음' 표기+판정 보류, 구버전 이중 상태는 행동/꼬리표 우선 정규화) ④**신기능 소개 팝업**(WhatsNewView — 버전당 1회, 신규 설치 시드로 미표시, 온보딩 우선, 全기기 업데이트 안내) ⑤**도움말 전면 자연화+신규 주제 3개**(사용자 예약 작업 — 오타·번역투·UI 명칭 정정, en/ja 전면 재번역·용어 통일[Action/アクション 등]) ⑥HealthKit 엔타이틀먼트(iOS 앱만)+NSHealthShareUsageDescription 3언어+PRIVACY.md 건강 문단. 검증: `-progressSelfTest` **61건**(건강 H 시리즈 12 신규)·20·27·10 ALL PASS(26.5+18.5 심), Debug/Store/워치(26.2·11.5) 빌드, 시각 QA 20여 장(워치 컴플리케이션 실데이터·미니 화면·타일·다짐 행·편집기·팝업·ja 도움말), 실버전 업그레이드 팝업 경로·벌크 1만 건+건강 결합 확인. 스토어 자료: whats-new-1.5·promotional-text-1.5·설명 3언어 갱신, **스크린샷 전면 신규 — 아이폰 10·아이패드 10·워치 1 × ko/en/ja 원본 57장+합성 63장 재생성 완료**(09-records→09-health 교체, Marketing/README 절차·주의 갱신). **CloudKit 프로덕션 스키마 배포 완료(2026-08-22, 사용자 콘솔 실행)** — Quest 신규 필드 3종(healthMetricRaw·sleepWindow*)은 개발 스키마에 없어서(디버그 내보내기 이력 없음이 원인) 시뮬 519869F7에 사용자 iCloud 로그인 후 디버그 빌드를 `-premium YES -cloudSync YES -seedHealthQuest YES`로 실행 → Sandbox 환경 전체 내보내기 성공(98레코드, error nil)으로 필드 생성 → 콘솔 배포(이 시뮬은 iCloud 로그인 유지 — 향후 스키마 작업 재사용 가능). **실측 발견: 1.3의 DiaryPageItem 스타일 필드가 프로덕션 미배포 상태였음**(마지막 배포=1.0 출시 시점 — 1.3 출시[8/6] 이후 도형·텍스트 상자 신규 스타일 필드 동기화가 조용히 실패했을 가능성, 이번 배포로 해소·밀린 내보내기는 자동 재시도. 소킹 중 아이패드↔맥 요소 동기화 교차 확인 권장). **남은 출시 절차(사용자)**: ①TestFlight 실기기 소킹(진행 중 — 실제 건강 데이터·워치 컴플리케이션·기기 간 건강 다짐 정의 동기화 중점) ②ASC 심사 제출(스크린샷 framed 세트 교체·whats-new/프로모션/설명 반영). **1.6 후보 보류 기록: `Docs/plan-1.6.md`**(타임테이블 건강 데이터 표시 — 2026-08-22 사용자 "일단 보류", 구현 금지·재논의 시 착수). 운동 종목 목록(20종)은 §3.4 — 사용자 실사용 종목 빠졌으면 추가 요청. **버전 1.4 (빌드 3) App Store 출시 완료(2026-08-13, 사용자 확인)** — 2026-08-13 심사 제출 후 같은 날 출시 확인. TestFlight 실기기 테스트(문제 없음 확인) 후 제출했음. iOS 18 실기기는 미확보로 미테스트(시뮬 검증 106건 ALL PASS로 갈음 — 해당 사용자 유입 시 피드백 대응 예정). 1.4 내용(사용자 A안 승인, 2026-08-11 세션에서 전부 구현·검증): ①**iOS 18.0 하한 인하**(위 플랫폼 행 — 글라스 버블 머티리얼 폴백·사용자 심볼 안전 렌더 `Image(safeSymbol:)`[iOS 55곳+워치 7곳, 18에 없는 카탈로그 심볼 3개 물음표 폴백]·`-symbolAuditDump`. ⚠️하한 18 Release(-O wholemodule)에서 swift-frontend가 제네릭 중첩 Coordinator의 deinit 최적화 중 크래시하는 컴파일러 버그 실측 — DiaryZoomCoordinator를 비제네릭 톱레벨+AnyView 소거로 우회, 되돌리지 말 것) ②**펜슬 저장 디바운스**(§6.7 — 획마다 전체 직렬화·블랍 재기록하던 버벅임 해소) ③**통계 '오늘 기준' 롤링**(§6.6·§10 ⑤ — 지난 7일/30일) ④**CSV 구간 내보내기**(§6.8, 코어 CSVExport 추출) ⑤**일기 내보내기 후 삭제**(§6.7, 렌더 코어 DiaryExportRenderer 추출) ⑥**데이터 정리·초기화**(§6.8 — 전체/처음~날짜까지+백업 3종[CSV·일기 PDF·정리 리포트 ArchiveReport]+**'일기만' 대상 축**[1.4(3), 2026-08-12 — 기록·구조·양식 보존, 백업은 일기 PDF만, `DataReset.deleteDiaries`·`-dataResetScope diary`·자가 검증 27건으로 확장]) ⑧**라디얼 모드 FAB 가림 수정**(1.4(3) — 목록 마지막 행이 FAB에 가려지던 실측 문제: 각 탭 루트에 하단 safeAreaInset 78pt, ⚠️NavigationStack '안쪽'에 붙일 것[바깥은 TabView가 safe area 재설정해 무시됨, 실측]) ⑦도움말 재구성(1.4(2) 검수 후속, 2026-08-12 — 뭉친 주제 3곳 분리: 기록·통계 그룹에 '지난 7일·30일로 보기'·'데이터 정리·초기화' 독립 주제 신설[CSV 주제는 백업·복원만, 비교 주제는 1.3 원문 복귀], 일기 그룹 '펜슬 노트 페이지'에서 '사진·도형·텍스트 꾸미기' 분리. 이미지는 그룹당 대표 1주제 원칙 유지 — 18장 전수 실사로 참조·언어 매칭 무결 확인)·l10n(전 카탈로그 missing/stale 0)·**워치 실행 햅틱 .click→.success 상향**(1.4(2) — 실사용 '너무 약함' 보고)·MARKETING_VERSION 1.4/**빌드 3**(TestFlight 재업로드용 — 같은 버전은 빌드 번호만 올려 업로드하면 1.4(2)로 기존 테스터에 배포됨)·`Marketing/AppStore/whats-new-1.4.txt`. 검증: 자가 검증 `-progressSelfTest` 49·`-csvImportTest` 20·`-intentSmokeTest` 10·`-dataResetTest` 27 ALL PASS(26 심+18.5 심), Debug/Store/워치 빌드 성공, 18.5·26 시각 QA(버블 폴백·일기 줌·롤링 통계·초기화 화면·리포트 PDF 3페이지 실물). **스토어 제출 시**: 하한 인하는 ASC에서 바꿀 것 없음(바이너리에서 자동 파생), 스크린샷 재촬영 불필요(통계 토글·설정 행 추가는 사소 — 교체 여부는 사용자 판단), 심사 특이사항 없음. 스토어 텍스트는 1.4(3)에서 한국어 문장 흐름 자연화(사용자 피드백 — 설명 ko 자연화+3언어에 1.4 기능 2줄 추가, whats-new 전면 재작성, 프로모션 1.4 전용 `promotional-text-1.4.txt`). **📌 다음 버전(1.5) 확정 계획 — 상세는 `Docs/plan-1.5.md`(2026-08-20 사용자 결정 완료)**: ①워치 행동 컴플리케이션(행동 편집에서 옵트인+기간 선택[하루/이번 주/이번 달/지난 7일/지난 30일], 탭=미니 행동 화면 착지·뒤로가기로 메인 복귀) ②건강 데이터 통합(모음 탭 타일 **무료**+건강 다짐 **프리미엄**, HealthCache 구조[값은 CloudKit 저장 금지 — 5.1.3], 수면은 사용자 지정 수면 구간→깨어난 날 귀속, 모음 탭 3섹션[즐겨찾기·나머지·건강] 순서 설정) ③도움말(HelpView) 전체 문구 한국어 기준 자연화(사용자 지시 2026-08-12 — ~해요체 유지·번역투 제거·en/ja 재검토·l10n 루틴) ④업데이트 신기능 소개 팝업(버전당 1회, 全기기 업데이트 안내 — 계획서 §11). 운동 세부 종목 다짐 포함(§3.4), 스크린샷 전면 신규(아이폰·아이패드 각 10장 — §6), 모든 사전 결정 완료(결정 이력 8건·위험 검토 R1~R16). 하위 OS 인하는 검토 후 기각(근거는 계획서 §4 — 재제안 금지). ⚠️**구현은 사용자의 "진행/시작" 지시가 있을 때만 착수** — 그 전까지 코드 무변경, 추가 요구는 계획서에 계속 반영. **버전 1.3 App Store 출시 2026-08-06** — 3일 실사용+심층 검증(2026-08-05: 자가 검증 3종 ALL PASS·벌크 1만 건·일기 내보내기 일치·위젯 스모크·만료 열람·도움말 — 회귀 0) 통과 후 제출. 심층 검증에서 기록한 사소 잔여 엣지 9건은 후속 후보로만 보류(전부 극단 한정·자가 복구형, 필기 blob 동시 편집 한계는 §6.7). 1.3 내용: 아래 소기능 이력의 일기 개선 묶음(양식 펜 색 고정 + 도형·텍스트 상자 편집 개편 + 검토 후속 수정), `Marketing/AppStore/whats-new-1.3.txt`. 잔여 엣지 9건 상세: 최소 크기 커밋 스냅백·일기 상세 이탈 시 빈 텍스트 상자 잔존·페이지 가장자리 손잡이 클리핑·인라인 편집 중 페이지 스와이프 상태 잔존·회전 상자 커서 어색함 등(1.0부터의 구조 한계인 필기 blob 동시 편집 덮어쓰기·열린 캔버스 원격 미갱신은 §6.7, 같은 페이지 동시 필기 회피 권장). 1.2 내용: 주기 몫 완료 상태 표기(§4.2)+도움말 '진행률 읽는 법' 갱신(상세는 아래 소기능 이력). **버전 1.1 출시 2026-07-30.** 1.1 내용: ①**맥 일기 개방**(§6.7 — 사이드바 노출 + '그리기' 토글로 마우스 필기, 텍스트 우선 도구줄. 아이패드 경로 불변. 맥 실기 확인 완료) ②**CSV 가져오기**(§6.8 — 프리미엄, 추가 전용·미리 보기·멱등. 검증 `-csvImportTest` 20건 ALL PASS) ③**일기 기본 표시 설정**(§6.7 — 캘린더·목표·행동 전 날짜 기본값 + 날짜별 재정의, 스키마 무변경 마커 방식) ④**'짧은 기록 무시' iCloud KVS 동기화**(§6.8 — 전 기기 공통) ⑤스크린샷 전면 개편(아이폰 10·아이패드 10·워치 합성 1 × ko/en/ja — ASC 업로드 완료) ⑥스토어 메타데이터 변경(앱 이름·부제목·키워드·프로모션 — 검색·색인 강화, `Marketing/AppStore/app-name-subtitle.txt`·`keywords.txt`·`promotional-text.txt`. 스토어 표기만 변경, 설치 이름 불변) ⑦MARKETING_VERSION 1.1. **버전 1.0 출시 2026-07-28.** 이후 작업은 사용자 실사용 중 발견한 버그 수정·사용자가 원하는 소기능 추가만 한다(선제적 기능 제안·대규모 리팩터링 금지). 출시 후 소기능 이력: **일기 도형·텍스트 상자 UX 2차 개편**(2026-08-03, 사용자 요청 — §6.7. 종류별 모양 손잡이[사각형 꼭짓점 4개·원 상하좌우 4개·선/화살표 양 끝점]와 정사각형·정원 스냅 피드백, 텍스트 상자 제자리 입력[탭→바로 키보드]·테두리 색 독립, '글 수정'→'스타일' 시트로 재편, borderColorHex 필드 추가. 1.3으로 버전 상향)·**일기 도형·텍스트 상자 편집 강화**(2026-08-03, 사용자 요청 — §6.7. "정해진 모양·크기 그대로만 나온다"는 보고: 크기 손잡이(가로세로 자유·맥 마우스 대응)·회전 제스처·'도형 수정' 시트[색·선 굵기·채우기·모서리 둥글기·회전]·텍스트 시트 확장[글자 크기·굵게·정렬·테두리], DiaryPageItem에 기본값 필드 8개 추가)·**양식 페이지 펜 색 고정**(2026-08-03, 사용자 요청 — §6.7. 다크/라이트 잉크 반전으로 맥·아이패드에서 필기가 안 보이던 실사용 보고 해소, 내보내기 라이트 트레잇 고정 포함)·**주기 몫 완료 상태 표기**(2026-08-01, 사용자 요청 — §4.2. 도움말 '진행률 읽는 법' 문구도 갱신. 같은 날 MARKETING_VERSION 1.2(빌드 1)로 상향 + `Marketing/AppStore/whats-new-1.2.txt` 작성·TestFlight 업로드, **심사 통과 → App Store 출시 완료(2026-08-02, 사용자 확인)**). 업데이트 제출: 버전 올려 빌드 업로드 → 심사 제출(IAP는 첫 심사에서 승인됐으므로 첨부 불필요). 출시 전 이력 — RC는 커밋 `f05e611`(버전 1.0 (1)), 이후 실사용 보고 기반 수정 라운드(전부 커밋·푸시·실기기 확인 완료): l10n 누락 일괄·ja 앱 이름 'Haru Danim' 통일·워치 컴플리케이션 추천 캡 제거(§11)·⑥ 위젯 종료 버튼(§10)·진행률 환산 캡+수행일 집계+수행일 아님 표기(§4.2)·파일명/CSV 헤더 현지화(§7)·워치 컴플리케이션 목표 필터(§6.4·§11, 사용자 승인 소기능)·기록 시각 입력 상시 휠 다이얼+분 절사(§6.5)·일기 달력 기분 사진 백레이어(§6.7)·다짐 없는 목표 '다짐 없음' 표기(§4.3)·워치 측정 중 행 탭 종료(§11)·도움말 예시 스크린샷 18장(§6.8)·설정 하루 시작 시간 접힘 행(§6.5)·**모음 탭 즐겨찾기 모아 보기**(§6.1 — 행동 많아질 때 혼잡도 대응, 사용자 승인 소기능. v1 별도 카드 가로 줄[대안 A~F 중 A]이 "따로 노는 느낌" 실사용 피드백으로 v2 그리드 섹션 통합+나머지 접기로 교체, 같은 날 후속 피드백으로 편집 모드 섹션 인지·섹션 간 드래그 지정/해제·"지정 순서대로 뒤에" 규칙 추가, 2026-07-22)·**en 복수형 정리**(2026-07-22 — 수량 1일 때 "1 times/quests" 류 오류를 카탈로그 plural variation으로 14건 전환[iOS 10·위젯 3·워치 1], 모음 탭 섹션 제목 en "Favorite"→"Favorites"로 워치와 통일. ko/ja 무영향). **App Store 등록 자료는 `Marketing/`에 완비**(설명·키워드·구독 메타·스크린샷 원본/합성판, README에 재생성 절차 — 앱 변경이 자료에 영향 주면 요청 없이 함께 갱신할 것. 2026-07-22 즐겨찾기 섹션(v2) 반영해 아이폰·아이패드 01-main과 help-main ko/en/ja 재촬영·합성판 재생성. **2026-07-29 스크린샷 세트 확장** — 아이폰 8장(+위젯·버블 메뉴·iCloud 동기화 합성·다크 모드)/아이패드 7장(+주간 타임테이블·위젯·동기화 합성) × ko/en/ja, 촬영·합성 절차는 Marketing/README '추가 스크린샷' 절. **1.1 제출 때 ASC 업로드 완료**). **사업자 등록·통신판매업 신고 완료(2026-07-22)** — 서류 절차 끝, ASC 등록·유료 계약 진행 가능(순서는 Marketing/README 체크리스트). 사용자는 계속 실사용 테스트 중이며 버그 보고 시: 최소 변경 + 시뮬레이터 재검증 + l10n 루틴(§2.3) + Debug/Store(워치 파일이면 워치까지) 빌드 + 커밋·푸시 | +| 현재 상태 (2026-08-22) | **버전 1.5 (빌드 5) — 소킹 사용자 요구·실측 수정 전부 반영 완료(2026-08-22 밤), TestFlight 재업로드·소킹 재개. 사용자 예고: 기능 수정은 이것으로 종료(이후는 버그·오류 수정만)**. ✅**동기화 정지 이슈 해결 확인(2026-08-22 밤, 사용자 실기기)**: 일기에 도형·텍스트 상자(DiaryPageItem)가 있으면 그 기기의 CloudKit 동기화 전체가 정지하던 문제(내보내기 대기열 직렬 — 거부된 아이템 뒤로 전부 막힘) — 원인은 **1.3의 DiaryPageItem 스타일 필드 10종이 프로덕션 스키마에 없었던 것**(1.0 출시 때가 마지막 배포였고, 1.3 이후 개발 빌드가 iCloud 내보내기를 한 적이 없어 개발 스키마에도 미생성이었음). 해결 절차 실행: 시뮬 519869F7(사용자 iCloud 로그인·재인증)에서 일기 요소 시드 포함 전체 내보내기로 개발 스키마 필드 생성(success·error nil) → 사용자가 콘솔 재배포 → **도형·텍스트 상자 있는 상태의 동기화 왕복 정상 확인(사용자)**. 교훈: **새 모델 필드는 배포 전 '개발 빌드로 그 타입 레코드를 실제 내보냈는지'까지 확인할 것** — 콘솔 diff에 타입 이름이 떠도 필드가 전부 실렸는지 봐야 한다. 업로드 검증 실측 2건: 빌드 1=ITMS-90683(HealthKit 엔타이틀먼트 보유 시 읽기 전용이어도 `NSHealthUpdateUsageDescription` 필수 — 쓰기 사유 3언어 추가, 쓰기 요청이 없어 표시될 일 없음), 빌드 2=ITMS-90626(**앱 인텐트 메타데이터에 'iPhone' 단어 금지** — 신규 컴플리케이션 인텐트·위젯 설명에서 '하루 다님 앱'으로 교체. 화면 뷰 문구의 iPhone은 스캔 대상 아님[1.4 전례]) → **빌드 3**으로 재업로드. **1.5 추가분(빌드 4, 2026-08-22 — 소킹 중 사용자 요구, 스키마 무변경·전부 로컬 설정/표시 계층)**: ⑦**아이폰 일기 탭 개방**(§6.7 — AppTab.phoneCases 개방[radialOrder 필터 제거·버블 8개 자동 배치 확인], 노트 필기는 맥 '그리기' 토글 문법 재사용[DeviceLayout.isPhone 신설, drawingPolicy anyInput, 가로 스크롤 도구 줄, 배치↔그리기 상호 배타 — 아이패드 경로 무변경], 일기 잠금 설정 전 기기 노출) ⑧**일기 하루 정리 '건강 데이터' 카드**(§6.7 — DiarySection.health[케이스 마지막이라 기존 사용자 목록 끝에 추가], DiaryHealthCard: 지표 선택 시트 공용화[HealthMetricPickerSheet Binding화], 저장은 기기 로컬 diary.healthMetrics[비면 타일 선택 상속], 맥은 목록·화면 모두 숨김, 인쇄 요약에 값 줄 DiaryPrintHealthRow 동승) ⑨**일기 타임테이블 수면·운동 실구간 블록**(§6.7 — **HealthIntervals 신설**[App Group health.intervals.v1, 400일, 실구간을 논리적 하루로 분할 저장·병합, CloudKit 금지 동일], refreshRecent/백필이 유지, ExportSnapshot.injectingHealthBlocks 주입[캘린더 전례·최하층 렌더 healthBlockView 반투명+실선], 지표 고정색 수면 인디고·운동 주황, 필터 시트 '건강 데이터' 토글[RecordFilterSheet showsHealthSection — 전 날짜 공통 diary.timetableHealthHidden, 기본 켬]+**맥 안내 문구**, 일기 필터 버튼 상시 노출로 변경, 내보내기 렌더러 동일 주입) ⑩**수면 표시 구간 설정**(§6.8 — SleepWindowPrefs[LocalPrefs]: 전체 스펙+요일별 7종[켤 때만], 설정 → 건강 데이터 → '수면 표시 구간'[SleepWindowSettingsView — 시작=끝이면 24시간 창], 평문 'sleep' 캐시 키=그날 유효 구간 값으로 변경[타일·일기 카드 공유], 백필 서명에 요일 매핑 포함[배정만 바뀌어도 재백필], **새 수면 다짐 기본 구간을 여기서 시드**) ⑪일기 목표 카드의 건강 다짐 값 단위 실측 수정("8,432회/8,000보"→지표 단위 — DiaryGoalsCard.valueLabel healthTarget 분기) ⑫**소킹 실기기 실측 버그 2건 수정(빌드 5)**: ⓐ더보기 탭 안 일기 달력에서 날짜 탭이 조용히 무시됨 — `AppRouter.morePath`가 `[AppTab]` 고정 타입이라 Date 푸시 불가 → **NavigationPath로 변경**(회귀 감시 인자 `-morePushDiaryToday`, 라디얼·사이드바는 원래 무사) ⓑ수면 블록이 수면 단계(코어·렘) 로우데이터대로 칸칸이 갈라짐 → **10분 이하의 깸은 이어 붙여 한 덩어리로**(DiaryHealthTimetable.sleepDisplayMergeGap — 표시 전용, 값 무영향. 20분쯤 깼다 자면 나뉘는 게 맞다는 사용자 규칙) ⑬**기록 탭 타임테이블에도 수면·운동 블록**(하루·주간 — DiaryHealthTimetable.blocks 단일 공급 지점·숨김 토글 공유[기록 필터 시트에도 건강 섹션], 내보내기는 `injectingHealthBlocks(forDayKeys:math:)`로 하루·주간 주입 + trim 표시 범위를 블록만큼 확장) ⑭**타임테이블 표시 색 설정**(설정 → 건강 데이터 → '타임테이블 표시 색' — 수면·운동 ColorPicker, 기본 인디고·주황[빈 값], 전 타임테이블·내보내기 공통 적용, 인자 `-healthColorPreview`) ⑮**버블 찌그러짐 실측 수정(빌드 6, 2026-08-23)**: 일기 버블 추가로 8개가 되자 이웃 간격(~9.6pt)이 유리 합체 판정 거리(18pt) 안으로 들어와 정지 상태에서도 원들이 서로를 향해 늘어남 — `glassBlendSpacing` 18→6(펼침 상태 정원 분리, FAB 모핑은 겹침 구간이라 유지. 마케팅 06-bubble 3언어 재촬영) ⑯**건강 다짐 표시 색(빌드 7, 2026-08-23 — 사용자 요구)**: 건강 다짐이 고정 분홍이던 것을 편집기 건강 섹션에서 색 선택(프리셋 12+피커, 기본 분홍=빈 값[시스템 분홍의 다크 적응 유지]) — **Quest 신규 필드 `healthColorHex`**(기본 "", targetColor 단일 지점 분기라 목표 탭·모음 카드·일기·위젯·워치 자동 반영, 행동·꼬리표 다짐은 저장 시 "" 정규화, 타임테이블 블록 색과 별개). ⚠️**CloudKit 스키마 추가 — 배포 절차(개발 내보내기→콘솔 Deploy)가 빌드 7 설치보다 선행 필수**(DiaryPageItem 전례 — 미배포 상태로 다짐 수정 시 그 기기 동기화 정지). 검증: 61/20/27/10 ALL PASS(26.5), 3종 빌드 그린, 전 카탈로그 missing/stale 0, 시각 QA(아이폰 요약·건강 카드·타임테이블 블록·노트 도구 줄·버블 8개·수면 구간 화면·아이패드·맥 분기·18.5). 스토어 자료: whats-new-1.5에 일기 확장 절 추가·설명 3언어 일기 항목 갱신. 신규 인자 `-sleepWindowPreview`(§14), `-seedHealthCache`가 실구간(수면 자정 분할+달리기)도 시드. 계획·결정 이력은 `Docs/plan-1.5.md`(전 섹션 ✅구현 완료). 1.5 내용: ①**워치 '행동 기록' 컴플리케이션**(§11 — 행동 편집 옵트인+표시 기간 5종[하루/이번 주/이번 달/지난 7일/지난 30일, 롤링은 rollingRange 재사용], 측정 중 노란 타이머, 탭=워치 앱 미니 행동 화면 push[뒤로가기=메인], recommendations 상한 없음) ②**모음 탭 건강 데이터 타일**(무료, §6.1 — 걸음·운동·수면 등 8지표 선택·순서, 접기, 연결 CTA[명시적 탭 권한], 안내 시트, 즐겨찾기·나머지·건강 3섹션 순서 설정[§6.8], 맥은 섹션 숨김) ③**건강 다짐**(프리미엄, §4.2·§6.4 — 8지표+운동 종목 20종[workout. 인코딩], 수면은 다짐별 수면 구간[기본 21:00~09:00]을 '구간 끝이 속한 논리적 하루'에 통귀속[겹침 분할과 다른 의도된 예외], 하루 단위 전용·마감 시각 미지원, QuestProgress 값 공급 단일 지점 3곳만 분기[수학 무변경 — 기존 49건 그린이 증거], HealthCache[App Group, 400일, ⚠️5.1.3: 값은 CloudKit 저장 금지 — 정의만 동기화]·백필·부트스트랩, 데이터 없는 기기는 모수 제외+'데이터 없음' 표기+판정 보류, 구버전 이중 상태는 행동/꼬리표 우선 정규화) ④**신기능 소개 팝업**(WhatsNewView — 버전당 1회, 신규 설치 시드로 미표시, 온보딩 우선, 全기기 업데이트 안내) ⑤**도움말 전면 자연화+신규 주제 3개**(사용자 예약 작업 — 오타·번역투·UI 명칭 정정, en/ja 전면 재번역·용어 통일[Action/アクション 등]) ⑥HealthKit 엔타이틀먼트(iOS 앱만)+NSHealthShareUsageDescription 3언어+PRIVACY.md 건강 문단. 검증: `-progressSelfTest` **61건**(건강 H 시리즈 12 신규)·20·27·10 ALL PASS(26.5+18.5 심), Debug/Store/워치(26.2·11.5) 빌드, 시각 QA 20여 장(워치 컴플리케이션 실데이터·미니 화면·타일·다짐 행·편집기·팝업·ja 도움말), 실버전 업그레이드 팝업 경로·벌크 1만 건+건강 결합 확인. 스토어 자료: whats-new-1.5·promotional-text-1.5·설명 3언어 갱신, **스크린샷 전면 신규 — 아이폰 10·아이패드 10·워치 1 × ko/en/ja 원본 57장+합성 63장 재생성 완료**(09-records→09-health 교체, Marketing/README 절차·주의 갱신). **CloudKit 프로덕션 스키마 배포 완료(2026-08-22, 사용자 콘솔 실행)** — Quest 신규 필드 3종(healthMetricRaw·sleepWindow*)은 개발 스키마에 없어서(디버그 내보내기 이력 없음이 원인) 시뮬 519869F7에 사용자 iCloud 로그인 후 디버그 빌드를 `-premium YES -cloudSync YES -seedHealthQuest YES`로 실행 → Sandbox 환경 전체 내보내기 성공(98레코드, error nil)으로 필드 생성 → 콘솔 배포(이 시뮬은 iCloud 로그인 유지 — 향후 스키마 작업 재사용 가능). **실측 발견: 1.3의 DiaryPageItem 스타일 필드가 프로덕션 미배포 상태였음**(마지막 배포=1.0 출시 시점 — 1.3 출시[8/6] 이후 도형·텍스트 상자 신규 스타일 필드 동기화가 조용히 실패했을 가능성, 이번 배포로 해소·밀린 내보내기는 자동 재시도. 소킹 중 아이패드↔맥 요소 동기화 교차 확인 권장). **남은 출시 절차(사용자)**: ①TestFlight 실기기 소킹(진행 중 — 실제 건강 데이터·워치 컴플리케이션·기기 간 건강 다짐 정의 동기화 중점) ②ASC 심사 제출(스크린샷 framed 세트 교체·whats-new/프로모션/설명 반영). **1.6 후보 보류 기록: `Docs/plan-1.6.md`**(타임테이블 건강 데이터 표시 — 2026-08-22 사용자 "일단 보류", 구현 금지·재논의 시 착수). 운동 종목 목록(20종)은 §3.4 — 사용자 실사용 종목 빠졌으면 추가 요청. **버전 1.4 (빌드 3) App Store 출시 완료(2026-08-13, 사용자 확인)** — 2026-08-13 심사 제출 후 같은 날 출시 확인. TestFlight 실기기 테스트(문제 없음 확인) 후 제출했음. iOS 18 실기기는 미확보로 미테스트(시뮬 검증 106건 ALL PASS로 갈음 — 해당 사용자 유입 시 피드백 대응 예정). 1.4 내용(사용자 A안 승인, 2026-08-11 세션에서 전부 구현·검증): ①**iOS 18.0 하한 인하**(위 플랫폼 행 — 글라스 버블 머티리얼 폴백·사용자 심볼 안전 렌더 `Image(safeSymbol:)`[iOS 55곳+워치 7곳, 18에 없는 카탈로그 심볼 3개 물음표 폴백]·`-symbolAuditDump`. ⚠️하한 18 Release(-O wholemodule)에서 swift-frontend가 제네릭 중첩 Coordinator의 deinit 최적화 중 크래시하는 컴파일러 버그 실측 — DiaryZoomCoordinator를 비제네릭 톱레벨+AnyView 소거로 우회, 되돌리지 말 것) ②**펜슬 저장 디바운스**(§6.7 — 획마다 전체 직렬화·블랍 재기록하던 버벅임 해소) ③**통계 '오늘 기준' 롤링**(§6.6·§10 ⑤ — 지난 7일/30일) ④**CSV 구간 내보내기**(§6.8, 코어 CSVExport 추출) ⑤**일기 내보내기 후 삭제**(§6.7, 렌더 코어 DiaryExportRenderer 추출) ⑥**데이터 정리·초기화**(§6.8 — 전체/처음~날짜까지+백업 3종[CSV·일기 PDF·정리 리포트 ArchiveReport]+**'일기만' 대상 축**[1.4(3), 2026-08-12 — 기록·구조·양식 보존, 백업은 일기 PDF만, `DataReset.deleteDiaries`·`-dataResetScope diary`·자가 검증 27건으로 확장]) ⑧**라디얼 모드 FAB 가림 수정**(1.4(3) — 목록 마지막 행이 FAB에 가려지던 실측 문제: 각 탭 루트에 하단 safeAreaInset 78pt, ⚠️NavigationStack '안쪽'에 붙일 것[바깥은 TabView가 safe area 재설정해 무시됨, 실측]) ⑦도움말 재구성(1.4(2) 검수 후속, 2026-08-12 — 뭉친 주제 3곳 분리: 기록·통계 그룹에 '지난 7일·30일로 보기'·'데이터 정리·초기화' 독립 주제 신설[CSV 주제는 백업·복원만, 비교 주제는 1.3 원문 복귀], 일기 그룹 '펜슬 노트 페이지'에서 '사진·도형·텍스트 꾸미기' 분리. 이미지는 그룹당 대표 1주제 원칙 유지 — 18장 전수 실사로 참조·언어 매칭 무결 확인)·l10n(전 카탈로그 missing/stale 0)·**워치 실행 햅틱 .click→.success 상향**(1.4(2) — 실사용 '너무 약함' 보고)·MARKETING_VERSION 1.4/**빌드 3**(TestFlight 재업로드용 — 같은 버전은 빌드 번호만 올려 업로드하면 1.4(2)로 기존 테스터에 배포됨)·`Marketing/AppStore/whats-new-1.4.txt`. 검증: 자가 검증 `-progressSelfTest` 49·`-csvImportTest` 20·`-intentSmokeTest` 10·`-dataResetTest` 27 ALL PASS(26 심+18.5 심), Debug/Store/워치 빌드 성공, 18.5·26 시각 QA(버블 폴백·일기 줌·롤링 통계·초기화 화면·리포트 PDF 3페이지 실물). **스토어 제출 시**: 하한 인하는 ASC에서 바꿀 것 없음(바이너리에서 자동 파생), 스크린샷 재촬영 불필요(통계 토글·설정 행 추가는 사소 — 교체 여부는 사용자 판단), 심사 특이사항 없음. 스토어 텍스트는 1.4(3)에서 한국어 문장 흐름 자연화(사용자 피드백 — 설명 ko 자연화+3언어에 1.4 기능 2줄 추가, whats-new 전면 재작성, 프로모션 1.4 전용 `promotional-text-1.4.txt`). **📌 다음 버전(1.5) 확정 계획 — 상세는 `Docs/plan-1.5.md`(2026-08-20 사용자 결정 완료)**: ①워치 행동 컴플리케이션(행동 편집에서 옵트인+기간 선택[하루/이번 주/이번 달/지난 7일/지난 30일], 탭=미니 행동 화면 착지·뒤로가기로 메인 복귀) ②건강 데이터 통합(모음 탭 타일 **무료**+건강 다짐 **프리미엄**, HealthCache 구조[값은 CloudKit 저장 금지 — 5.1.3], 수면은 사용자 지정 수면 구간→깨어난 날 귀속, 모음 탭 3섹션[즐겨찾기·나머지·건강] 순서 설정) ③도움말(HelpView) 전체 문구 한국어 기준 자연화(사용자 지시 2026-08-12 — ~해요체 유지·번역투 제거·en/ja 재검토·l10n 루틴) ④업데이트 신기능 소개 팝업(버전당 1회, 全기기 업데이트 안내 — 계획서 §11). 운동 세부 종목 다짐 포함(§3.4), 스크린샷 전면 신규(아이폰·아이패드 각 10장 — §6), 모든 사전 결정 완료(결정 이력 8건·위험 검토 R1~R16). 하위 OS 인하는 검토 후 기각(근거는 계획서 §4 — 재제안 금지). ⚠️**구현은 사용자의 "진행/시작" 지시가 있을 때만 착수** — 그 전까지 코드 무변경, 추가 요구는 계획서에 계속 반영. **버전 1.3 App Store 출시 2026-08-06** — 3일 실사용+심층 검증(2026-08-05: 자가 검증 3종 ALL PASS·벌크 1만 건·일기 내보내기 일치·위젯 스모크·만료 열람·도움말 — 회귀 0) 통과 후 제출. 심층 검증에서 기록한 사소 잔여 엣지 9건은 후속 후보로만 보류(전부 극단 한정·자가 복구형, 필기 blob 동시 편집 한계는 §6.7). 1.3 내용: 아래 소기능 이력의 일기 개선 묶음(양식 펜 색 고정 + 도형·텍스트 상자 편집 개편 + 검토 후속 수정), `Marketing/AppStore/whats-new-1.3.txt`. 잔여 엣지 9건 상세: 최소 크기 커밋 스냅백·일기 상세 이탈 시 빈 텍스트 상자 잔존·페이지 가장자리 손잡이 클리핑·인라인 편집 중 페이지 스와이프 상태 잔존·회전 상자 커서 어색함 등(1.0부터의 구조 한계인 필기 blob 동시 편집 덮어쓰기·열린 캔버스 원격 미갱신은 §6.7, 같은 페이지 동시 필기 회피 권장). 1.2 내용: 주기 몫 완료 상태 표기(§4.2)+도움말 '진행률 읽는 법' 갱신(상세는 아래 소기능 이력). **버전 1.1 출시 2026-07-30.** 1.1 내용: ①**맥 일기 개방**(§6.7 — 사이드바 노출 + '그리기' 토글로 마우스 필기, 텍스트 우선 도구줄. 아이패드 경로 불변. 맥 실기 확인 완료) ②**CSV 가져오기**(§6.8 — 프리미엄, 추가 전용·미리 보기·멱등. 검증 `-csvImportTest` 20건 ALL PASS) ③**일기 기본 표시 설정**(§6.7 — 캘린더·목표·행동 전 날짜 기본값 + 날짜별 재정의, 스키마 무변경 마커 방식) ④**'짧은 기록 무시' iCloud KVS 동기화**(§6.8 — 전 기기 공통) ⑤스크린샷 전면 개편(아이폰 10·아이패드 10·워치 합성 1 × ko/en/ja — ASC 업로드 완료) ⑥스토어 메타데이터 변경(앱 이름·부제목·키워드·프로모션 — 검색·색인 강화, `Marketing/AppStore/app-name-subtitle.txt`·`keywords.txt`·`promotional-text.txt`. 스토어 표기만 변경, 설치 이름 불변) ⑦MARKETING_VERSION 1.1. **버전 1.0 출시 2026-07-28.** 이후 작업은 사용자 실사용 중 발견한 버그 수정·사용자가 원하는 소기능 추가만 한다(선제적 기능 제안·대규모 리팩터링 금지). 출시 후 소기능 이력: **일기 도형·텍스트 상자 UX 2차 개편**(2026-08-03, 사용자 요청 — §6.7. 종류별 모양 손잡이[사각형 꼭짓점 4개·원 상하좌우 4개·선/화살표 양 끝점]와 정사각형·정원 스냅 피드백, 텍스트 상자 제자리 입력[탭→바로 키보드]·테두리 색 독립, '글 수정'→'스타일' 시트로 재편, borderColorHex 필드 추가. 1.3으로 버전 상향)·**일기 도형·텍스트 상자 편집 강화**(2026-08-03, 사용자 요청 — §6.7. "정해진 모양·크기 그대로만 나온다"는 보고: 크기 손잡이(가로세로 자유·맥 마우스 대응)·회전 제스처·'도형 수정' 시트[색·선 굵기·채우기·모서리 둥글기·회전]·텍스트 시트 확장[글자 크기·굵게·정렬·테두리], DiaryPageItem에 기본값 필드 8개 추가)·**양식 페이지 펜 색 고정**(2026-08-03, 사용자 요청 — §6.7. 다크/라이트 잉크 반전으로 맥·아이패드에서 필기가 안 보이던 실사용 보고 해소, 내보내기 라이트 트레잇 고정 포함)·**주기 몫 완료 상태 표기**(2026-08-01, 사용자 요청 — §4.2. 도움말 '진행률 읽는 법' 문구도 갱신. 같은 날 MARKETING_VERSION 1.2(빌드 1)로 상향 + `Marketing/AppStore/whats-new-1.2.txt` 작성·TestFlight 업로드, **심사 통과 → App Store 출시 완료(2026-08-02, 사용자 확인)**). 업데이트 제출: 버전 올려 빌드 업로드 → 심사 제출(IAP는 첫 심사에서 승인됐으므로 첨부 불필요). 출시 전 이력 — RC는 커밋 `f05e611`(버전 1.0 (1)), 이후 실사용 보고 기반 수정 라운드(전부 커밋·푸시·실기기 확인 완료): l10n 누락 일괄·ja 앱 이름 'Haru Danim' 통일·워치 컴플리케이션 추천 캡 제거(§11)·⑥ 위젯 종료 버튼(§10)·진행률 환산 캡+수행일 집계+수행일 아님 표기(§4.2)·파일명/CSV 헤더 현지화(§7)·워치 컴플리케이션 목표 필터(§6.4·§11, 사용자 승인 소기능)·기록 시각 입력 상시 휠 다이얼+분 절사(§6.5)·일기 달력 기분 사진 백레이어(§6.7)·다짐 없는 목표 '다짐 없음' 표기(§4.3)·워치 측정 중 행 탭 종료(§11)·도움말 예시 스크린샷 18장(§6.8)·설정 하루 시작 시간 접힘 행(§6.5)·**모음 탭 즐겨찾기 모아 보기**(§6.1 — 행동 많아질 때 혼잡도 대응, 사용자 승인 소기능. v1 별도 카드 가로 줄[대안 A~F 중 A]이 "따로 노는 느낌" 실사용 피드백으로 v2 그리드 섹션 통합+나머지 접기로 교체, 같은 날 후속 피드백으로 편집 모드 섹션 인지·섹션 간 드래그 지정/해제·"지정 순서대로 뒤에" 규칙 추가, 2026-07-22)·**en 복수형 정리**(2026-07-22 — 수량 1일 때 "1 times/quests" 류 오류를 카탈로그 plural variation으로 14건 전환[iOS 10·위젯 3·워치 1], 모음 탭 섹션 제목 en "Favorite"→"Favorites"로 워치와 통일. ko/ja 무영향). **App Store 등록 자료는 `Marketing/`에 완비**(설명·키워드·구독 메타·스크린샷 원본/합성판, README에 재생성 절차 — 앱 변경이 자료에 영향 주면 요청 없이 함께 갱신할 것. 2026-07-22 즐겨찾기 섹션(v2) 반영해 아이폰·아이패드 01-main과 help-main ko/en/ja 재촬영·합성판 재생성. **2026-07-29 스크린샷 세트 확장** — 아이폰 8장(+위젯·버블 메뉴·iCloud 동기화 합성·다크 모드)/아이패드 7장(+주간 타임테이블·위젯·동기화 합성) × ko/en/ja, 촬영·합성 절차는 Marketing/README '추가 스크린샷' 절. **1.1 제출 때 ASC 업로드 완료**). **사업자 등록·통신판매업 신고 완료(2026-07-22)** — 서류 절차 끝, ASC 등록·유료 계약 진행 가능(순서는 Marketing/README 체크리스트). 사용자는 계속 실사용 테스트 중이며 버그 보고 시: 최소 변경 + 시뮬레이터 재검증 + l10n 루틴(§2.3) + Debug/Store(워치 파일이면 워치까지) 빌드 + 커밋·푸시 | | 출시·운영 메모 (2026-07-28) | **ASC 등록·심사·출시 전부 완료** — 제출 1건에 앱 1.0+구독 그룹+상품 3종 동반(신형 ASC는 각 항목의 "심사에 추가"로 하나의 제출 초안에 담는 방식), '앱 개인정보 보호'="데이터 수집 안 함", 유료 앱 계약·대한민국 세금 양식 활성, 소규모 사업자 프로그램 가입. 개발자 본인 프리미엄은 **평생 이용권 특가 코드(무료 Offer Code) 교환**으로 스토어 버전에 적용됨(IAP용 프로모션 코드는 2026-03 폐지 — 이후 무료 지급은 특가 코드만 가능, 생성 후 교환 가능까지 최대 1시간). 상시 참고: `ITSAppUsesNonExemptEncryption=NO`, PrivacyInfo.xcprivacy 4개 번들(수집·트래킹 없음), 개인정보처리방침=`github.com/notalentprogrammer/HaruDanim` PRIVACY.md·이용약관=Apple 표준 EULA(결제 화면·앱 설명 모두 링크). **iCloud 프로덕션 동기화 확인 완료(2026-07-28)** — 아이폰·아이패드·맥 3기기 반나절 실사용에서 기존 데이터 포함 정상 왕복(개발→프로덕션 CloudKit 환경 전환에 따른 재업로드 우려 해소. 향후 동기화 문제 보고 시 이 전환 이력 참고). **정산 계좌 변경 완료** — 1.0 출시 시점에 이미 처리(2026-08-06 사용자 확인). 남은 운영 예정 작업 없음. 절차 상세 기록은 Marketing/README.md 체크리스트 | --- @@ -107,7 +107,7 @@ xcrun xcstringstool sync Widgets/Localizable.xcstrings --stringsdata "${widget_f | `TimeSession` | startAt, endAt(nil=측정 중), note | 삭제 규칙: Action cascade | | `CountEntry` | timestamp, amount, note | | | `Goal` | uuid, title, symbolName, colorHex, startDate, endDate?, statusRaw(inProgress/achieved/notAchieved), **achieveThresholdPercent(기본 100)**, sortOrder | isCollapsed·showsOnMain은 레거시 | -| `Quest` | uuid, goal, targetAction 또는 targetTag, measureRaw, periodRaw(daily/weekly/monthly/custom), scheduleModeRaw(everyDay/weekdays/monthDays/ordinalWeekday), weekdays[], monthDays[], ordinalWeek/Weekday, customStart/End, targetSeconds/targetCount, directionRaw(atLeast/atMost), **deadlineMinutes(-1=없음 — 하루 단위 전용 마감 시각, §4.2)**, sortOrder | 꼬리표 대상이면 measure는 생성 시 선택, `targetActions`는 해당 measure의 행동만 | +| `Quest` | uuid, goal, targetAction 또는 targetTag, measureRaw, periodRaw(daily/weekly/monthly/custom), scheduleModeRaw(everyDay/weekdays/monthDays/ordinalWeekday), weekdays[], monthDays[], ordinalWeek/Weekday, customStart/End, targetSeconds/targetCount, directionRaw(atLeast/atMost), **deadlineMinutes(-1=없음 — 하루 단위 전용 마감 시각, §4.2)**, **healthColorHex(""=기본 분홍 — 건강 다짐 표시 색, 1.5(7))**, sortOrder | 꼬리표 대상이면 measure는 생성 시 선택, `targetActions`는 해당 measure의 행동만 | | `DiaryEntry` | dayKey(논리적 하루 키), moodEmoji, moodImageData(externalStorage), **calendarEventIDs[]**(그날 타임테이블에 넣을 EKEvent id), **hiddenActionIDs[]**(그날 타임테이블에서 숨길 Action.uuid 문자열), **hiddenGoalIDs[]**(그날 '이 날의 목표' 카드에서 숨길 Goal.uuid 문자열) | 날짜당 1개. 날짜별 선택은 uuid 문자열로 저장(기기 간 동기화 안전) | | `DiaryTodo` | text, isDone, sortOrder | 요약 페이지 체크리스트 | | `DiaryPage` | index, lined, lineSpacing, drawingData(PKDrawing, externalStorage), **templateID**(DiaryTemplate.uuid 문자열, 빈 값=없음), **templatePageIndex**(PDF 쪽, 0부터) | 768×1024 논리 좌표. 양식만 깔린 페이지도 hasContent=true(작성함 취급·내보내기 포함) | @@ -205,7 +205,7 @@ xcrun xcstringstool sync Widgets/Localizable.xcstrings --stringsdata "${widget_f - 목표 행: 상태 뱃지(진행 중/달성/미달성/확인 필요) + 기간 진행률 바(종료일 있을 때). "확인 필요"는 탭해서 달성/미달성 직접 선택 - 목표 편집: 내용·아이콘·색·시작일(과거 가능)·종료일(선택)·**달성 판정 기준 슬라이더(10~100%, 5% 단위, 기본 100%)**·**'애플워치에서 보기' 토글(iPhone 전용 — 기본 꺼짐, 켠 목표만 워치 컴플리케이션 목록에 노출. 기기 로컬 `local.watchGoals` §5.2)** - 목표 상세: 다짐 목록(탭=수정, 스와이프 삭제, 순서 모드), 다짐 추가(무료 한도 3개), 종료일 없으면 수동 종료(기준<100%면 안내 문구에 기준 표기), 삭제 -- 다짐 편집 3단계: ①대상(행동 또는 꼬리표+측정 기준, **또는 건강[1.5 프리미엄]** — 지표 8종+운동 종목별 20종, 수면이면 수면 구간 휠. 건강 다짐은 하루 단위 전용·마감 토글 숨김, 목표량은 지표 단위 입력[보·kcal·km·L·시간], 저장 시 반대편 대상 정리[정규화]) ②주기(하루[매일/요일/날짜/n번째 요일]·주·월·특정 기간 — ordinalWeekday 구현은 weekdayOrdinal 즉 "그 달의 n번째 ◯요일"이며 UI 문구도 그렇게 표기. 하루 단위는 '마감 시각까지만 집계' 토글+시간 선택 — §4.2 마감 규칙) ③목표량(시간 휠 또는 횟수 스테퍼)+방향(이상 달성/이하 유지) +- 다짐 편집 3단계: ①대상(행동 또는 꼬리표+측정 기준, **또는 건강[1.5 프리미엄]** — 지표 8종+운동 종목별 20종, 수면이면 수면 구간 휠, **표시 색 선택[1.5(7) — 프리셋 12+피커, 기본 분홍, targetColor 단일 지점이라 전 표면 반영]**. 건강 다짐은 하루 단위 전용·마감 토글 숨김, 목표량은 지표 단위 입력[보·kcal·km·L·시간], 저장 시 반대편 대상 정리[정규화 — healthColorHex도 행동/꼬리표면 ""]) ②주기(하루[매일/요일/날짜/n번째 요일]·주·월·특정 기간 — ordinalWeekday 구현은 weekdayOrdinal 즉 "그 달의 n번째 ◯요일"이며 UI 문구도 그렇게 표기. 하루 단위는 '마감 시각까지만 집계' 토글+시간 선택 — §4.2 마감 규칙) ③목표량(시간 휠 또는 횟수 스테퍼)+방향(이상 달성/이하 유지) - **연속 달성**(`QuestProgress.streak` → `QuestStreakInfo`): 하루 단위=적용일만 연속 계산("연속 N일" — 매주 수요일 다짐을 4주 연속이면 연속 4일), 주간/월간="연속 N주/N달", 특정 기간=nil. 진행 중인 오늘/이번 주기는 atLeast면 미달이어도 끊기지 않고(건너뜀) 채웠으면 포함, atMost는 넘는 순간 끊김. **하한 = 목표 시작일** — 행동이 아니라 "목표 안 다짐"의 연속이므로 목표 시작 전 날짜/주기는 세지 않음(주·월은 시작일이 걸친 부분 주기까지 포함). 특히 atMost는 기록 없는 날이 전부 달성이라 이 하한이 없으면 과거 전체가 연속으로 잡힘. 소급 상한 400일(성능). 기록을 하루 키로 1회 버킷팅해 O(기록+일수). **미래 시각 기록(수동 입력)은 진행률·게이지에는 즉시 반영되지만 연속 계산은 now까지만 집계** — 그 시각이 지나야 연속에 반영된다(선기록으로 연속이 미리 쌓이지 않게 하는 의도된 동작, 고치지 말 것). 표기: 목표 탭 다짐 행 + 위젯 ②다짐 줄·③링 셀·④현황 그리드 (불꽃+노랑, 0이면 숨김). '스트릭'이라는 단어는 한국어 UI에 쓰지 않는다 - 목록 진입 시 `evaluateIfEnded` 일괄 실행 diff --git a/myApp/HaruDanim/Docs/plan-1.5.md b/myApp/HaruDanim/Docs/plan-1.5.md index e5448f3..0c17e2b 100644 --- a/myApp/HaruDanim/Docs/plan-1.5.md +++ b/myApp/HaruDanim/Docs/plan-1.5.md @@ -182,3 +182,10 @@ - **실기기 실측(사용자)**: 버블 메뉴 펼침 상태에서 각 원이 이웃 버블 방향으로 늘어나 찌그러짐("서로 인력을 가진 느낌"). 원인: 일기 버블 추가로 8개가 되며 이웃 가장자리 간격이 ~9.6pt로 줄었는데, 유리 합체 판정 거리 `glassBlendSpacing`이 7개 시절 기준 18pt 그대로라 **정지 상태에서도 이웃끼리 합체 판정에 걸림**(1.4까지 7개는 간격 ~20.7pt로 판정 밖 — "1.3까지는 문제없었다"는 증언과 일치). - 수정: 18→6 (펼침 상태 정원 분리 확인 — 시각 QA. FAB에서 피어나는 모핑은 겹침 구간에서 일어나므로 유지). 마케팅 06-bubble ×3 재촬영(구 샷에 왜곡 찍혀 있었음), 코드 주석에 "탭 추가 시 간격 하한 재확인" 경고. + +### §12 후속 3 — 건강 다짐 표시 색 (2026-08-23, 빌드 7) + +- 사용자 요구: 건강 다짐이 표시 표면(목표 탭·모음 카드·위젯·다짐 현황)에서 고정 분홍 — 만들 때 색을 고를 수 있게(타임테이블 블록 색과 별개). +- 구현: **Quest 신규 필드 `healthColorHex`(기본 "")** + `targetColor` 건강 분기(빈 값=시스템 분홍 → 다크 적응 유지, 값 있으면 hex 고정 — 꼬리표 색과 같은 문법). 편집기 건강 섹션에 '다짐 색'(프리셋 12=AppTheme.tagPresets+컬러 피커), 저장 시 기본 분홍 그대로면 ""로 정규화, 행동·꼬리표 전환 시 "" 정리. targetColor가 단일 공급 지점이라 전 표면 자동 반영. +- ⚠️ **CloudKit 스키마 추가** — DiaryPageItem 전례에 따라 **배포(개발 내보내기→콘솔 Deploy)가 빌드 7 설치보다 선행**. 절차: 아리나 시뮬 내보내기 → 사용자 콘솔 Deploy → 그다음 업로드·설치. 구버전 기기는 분홍 폴백(표시 차이만 — 안전). +- 시드: -seedHealthQuest 걸음 다짐에 #3E7CB1 시드(신규·멱등 재실행 모두 — 렌더 검증+스키마 내보내기 트리거 겸용). 도움말·whats-new 3언어 갱신, l10n 0/0. diff --git a/myApp/HaruDanim/Haru_Danim.xcodeproj/project.pbxproj b/myApp/HaruDanim/Haru_Danim.xcodeproj/project.pbxproj index 88b617c..c253fc5 100644 --- a/myApp/HaruDanim/Haru_Danim.xcodeproj/project.pbxproj +++ b/myApp/HaruDanim/Haru_Danim.xcodeproj/project.pbxproj @@ -601,7 +601,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = IOS/Haru_Danim.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 6; + CURRENT_PROJECT_VERSION = 7; DEVELOPMENT_TEAM = 5GNS4Z2SYT; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; @@ -643,7 +643,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = IOS/Haru_Danim.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 6; + CURRENT_PROJECT_VERSION = 7; DEVELOPMENT_TEAM = 5GNS4Z2SYT; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; @@ -686,7 +686,7 @@ CODE_SIGN_ENTITLEMENTS = "Haru_DanimWatch Watch App/Haru_DanimWatch Watch App.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 6; + CURRENT_PROJECT_VERSION = 7; DEVELOPMENT_TEAM = 5GNS4Z2SYT; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; @@ -722,7 +722,7 @@ CODE_SIGN_ENTITLEMENTS = "Haru_DanimWatch Watch App/Haru_DanimWatch Watch App.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 6; + CURRENT_PROJECT_VERSION = 7; DEVELOPMENT_TEAM = 5GNS4Z2SYT; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; @@ -758,7 +758,7 @@ CODE_SIGN_ENTITLEMENTS = Haru_DanimWatchWidgets/Haru_DanimWatchWidgetsExtension.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 6; + CURRENT_PROJECT_VERSION = 7; DEVELOPMENT_TEAM = 5GNS4Z2SYT; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = Haru_DanimWatchWidgets/Info.plist; @@ -794,7 +794,7 @@ CODE_SIGN_ENTITLEMENTS = Haru_DanimWatchWidgets/Haru_DanimWatchWidgetsExtension.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 6; + CURRENT_PROJECT_VERSION = 7; DEVELOPMENT_TEAM = 5GNS4Z2SYT; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = Haru_DanimWatchWidgets/Info.plist; @@ -827,7 +827,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = Widgets/Haru_DanimWidgets.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 6; + CURRENT_PROJECT_VERSION = 7; DEVELOPMENT_TEAM = 5GNS4Z2SYT; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = Widgets/Info.plist; @@ -853,7 +853,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = Widgets/Haru_DanimWidgets.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 6; + CURRENT_PROJECT_VERSION = 7; DEVELOPMENT_TEAM = 5GNS4Z2SYT; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = Widgets/Info.plist; diff --git a/myApp/HaruDanim/IOS/Core/DebugSeed.swift b/myApp/HaruDanim/IOS/Core/DebugSeed.swift index 4fdcfe0..c02cb74 100644 --- a/myApp/HaruDanim/IOS/Core/DebugSeed.swift +++ b/myApp/HaruDanim/IOS/Core/DebugSeed.swift @@ -674,7 +674,16 @@ enum DebugSeed { // 마케팅 촬영에 쓰이므로 실행 로케일을 따른다 (-seedDemo 시드 이름과 같은 규칙) let title = String(localized: "건강 습관 만들기") let existing = (try? context.fetch(FetchDescriptor())) ?? [] - guard !existing.contains(where: { $0.title == title }) else { return } + if let seeded = existing.first(where: { $0.title == title }) { + // 재실행(멱등) 경로: 걸음 다짐에 지정 색이 없으면 입혀 준다 — 표시 색(1.5(7))의 + // 렌더 검증 + 새 healthColorHex 필드의 CloudKit 내보내기(스키마 생성) 트리거 겸용 + if let steps = seeded.quests.first(where: { $0.healthMetricRaw == HealthMetric.steps.rawValue }), + steps.healthColorHex.isEmpty { + steps.healthColorHex = "#3E7CB1" + DataChange.commit(context: context) + } + return + } let goal = Goal(title: title, symbolName: "heart.fill", colorHex: "#E0558C", startDate: Calendar.current.date(byAdding: .day, value: -7, to: .now) ?? .now, endDate: nil) @@ -689,6 +698,8 @@ enum DebugSeed { context.insert(quest) } addQuest(HealthMetric.steps.rawValue, count: 8000, isDuration: false) + // 걸음 다짐에 지정 색 시드 — 나머지는 기본 분홍 유지 (색 지정/기본의 대비 렌더 검증, 1.5(7)) + goal.quests.first { $0.healthMetricRaw == HealthMetric.steps.rawValue }?.healthColorHex = "#3E7CB1" addQuest(HealthMetric.sleep.rawValue, seconds: 8 * 3600, isDuration: true) addQuest("workout.running", seconds: 30 * 60, isDuration: true) addQuest(HealthMetric.water.rawValue, count: 2000, isDuration: false) diff --git a/myApp/HaruDanim/IOS/Localizable.xcstrings b/myApp/HaruDanim/IOS/Localizable.xcstrings index 9b1c026..c8fb55c 100644 --- a/myApp/HaruDanim/IOS/Localizable.xcstrings +++ b/myApp/HaruDanim/IOS/Localizable.xcstrings @@ -4835,6 +4835,22 @@ } } }, + "다짐 색": { + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": "Quest color" + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": "クエストの色" + } + } + } + }, "다짐 수정": { "localizations": { "en": { @@ -5059,18 +5075,18 @@ } } }, - "다짐을 만들 때 대상에서 '건강'을 고르면 '매일 8,000보', '수면 8시간 이상', '달리기 30분'처럼 건강 데이터를 목표로 삼을 수 있어요. 걸음 수·운동 시간·수면·활동 에너지·이동 거리·일어서기·마음챙김·물 섭취를 고를 수 있고, 운동은 달리기·수영·근력 운동 같은 종목별로도 만들 수 있어요 — 종목별 시간은 건강 앱에 기록된 운동 기준이라 활동 링의 '운동 시간'과는 값이 다를 수 있어요. 건강 다짐은 하루 단위로만 반복돼요(요일 지정은 돼요).\n수면 다짐은 '수면 구간'(기본 저녁 9시~다음 날 아침 9시)을 정해 두면 그 안에서 잔 시간을 통째로 그날 것으로 세요 — 자정을 넘겨 자도 하루가 쪼개지지 않아요. 진행률·연속 달성·목표 판정은 다른 다짐과 똑같은 규칙으로 계산돼요. 건강 데이터가 없는 기기(맥 등)에서는 건강 다짐이 '데이터 없음'으로 보이고 목표 진행률에서 빠져요 — 아이폰에서 보면 정상으로 보여요.": { + "다짐을 만들 때 대상에서 '건강'을 고르면 '매일 8,000보', '수면 8시간 이상', '달리기 30분'처럼 건강 데이터를 목표로 삼을 수 있어요. 걸음 수·운동 시간·수면·활동 에너지·이동 거리·일어서기·마음챙김·물 섭취를 고를 수 있고, 운동은 달리기·수영·근력 운동 같은 종목별로도 만들 수 있어요 — 종목별 시간은 건강 앱에 기록된 운동 기준이라 활동 링의 '운동 시간'과는 값이 다를 수 있어요. 건강 다짐은 하루 단위로만 반복돼요(요일 지정은 돼요). 목표 탭·위젯에서 이 다짐이 보일 색도 만들 때 직접 고를 수 있어요 — 기본은 분홍이고, 타임테이블의 수면·운동 블록 색과는 별개예요.\n수면 다짐은 '수면 구간'(기본 저녁 9시~다음 날 아침 9시)을 정해 두면 그 안에서 잔 시간을 통째로 그날 것으로 세요 — 자정을 넘겨 자도 하루가 쪼개지지 않아요. 진행률·연속 달성·목표 판정은 다른 다짐과 똑같은 규칙으로 계산돼요. 건강 데이터가 없는 기기(맥 등)에서는 건강 다짐이 '데이터 없음'으로 보이고 목표 진행률에서 빠져요 — 아이폰에서 보면 정상으로 보여요.": { "localizations": { "en": { "stringUnit": { "state": "translated", - "value": "Pick Health as the target when creating a quest, and health data becomes your goal — \"8,000 steps a day,\" \"at least 8 hours of sleep,\" \"30 minutes of running.\" You can choose steps, exercise time, sleep, active energy, distance, stand hours, mindfulness or water intake, and workouts can be tracked by type, like running, swimming or strength training — type-based time comes from workouts logged in the Health app, so it can differ from the activity ring's Exercise Time. Health quests repeat daily only (weekday schedules are fine).\nFor a sleep quest, set a sleep window (9 PM to 9 AM the next morning by default) and everything you sleep within it counts as that day's sleep — crossing midnight doesn't split your night. Progress, streaks and goal judgment follow exactly the same rules as other quests. On devices without health data (like the Mac), health quests show \"No data\" and drop out of goal progress — they look normal again on your iPhone." + "value": "Pick 'Health' as a quest's target to set goals from health data — '8,000 steps a day', 'at least 8 hours of sleep', '30 minutes of running'. You can choose steps, exercise time, sleep, active energy, distance, stand hours, mindful minutes or water intake, and workouts can be set by type, like running, swimming or strength training — type-based time comes from workouts logged in the Health app, so it can differ from the activity ring's 'exercise time'. Health quests repeat daily only (weekday schedules are fine). You can also pick the color the quest shows in the Goals tab and widgets — pink by default, and separate from the timetable's sleep and workout block colors.\nFor a sleep quest, set a sleep window (9 PM to 9 AM the next day by default) and everything you sleep within it counts as that day's — sleeping past midnight won't split your night. Progress, streaks and goal judgment follow the same rules as any other quest. On devices without health data (like the Mac), health quests show as 'no data' and drop out of goal progress — they look normal on your iPhone." } }, "ja": { "stringUnit": { "state": "translated", - "value": "クエストを作るとき対象で「ヘルス」を選ぶと、「毎日8,000歩」「睡眠8時間以上」「ランニング30分」のように、ヘルスデータを目標にできます。歩数・運動時間・睡眠・アクティブエネルギー・移動距離・スタンド時間・マインドフルネス・水分摂取から選べて、運動はランニング・水泳・筋力トレーニングのような種目別でも作れます — 種目別の時間はヘルスケアアプリに記録された運動が基準なので、アクティビティリングの「運動時間」とは値が異なることがあります。ヘルスクエストは1日単位でのみ繰り返されます(曜日指定はできます)。\n睡眠クエストは「睡眠時間帯」(デフォルトは夜9時〜翌朝9時)を決めておくと、その中で眠った時間をまるごとその日の分として数えます — 日付をまたいで眠っても1日が分割されません。進捗・連続達成・目標判定はほかのクエストとまったく同じルールで計算されます。ヘルスデータのない端末(Macなど)ではヘルスクエストが「データなし」と表示され目標の進捗から外れます — iPhoneで見れば通常どおり表示されます。" + "value": "クエストの対象で「ヘルス」を選ぶと、「毎日8,000歩」「睡眠8時間以上」「ランニング30分」のようにヘルスデータを目標にできます。歩数・運動時間・睡眠・アクティブエネルギー・移動距離・スタンド時間・マインドフル分・水分摂取から選べ、運動はランニング・水泳・筋力トレーニングなど種目別でも作れます — 種目別の時間はヘルスケアAppに記録されたワークアウト基準なので、アクティビティリングの「エクササイズ時間」とは値が異なることがあります。ヘルスクエストは1日単位のみで繰り返します(曜日指定はできます)。目標タブやウィジェットでクエストが表示される色も作成時に選べます — 基本はピンクで、タイムテーブルの睡眠・運動ブロックの色とは別です。\n睡眠クエストは「睡眠時間帯」(初期設定は夜9時〜翌朝9時)を決めておくと、その中で眠った時間をまるごとその日のものとして数えます — 日付をまたいで眠っても1日が分割されません。進捗・継続・目標の判定は他のクエストと同じルールで計算されます。ヘルスデータのない端末(Macなど)ではヘルスクエストが「データなし」と表示され、目標の進捗から外れます — iPhoneで見れば正常に表示されます。" } } } diff --git a/myApp/HaruDanim/IOS/Views/HelpView.swift b/myApp/HaruDanim/IOS/Views/HelpView.swift index 222429c..f86f428 100644 --- a/myApp/HaruDanim/IOS/Views/HelpView.swift +++ b/myApp/HaruDanim/IOS/Views/HelpView.swift @@ -317,7 +317,7 @@ struct HelpView: View { HelpTopic( symbol: "figure.run", title: "건강 데이터로 다짐 만들기 (프리미엄)", - body: "다짐을 만들 때 대상에서 '건강'을 고르면 '매일 8,000보', '수면 8시간 이상', '달리기 30분'처럼 건강 데이터를 목표로 삼을 수 있어요. 걸음 수·운동 시간·수면·활동 에너지·이동 거리·일어서기·마음챙김·물 섭취를 고를 수 있고, 운동은 달리기·수영·근력 운동 같은 종목별로도 만들 수 있어요 — 종목별 시간은 건강 앱에 기록된 운동 기준이라 활동 링의 '운동 시간'과는 값이 다를 수 있어요. 건강 다짐은 하루 단위로만 반복돼요(요일 지정은 돼요).\n수면 다짐은 '수면 구간'(기본 저녁 9시~다음 날 아침 9시)을 정해 두면 그 안에서 잔 시간을 통째로 그날 것으로 세요 — 자정을 넘겨 자도 하루가 쪼개지지 않아요. 진행률·연속 달성·목표 판정은 다른 다짐과 똑같은 규칙으로 계산돼요. 건강 데이터가 없는 기기(맥 등)에서는 건강 다짐이 '데이터 없음'으로 보이고 목표 진행률에서 빠져요 — 아이폰에서 보면 정상으로 보여요." + body: "다짐을 만들 때 대상에서 '건강'을 고르면 '매일 8,000보', '수면 8시간 이상', '달리기 30분'처럼 건강 데이터를 목표로 삼을 수 있어요. 걸음 수·운동 시간·수면·활동 에너지·이동 거리·일어서기·마음챙김·물 섭취를 고를 수 있고, 운동은 달리기·수영·근력 운동 같은 종목별로도 만들 수 있어요 — 종목별 시간은 건강 앱에 기록된 운동 기준이라 활동 링의 '운동 시간'과는 값이 다를 수 있어요. 건강 다짐은 하루 단위로만 반복돼요(요일 지정은 돼요). 목표 탭·위젯에서 이 다짐이 보일 색도 만들 때 직접 고를 수 있어요 — 기본은 분홍이고, 타임테이블의 수면·운동 블록 색과는 별개예요.\n수면 다짐은 '수면 구간'(기본 저녁 9시~다음 날 아침 9시)을 정해 두면 그 안에서 잔 시간을 통째로 그날 것으로 세요 — 자정을 넘겨 자도 하루가 쪼개지지 않아요. 진행률·연속 달성·목표 판정은 다른 다짐과 똑같은 규칙으로 계산돼요. 건강 데이터가 없는 기기(맥 등)에서는 건강 다짐이 '데이터 없음'으로 보이고 목표 진행률에서 빠져요 — 아이폰에서 보면 정상으로 보여요." ), ]) } diff --git a/myApp/HaruDanim/IOS/Views/QuestEditorView.swift b/myApp/HaruDanim/IOS/Views/QuestEditorView.swift index 2cce2a0..4c4cc17 100644 --- a/myApp/HaruDanim/IOS/Views/QuestEditorView.swift +++ b/myApp/HaruDanim/IOS/Views/QuestEditorView.swift @@ -63,6 +63,9 @@ struct QuestEditorView: View { to: Calendar.current.startOfDay(for: .now) ) ?? .now }() + /// 건강 다짐 표시 색 (1.5(7)) — 기본 분홍(.pink). 저장 시 기본색 그대로면 빈 값으로 + /// 정규화해 시스템 분홍의 라이트/다크 적응을 유지한다 (save() 참고) + @State private var healthColor: Color = .pink /// 수량형 건강 목표 입력값 (지표별 기본 단위 — 걸음 보 / 에너지 kcal / 스탠드 시간) @State private var healthIntTarget = 8000 /// 거리 목표 (km — 저장은 m) @@ -182,6 +185,34 @@ struct QuestEditorView: View { components: .hourAndMinute ) } + // 표시 색 (1.5(7)) — 목표 탭·모음 카드·일기·위젯에서 이 다짐이 보일 색. + // 행동·꼬리표 다짐은 대상의 색을 따르므로 건강 다짐에만 있는 선택이고, + // 타임테이블의 수면·운동 블록 색(설정 → 건강 데이터)과는 별개다 + ColorPicker(selection: $healthColor, supportsOpacity: false) { + Text("다짐 색") + } + LazyVGrid(columns: [GridItem(.adaptive(minimum: 40), spacing: 10)], spacing: 10) { + ForEach(Array(AppTheme.tagPresets.enumerated()), id: \.offset) { index, hex in + Button { + healthColor = Color(hex: hex) + } label: { + Circle() + .fill(Color(hex: hex)) + .frame(width: 36, height: 36) + .overlay { + if healthColor.hexString == hex { + Image(systemName: "checkmark") + .font(.system(size: 14, weight: .bold)) + .foregroundStyle(.white) + } + } + } + .buttonStyle(.plain) + .accessibilityLabel(String(localized: "미리 설정된 색 \(index + 1)")) + .accessibilityAddTraits(healthColor.hexString == hex ? .isSelected : []) + } + } + .padding(.vertical, 4) } case .action: if allActions.isEmpty { @@ -503,6 +534,9 @@ struct QuestEditorView: View { let dayStart = cal.startOfDay(for: .now) sleepStart = cal.date(byAdding: .minute, value: quest.sleepWindowStartMinutes, to: dayStart) ?? sleepStart sleepEnd = cal.date(byAdding: .minute, value: quest.sleepWindowEndMinutes, to: dayStart) ?? sleepEnd + if !quest.healthColorHex.isEmpty { + healthColor = Color(hex: quest.healthColorHex) + } } measure = quest.measure period = quest.period @@ -533,11 +567,13 @@ struct QuestEditorView: View { target.targetTag = nil target.measure = selectedAction?.trackingType ?? .time target.healthMetricRaw = "" // 정규화 — 반대편 대상 정리 (plan §3.4) + target.healthColorHex = "" case .tag: target.targetTag = selectedTag target.targetAction = nil target.measure = measure target.healthMetricRaw = "" + target.healthColorHex = "" case .health: target.targetAction = nil target.targetTag = nil @@ -559,6 +595,10 @@ struct QuestEditorView: View { let endComps = cal.dateComponents([.hour, .minute], from: sleepEnd) target.sleepWindowStartMinutes = (startComps.hour ?? 21) * 60 + (startComps.minute ?? 0) target.sleepWindowEndMinutes = (endComps.hour ?? 9) * 60 + (endComps.minute ?? 0) + // 표시 색 — 기본 분홍 그대로면 빈 값(시스템 분홍의 다크 모드 적응 유지), + // 사용자가 바꿨을 때만 hex 고정 저장 (1.5(7)) + target.healthColorHex = + healthColor.hexString == Color.pink.hexString ? "" : healthColor.hexString period = .daily // 건강 다짐은 하루 단위 전용 (방어 — UI에서도 강제됨) } target.period = period diff --git a/myApp/HaruDanim/Marketing/AppStore/whats-new-1.5.txt b/myApp/HaruDanim/Marketing/AppStore/whats-new-1.5.txt index 603d05a..86bfaca 100644 --- a/myApp/HaruDanim/Marketing/AppStore/whats-new-1.5.txt +++ b/myApp/HaruDanim/Marketing/AppStore/whats-new-1.5.txt @@ -5,7 +5,7 @@ ● 애플 건강과 연결 • 모음 탭에서 걸음·운동·수면 같은 오늘의 건강 데이터를 타일로 볼 수 있어요 — 값은 기기 밖으로 나가지 않아요 -• 건강 데이터로 다짐을 만들 수 있어요(프리미엄) — '매일 8,000보', '수면 8시간', '달리기 30분'처럼요. 운동은 종목별로도 돼요 +• 건강 데이터로 다짐을 만들 수 있어요(프리미엄) — '매일 8,000보', '수면 8시간', '달리기 30분'처럼요. 운동은 종목별로도 되고, 다짐이 보일 색도 고를 수 있어요 • 수면은 '수면 구간'을 정해 두면 자정을 넘겨 자도 하루가 쪼개지지 않아요. 낮에 자는 날이 있다면 '수면 표시 구간'을 요일별로 맞출 수도 있어요 ● 일기가 더 넓어졌어요 (프리미엄) @@ -26,7 +26,7 @@ This update brings Haru Danim closer to Apple Health — and your Apple Watch. A ● Apple Health, connected • See today's health data — steps, exercise, sleep — as tiles on the Home tab. Values never leave your device -• Build quests from health data (Premium): "8,000 steps a day," "8 hours of sleep," "30 minutes of running" — workouts by type, too +• Build quests from health data (Premium): "8,000 steps a day," "8 hours of sleep," "30 minutes of running" — workouts by type, and pick the quest's color too • Set a sleep window and sleeping past midnight won't split your night. If some days you sleep in the daytime, tune the display window per weekday ● A bigger Diary (Premium) @@ -47,7 +47,7 @@ This update brings Haru Danim closer to Apple Health — and your Apple Watch. A ● Appleヘルスケアと連携 • ホームタブで歩数・運動・睡眠など今日のヘルスデータをタイルで見られます — 値が端末の外に出ることはありません -• ヘルスデータでクエストを作れます(プレミアム)—「毎日8,000歩」「睡眠8時間」「ランニング30分」など。運動は種目別でもOK +• ヘルスデータでクエストを作れます(プレミアム)—「毎日8,000歩」「睡眠8時間」「ランニング30分」など。運動は種目別でもOK、クエストの色も選べます • 「睡眠時間帯」を決めておけば、日付をまたいで眠っても1日が分割されません。昼間に眠る日があるなら、表示の時間帯を曜日ごとに調整できます ● 日記がもっと広く(プレミアム) diff --git a/myApp/HaruDanim/Shared/Models.swift b/myApp/HaruDanim/Shared/Models.swift index c43f33c..88dab5f 100644 --- a/myApp/HaruDanim/Shared/Models.swift +++ b/myApp/HaruDanim/Shared/Models.swift @@ -396,6 +396,10 @@ final class Quest { /// 구간 '끝'이 속한 논리적 하루에 수면 전체가 귀속된다 (깨어난 날 규칙 — plan §3.4) var sleepWindowStartMinutes: Int = 1260 var sleepWindowEndMinutes: Int = 540 + /// 건강 다짐의 표시 색 "#RRGGBB" (1.5(7)) — 빈 값 = 기본(분홍). 행동·꼬리표 다짐은 + /// 대상의 색을 쓰므로 항상 빈 값(저장 시 정규화). ⚠️ 새 필드 = CloudKit 스키마 추가 — + /// 배포 절차(개발 내보내기→콘솔 Deploy)가 새 빌드 설치보다 먼저여야 함(§3, plan §12) + var healthColorHex: String = "" /// 목표 안에서의 표시 순서 var sortOrder: Int = 0 @@ -452,7 +456,11 @@ extension Quest { var targetColor: Color { if let targetAction { return targetAction.color } if let targetTag { return targetTag.color } - if healthTarget != nil { return .pink } + // 건강 다짐: 사용자 지정 색(1.5(7)), 없으면 기본 분홍 — 이 접근자가 단일 공급 + // 지점이라 목표 탭·모음 카드·일기·위젯·워치 스냅숏이 전부 함께 따라온다 + if healthTarget != nil { + return healthColorHex.isEmpty ? .pink : Color(hex: healthColorHex) + } return AppTheme.green }