mycode/myApp/HaruDanim/Docs/plan-1.5.md
songyc macbook ac68fddb14 fix(1.5-p8): 버블 메뉴 원 찌그러짐 — 8개 배치에서 유리 합체 판정 거리 초과(glassBlendSpacing 18→6), 빌드 6
- 원인: 일기 버블 추가로 이웃 간격 ~9.6pt < 판정 18pt → 정지 상태에서도 이웃끼리 액체 합체가 걸려 원이 늘어남(7개 시절 ~20.7pt는 판정 밖 — '1.3까진 정상' 증언과 일치)
- 펼침 상태 정원 분리 시각 QA 확인, FAB 피어남 모핑은 겹침 구간이라 유지
- 마케팅 06-bubble ko/en/ja 재촬영(구 샷에 왜곡 포함)·합성 재생성, 코드 주석에 탭 추가 시 재확인 경고

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WtZwRRjbtM9pZJDM4FkTq6
2026-08-23 07:08:39 +09:00

185 lines
37 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 하루 다님 1.5 확정 계획
> 상태: **구현 완료(2026-08-22)** — 전 기능·검증·스토어 자료 완료, 커밋·푸시됨. 남은 것은 사용자 절차(TestFlight 소킹·CloudKit 스키마 콘솔 확인·ASC 업로드 — §6)와 비차단 확인(운동 종목 목록).
> 작성 2026-08-20. 근거: 2026-08-20 세션에서 사용자 위시리스트 → 분석 보고 2회 → 사용자 결정 4건(아래 결정 이력)으로 확정.
> 구현 시 이 문서를 명세로 삼고, 완료된 항목은 CLAUDE.md 현행 명세에 흡수한 뒤 이 문서에 완료 표기할 것.
## 0. 범위 요약
| # | 기능 | 과금 | 규모 |
|---|---|---|---|
| 1 | 워치 행동 컴플리케이션 (기간 선택·미니 행동 화면 착지) | 프리미엄(워치 자체가 프리미엄) | 중간 |
| 2 | 건강 데이터 통합 — 모음 탭 타일(표시) + 건강 다짐 | 타일 **무료** + 건강 다짐 **프리미엄** | 큼 |
| 3 | 도움말(HelpView) 전체 문구 한국어 자연화 (2026-08-12 예약분) | — | 중간 |
| 4 | 업데이트 신기능 소개 팝업(버전당 1회, 全기기 업데이트 안내 포함) | 무료 | 소 |
**제외 확정**: 하위 OS 인하(§4 기각 기록), 워치 스마트 스택 인터랙티브 위젯, 모음 탭 스와이프 페이지 배치.
## 1. 결정 이력 (2026-08-20 사용자 답변)
1. 컴플리케이션 탭 착지 = **미니 행동 화면 신설** (기존 목록 스크롤 기각)
2. 건강 타일 배치 = **타일 줄 + 접기** (스와이프 페이지 기각 — 목표 카드 가로 페이징·배치 편집 드래그와 제스처 충돌, 발견성 낮음)
3. 건강 다짐 v1 지표 = **"지표 더 추가"** 선택 — 구체 세트는 미지정. 아래 §3.4의 8종 제안을 착수 시 사용자 확인으로 확정할 것 (수면 주간 합산은 선택지에서 미채택 → v1 제외)
4. 과금 = **타일 무료 + 건강 다짐 프리미엄**
5. (앞선 보고에서) 하위 OS 철회, 스마트 스택 불요, 표시 기간 옵션은 달력 주기+롤링 둘 다, 건강은 표시·다짐을 **한 버전에 통합**(감수사항 3건 §3.1 전제)
6. 후속 추가(2026-08-20): ①컴플리케이션 착지 미니 화면은 **뒤로가기로 워치 앱 메인 복귀**(push 구조 필수) ②모음 탭 건강 섹션은 **설정에서 표시 on/off + 즐겨찾기·나머지 행동·건강 3섹션 순서 지정**(목표 카드 선택 설정 아래 배치). 이후 추가 요구는 사용자가 그때그때 전달 예정 — 이 문서에 계속 반영할 것
7. 후속 승인·추가(2026-08-22): **§8 세 건 전부 승인**(③ 표시 전용 상속 / 데이터 없는 기기 모수 제외+판정 보류 / 건강 다짐 v1 마감 시각 미지원). 추가 요구: **건강 데이터의 특성(하루 경계·수면 귀속 규칙·값 신선도·기기별 편차)을 도움말에 상세히 설명**하고, **건강 데이터를 보는 화면(모음 탭 타일 영역)에도 해당 안내 가이드 문구를 표기**할 것. 1.5 도움말 작업은 자연화(예약분)+신규 주제+이 안내를 한 묶음으로 진행. **안정성 최우선 지시**: 1.4 기능은 오류 없이 그대로 유지된 채 1.5가 얹혀야 함 — §10 위험 검토가 그 근거 문서
8. 2차 답변(2026-08-22): ①지표 8종 확정 + **운동 세부 종목 다짐 추가**(사용자 핵심 니즈 — §3.4) ②프리미엄 만료 처리=기존 원칙(만든 건 유지 — "돈 내고 쓴 기간에 한 건 인정") ③스크린샷=기존 전부 폐기, 아이폰·아이패드 각 10장 신규(스타일 동일·구성 일신 — §6) ④whats-new에 全기기 업데이트 완화 문구 ⑤**업데이트 신기능 소개 팝업 신설**(§11) ⑥CloudKit 스키마 배포=사용자 기억 없음 → 아리나가 구현 중 확인·준비하고 콘솔 작업 필요 시 시점·절차를 사용자에게 안내(§3.5). 이 반영은 "기록 용도 문서 수정만 허용(코드·프로젝트 파일 금지)" 상태에서 수행
## 2. 기능 1 — 워치 행동 컴플리케이션 ✅구현 완료(2026-08-22 — 빌드 4종·자가 검증 106건×2심·시각 QA[워치 26.2 실데이터/11.5 빈 상태·미니 화면 뒤로가기·편집기 섹션] 통과)
### 스펙
- **옵트인+기간 설정(아이폰)**: 행동 편집 화면에 '애플워치 컴플리케이션' 토글, 켜면 표시 기간 선택: **하루 / 이번 주 / 이번 달 / 지난 7일 / 지난 30일**. 저장은 기기 로컬 `LocalPrefs` 신설 키(uuid→기간 맵, `local.watchGoals`와 동일 계열 — 워치는 이 아이폰과 페어링이므로 기기 로컬이 자연스러움).
- **표시**: 원형=행동 아이콘 + 큰 값(횟수형 "N회", 시간형 압축 표기 "47분"·"1:12"류). corner/inline/rectangular 대응(rectangular는 아이콘+이름+값). 측정 중이면 노란 시그널 + 실시간 타이머 — '현재 현황' 컴플리케이션의 tickingBase 방식(스냅숏 시점 누적초)과 유령 타이머 2시간 안전장치(`runningTrustInterval`) 재사용. 주·월 기간에도 tickingBase 산식 동일 적용 가능.
- **탭 동작**: `widgetURL` 딥링크 → 워치 앱 **미니 행동 화면**(신설): 아이콘+이름+설정 기간 누적값+큼직한 실행/종료(횟수형은 +1) 버튼. 실행은 기존 run 명령 재사용. 자동 실행 금지(손목 오탭 방지 — 명시적 버튼 탭 문법 유지). **뒤로가기 필수(사용자 요구 2026-08-20)**: 미니 화면은 워치 앱 첫 화면(메인 목록) 위에 push로 착지 — 뒤로가기 한 번에 기존 메인으로 복귀, 앱을 종료·재실행할 필요가 없어야 함(딥링크가 고립 화면이 되지 않게 내비게이션 스택 구성).
- **recommendations**: 옵트인 행동 전부 나열(상한 금지 — §11 규칙), 기간은 아이폰 설정값이 반영된 단일 항목. 스냅숏 적용 시 기존 `invalidateConfigurationRecommendations()` 경로로 자동 갱신.
- **갱신 특성(의도된 한계)**: 기존 컴플리케이션과 동일 — 스냅숏 push + 15분 .after 타임라인. 아이폰 +1 직후 페이스 반영은 수 분 지연 가능, 측정 시작/종료는 `transferCurrentComplicationUserInfo` 즉시 푸시 경로 기존과 동일.
### 데이터 배선
- `WatchActionInfo`**optional** 필드 추가: 설정 기간 식별 + 그 기간 누적값(예: `complicationPeriodRaw`, `periodValue`). 구버전 캐시 호환은 기존 optional 패턴(isFavorite·runningActionID 선례). `makeSnapshot`**옵트인된 행동만** 기간값을 계산(페이로드 절약).
- 롤링 창은 1.4의 `DayMath.rollingRange` 재사용. ⚠️ **StatSpan enum 케이스 추가 금지**(§6.6 경고 준수) — 기간+롤링 플래그로 처리. 수치는 통계 탭과 동일해야 함(Aggregator 경유).
### 영향 파일(예상)
`WatchShared/WatchPayload.swift`(필드) · `IOS/Core/WatchSyncManager.swift`(makeSnapshot) · `Haru_DanimWatchWidgets/`(신규 컴플리케이션 1종) · 워치 앱(미니 행동 화면 + widgetURL 라우팅) · `IOS/Views/ActionViews.swift`(편집 토글+기간 선택) · `Shared/LocalPrefs.swift`(신설 키) · l10n: IOS+워치 카탈로그.
### 검증
`-complicationPreview`에 신규 종 포함, 워치 심 11.5·26.2 렌더, 기간별 수치를 통계 탭과 대조, 구버전 스냅숏 캐시 폴백(기간 필드 없음 → 하루 폴백), 딥링크 착지·실행·오탭 시나리오, ko/en/ja.
## 3. 기능 2 — 건강 데이터 통합 (HealthKit)
### 3.1 전제 (사용자 감수 확정)
1. **위젯의 건강 수치는 실시간이 아님** — 마지막 앱 갱신+백그라운드 딜리버리(걸음 등 누적형은 시스템상 최대 시간당 1회) 기준.
2. **기기별 데이터 편차 상태 신설** — 아이폰=완전 / 아이패드=사용자가 시스템 건강 iCloud 동기화를 켠 경우만 / 맥(Designed for iPad)=HealthKit 없음 → 타일 섹션 숨김·건강 다짐은 "이 기기에선 건강 데이터 없음" 상태('수행일 아님' 패턴 계열의 새 표시 상태).
3. **큰 버전** — 내부 2단계(타일 먼저 완성 → 다짐 얹기) 순서로 구현, TestFlight 자가 테스트 기간 넉넉히.
### 3.2 아키텍처 — HealthCache (핵심)
- **메인 앱만** HealthKit을 조회해 App Group에 "지표×dayKey→값" 캐시를 유지(포그라운드 진입 + `HKObserverQuery`/백그라운드 딜리버리 때 갱신 후 위젯 리로드). **화면·위젯·시리·판정·연속 계산은 전부 이 캐시를 동기 조회** — QuestProgress의 동기 계산 세계를 깨지 않는다. 위젯 확장은 HealthKit 직접 조회 불가이므로 캐시가 유일 경로.
- **워치**: 워치에서 HK 직조회하지 않음 — 건강 다짐 값도 다른 다짐처럼 아이폰이 계산해 스냅숏에 실어 보냄(스냅숏이 곧 캐시 push, 추가 구조 불요).
- ⚠️ **심사 지침 5.1.3 — HealthKit 데이터를 iCloud(CloudKit)에 저장 금지**: HK **값**은 절대 SwiftData/CloudKit에 넣지 않는다(App Group 캐시는 기기 로컬이라 무방). 다짐의 **정의**(지표·목표량·방향·수면 구간)는 일반 데이터이므로 동기화 OK. → "정의는 동기화, 값은 기기별 자기 HealthKit"이 동기화 모델의 전부.
- 읽기 권한은 거부돼도 감지 불가(빈 값이 옴 — 애플 프라이버시 설계) → "표시할 데이터 없음" 상태로 흡수, 권한 재요청 유도 문구는 안내 수준만.
### 3.3 타일(표시 전용, 무료) ✅구현 완료(2026-08-22 — 타일·순서 설정·지표 선택·안내 시트·CTA·HealthCache·엔타이틀먼트, 26.5+18.5 시각 QA·회귀 106건 그린. ⚠QA 도구 주의: simctl spawn defaults의 앱그룹 도메인 쓰기가 18.5 심에선 앱그룹 컨테이너에 닿지 않음 — 26.5는 닿음, 검증 시 참고)
- 형태: 가로 스크롤 컴팩트 타일 줄 + 접기(즐겨찾기/나머지 섹션과 같은 접힘 문법, 접힘 상태 기기 로컬).
- **모음 탭 배치 = 설정으로 제어(사용자 요구 2026-08-20)**: 설정 탭 모음 탭 영역(목표 카드 선택 아래)에 ①**건강 데이터 표시 on/off** ②표시 시 **즐겨찾기 / 나머지 행동 / 건강 데이터 3섹션의 표시 순서 지정** UI 신설(기기 로컬 저장 — 보기 설정 계층). 목표 현황 카드·'현재 진행 중' 영역은 기존대로 상단 고정, 순서 지정 대상은 위 3섹션만(다른 해석 원하면 착수 전 확인).
- 우상단 버튼 → **지표 선택 시트**(표시할 지표 체크+순서, 기기 로컬 — 표시 지표는 다짐 가능 8종보다 넓게 제공 가능).
- **안내 가이드 문구(사용자 요구 2026-08-22)**: 타일 영역에 정보 버튼(또는 각주) → 건강 데이터 특성 안내 시트: 값은 애플 건강 앱이 준 것(앱이 저장·전송하지 않음), 하루 경계·수면 귀속 규칙, 위젯 값의 신선도(실시간 아님), 기기별 차이(아이패드=건강 iCloud 설정 따름·맥=미지원). 도움말 해당 주제와 문구 일관 유지.
- 상태 처리: 맥=섹션 숨김 / 권한 없음·데이터 없음=상태 문구 타일 / 아이패드=자기 HK 기준.
- 운동은 종목별 집계 가능(HKWorkout.workoutActivityType) — 타일 v1은 '운동 시간(엑서사이즈 분)' 기준, 종목별은 후속 후보로만.
### 3.4 건강 다짐 (프리미엄) ✅구현 완료(2026-08-22 — 모델 3필드·값 공급 이음새 3곳·운동 종목 20종·수면 구간·판정 보류·데이터 없음 상태·편집기·자가 검증 H 시리즈 12건. 회귀 61·20·27·10 ALL PASS×2심)
- **모델**: `Quest`에 건강 대상 필드 신설(예: `healthMetricRaw` 기본 "" — §3 CloudKit 규칙 준수: 기본값+스키마 안전). 대상 3유형째(행동/꼬리표/건강 지표). 수면 구간 필드(시작·끝 분, 기본값) 추가.
- **v1 지표 세트(확정 2026-08-22)**: 걸음 수 · 운동 시간 · 수면(특수) · 활동 에너지(kcal) · 이동 거리(km) · 스탠드 시간 · 마음챙김 분 · 물 섭취(L) — 8종. 수면 외 7종은 전부 "논리적 하루 창의 누적 수량"으로 구조 동일 — 한 어댑터로 처리.
- **운동 세부 종목 다짐(확정 2026-08-22 — 사용자 핵심 니즈)**: '운동'은 전체 합산 외에 **종목별 다짐** 지원(예: 달리기 30분 이상) — HKWorkout의 종목별 duration 합산(기록된 운동 기준). `healthMetricRaw`에 종목 파라미터 인코딩(예: workout.running), HealthCache 키도 지표+종목으로 확장(위험 구조는 8종과 동일 — 누적 수량 패턴). **종목 이름은 API가 현지화를 제공하지 않음 → 자체 큐레이션 목록(20종 내외: 달리기·걷기·사이클·수영·근력 운동·요가·필라테스·등산·축구·야구·농구·테니스·배드민턴·골프·줄넘기·복싱·댄스·스트레칭·HIIT·기타)을 ko/en/ja 직접 명명** — 구현 중 목록을 사용자에게 제시해 실사용 종목 포함 확인(비차단), 이후 추가는 케이스+문자열 3개로 저비용. ⚠️'운동 시간'(엑서사이즈 분, 활동 링 기준)과 종목별(기록된 운동 시간)은 값 기준이 다름 — 가이드 문구·도움말에 차이 설명 필수.
- **수면 귀속 규칙(사용자 설계, 2026-08-20)**: 다짐 전용 **수면 구간**(기본 전날 21:00 ~ 당일 09:00, 사용자 지정 가능) 안의 수면 합을 **'깨어난 날' 하루에 통귀속**. ⚠️ 시간 세션의 겹침 분할과 다른 규칙이지만 **의도된 예외**(수면은 깬 날의 것으로 세는 도메인 관습 — deadlineMinutes와 같은 '다짐 전용 측정 창' 계열의 확장). 소스 중복(아이폰+워치 동시 기록)은 '잠듦' 구간 **합집합 병합**. 하루 단위 전용(요일 스케줄 가능), 주간 합산 다짐 v1 제외.
- **진행률 의미론 — 기존 §4.2와 완전 동일 유지**: atLeast 게이지 min(값/목표,1)·퍼센트 초과 표기, atMost, 연속 달성(하루 버킷·시작일 하한·400일 상한), 판정 시점 클리핑, 주기 몫 완료, 수행일 아님. 단 **마감 시각 옵션은 건강 다짐 v1 미지원(§8ⓔ 확정 — 캐시가 하루 단위 값이라 부분 창 미지원, 편집기에서 숨김)**. HealthProgress 어댑터가 QuestProgress와 같은 수치 계약을 지키고, 값 공급원만 HealthCache로 다름.
- **과금 게이트**: 건강 다짐 생성 = 프리미엄(`PremiumManager` 경유 — canAddQuest에 건강 분기 또는 전용 판정). 만료 정책 **확정(2026-08-22)**: 기존 원칙 그대로 — 이미 만든 건강 다짐은 만료 후에도 유지·표시, 추가 생성만 제한.
- **파급 표면(전수)**: QuestEditorView(대상 3유형째+지표 픽커+수면 구간 UI — CollapsibleTimeWheel 재사용) · 목표 탭 행 · 모음 카드 · 일기 '이 날의 목표'(과거 날짜는 캐시/실조회) · 위젯 ②③④(캐시 조회) · 워치(스냅숏 동승) · 시리 다짐 조회 · evaluateIfEnded 판정 · CSV(다짐 CSV에 건강 다짐 행 — 기록 CSV 무영향, 가져오기 비대상 유지 §6.8) · 무료 한도 카운트(목표당 3개에 귀속).
- **이중 상태 정규화(혼합 버전 대비 — 2026-08-22 검토)**: 구버전(1.0~1.4) 편집기가 "대상 없음"으로 보이는 건강 다짐에 행동/꼬리표를 지정·저장하면 지표+행동이 공존할 수 있음 → 판독 규칙은 **행동/꼬리표 우선**(사람의 최신 의도 존중), 1.5 편집기는 저장 시 반대편 필드를 정리해 일관 상태 복원.
### 3.5 심사·문서 체크리스트
- HealthKit 엔타이틀먼트 + `NSHealthShareUsageDescription`(ko/en/ja — InfoPlist.xcstrings).
- **`Docs/PRIVACY.md`에 건강 데이터 문단 추가 필수**(5.1.3 요구): 읽기 전용·기기 밖 전송 없음·iCloud 저장 없음 명시. 개인정보 라벨 "데이터 수집 안 함" 유지 가능(개발자 서버 전송 없음).
- 결제 화면(PremiumView) 기능 목록에 '건강 다짐' 추가, 도움말 신규 주제(§5), Marketing 자료 갱신(§6).
- **CloudKit 스키마 배포 체크(2026-08-22 — 사용자 기억 없음, 아리나 주도)**: 착수 첫 단계에서 개발 환경 스키마 생성·CloudKit 콘솔 상태 확인(1.3의 DiaryPageItem 필드 8개가 프로덕션에 있는지도 함께 판독 — 당시 배포 이력 불명). 출시 게이트에서 프로덕션 배포가 필요하면 콘솔 작업은 사용자 계정이 필요 → 아리나가 정확한 절차를 안내하고 사용자가 실행. 배포 없이 1.5를 내보내면 새 필드 동기화가 실패할 수 있으므로 **출시 전 필수 관문**. → ✅**배포 완료(2026-08-22)**: 개발 스키마에 Quest 필드 3종이 없어(디버그 내보내기 이력 없음) 시뮬 519869F7에 사용자 iCloud 로그인 후 `-premium YES -cloudSync YES -seedHealthQuest YES` 실행 → Sandbox 내보내기 성공(98레코드, error nil)으로 생성 → 사용자가 콘솔에서 프로덕션 배포. **판독 결과: 1.3의 DiaryPageItem 스타일 필드는 프로덕션 미배포 상태였음**(마지막 배포=1.0 출시 시점) — 이번 배포에 동승해 해소, 소킹 중 아이패드↔맥 도형·텍스트 상자 동기화 교차 확인 권장. → ✅**회복 확인(2026-08-22 밤, 사용자 실기기)**: 첫 배포에는 스타일 필드가 실리지 못했음(개발 스키마에도 미생성 — 아이템 있는 기기의 동기화 전체 정지로 실측 발각). 시뮬 내보내기로 개발 스키마에 필드 생성 → 콘솔 재배포 → 도형·텍스트 상자 있는 상태의 동기화 왕복 정상.
### 3.6 검증
- `-progressSelfTest`에 건강 어댑터 시리즈 추가(HealthCache 주입식 인메모리 — 실 HK 비의존): 수면 구간 경계(자정 걸침·구간 밖 수면·하루 시작 시간 05:00 조합), atLeast 캡·초과, 연속, 판정 클리핑.
- 시뮬 검증용 캐시 시드 인자(예: `-seedHealthCache`) 신설 — 시뮬레이터 HK 실데이터 없이 전 표면 렌더 확인.
- 기기별 상태: 맥 분기 `-forceMacLayout`, 권한 없음/데이터 없음 상태, 아이패드 심.
## 4. 하위 OS 인하 — 기각 기록 (재제안 방지)
2026-08-20 검토 후 사용자 철회. 근거(재검토 시 참고): ①iOS 17·18은 지원 아이폰 목록 동일(XS/XR 이후) → 인하해도 신규 커버 아이폰 0대, 노치 중 미지원은 iPhone X(iOS 16 최대)뿐 ②iPadOS 17 인하 시 추가는 iPad 6세대·Pro 10.5"·Pro 12.9" 2세대(2017~18) 3기종뿐 ③iOS 16 이하는 SwiftData(17+)라 데이터층 재작성 = 불가 ④17 지원 실비용: `LiveActivityIntent`(17.2 도입) 채택 인텐트 4종 구조 수술 + 제어 센터 API 3곳·ControlWidget 18 가드 + 심볼 감사·QA 라인 추가 + 17 SwiftData 안정성 리스크. **재검토 트리거**: 구형 기기 사용자의 실제 설치 문의 발생 시(아이패드만 따로 인하 불가 — 배포 타깃 공용 유의).
## 5. 기능 3 — 도움말 한국어 자연화 (예약분, 사용자 지시 2026-08-12) ✅구현 완료(2026-08-22 — 전 주제 자연화[오타·번역투·UI 명칭 정정 포함]+신규 주제 3개[행동 컴플리케이션·건강 2종], en/ja 전면 재번역·용어 통일[アクション·クエスト 등], 전 카탈로그 missing/stale 0)
- HelpView 전체 문구를 **한국어 기준으로 재작성** — 말투 컨셉(~해요체) 유지, 번역투·어색한 단어 선택·문장 구성 정리. en/ja도 함께 재검토.
- 1.5 신규 기능 주제 추가와 병행: 행동 컴플리케이션(워치 그룹), 건강 타일·건강 다짐(그룹 배치는 구현 시 결정, 이미지는 그룹당 대표 1주제 원칙 유지). **건강 주제는 특성 설명을 상세히(사용자 요구 2026-08-22)**: 하루 경계 처리, 수면 구간·깨어난 날 귀속, 위젯 신선도(실시간 아님), 기기별 편차(아이폰/아이패드/맥), 판정 보류 규칙, 데이터가 기기 밖으로 나가지 않는다는 점 — 모음 탭 가이드 문구(§3.3)와 동일 내용의 확장판.
- l10n 루틴(§2.3) 필수, 도움말 스크린샷은 문구·화면 변화 정도 보고 재촬영 판단.
## 6. 공통 마무리 작업 (출시 전) ✅구현분 완료(2026-08-22 — 버전 1.5(1)·whats-new·프로모션·설명·PRIVACY·스크린샷 원본 57장+합성 63장. 잔여=사용자 절차: TestFlight 소킹, CloudKit 콘솔 스키마 배포 확인[§3.5], ASC 업로드 → 2026-08-22 현재: 빌드 3 업로드·스키마 배포 완료[§3.5 ✅], 소킹 진행 중[약 1주] — 남은 것=심사 제출)
- MARKETING_VERSION 1.5, `Marketing/AppStore/whats-new-1.5.txt`(**"여러 기기를 쓰면 모든 기기에서 업데이트" 완화 문구 포함** — 확정 2026-08-22), 프로모션 텍스트 1.5판.
- **스크린샷 전면 신규 제작(확정 2026-08-22)**: 기존 세트 전부 폐기, **아이폰 10장·아이패드 10장 × ko/en/ja 신규**(스타일은 현재와 동일, 구성·이미지 일신 — 1.5 기능 반영. 워치 합성 1장 유지 여부는 시안 때 결정). 촬영·합성은 Marketing/README 절차 준용, 장면 구성 시안은 마무리 단계에서 사용자 확인.
- 자가 검증 전체 회귀(-progressSelfTest 확장분 포함 4종+신규 인자), Debug/Store/워치 빌드, 26+18.5 심 QA.
- CLAUDE.md 현행 명세 갱신(§6.1 모음 탭·§6.4 다짐·§11 워치·§14 인자 등) + 이 문서 완료 표기.
## 7. 구현 순서 제안
① 행동 컴플리케이션 → ② 건강 타일(권한·HealthCache 기반 공사 포함) → ③ 건강 다짐(어댑터→편집기→전 표면) → ④ 도움말 자연화(신규 주제 포함, 문구가 확정된 마지막에) → ⑤ 마무리(§6). 단계마다 빌드+심 검증+커밋.
## 8. 건강 다짐 × 위젯 전수 점검 (2026-08-20 후속 분석 — 사용자 질문 "③ 인터랙티브 위젯 처리")
- **③ 다짐 링(인터랙티브)**: 건강 다짐 셀은 **꼬리표 대상 다짐과 동일 문법** — 버튼 없는 표시 전용 셀, 탭=앱 열기(§10에 '의도된 동작'으로 기존 문서화). 누적값 줄은 HealthCache 값, atMost·주기 몫 완료 등 표시 상태 전부 상속. 셀에 지표 심볼 소표기(디자인 디테일). ✅확정(사용자 승인 2026-08-22)
- **무관(행동·세션 전용)**: ① 행동 실행 · ⑥ 현재 진행 중 · 제어 센터 · Live Activity.
- **표시 전용이라 구조 무관, 캐시 값만 소비**: ② 목표 바 · ④ 다짐 그리드 · 잠금화면(다짐 점·게이지 포함).
- **⑤ 행동 통계 = 건강 비대상 선언** — 통계 탭·⑤는 행동 기반, 건강 표시는 모음 탭 타일 담당(범위 못 박기).
- **위젯 공통**: ⓐ갱신 경로 신설 — DataChange.commit 외에 백그라운드 딜리버리→캐시 갱신→reloadAllTimelines(주기 폴링 아님, §10 예산 전략과 충돌 없음. 신선도=시간 단위 감수 §3.1) ⓑ하루 경계는 기존 타임라인 안전망으로 새 날 0 리셋 자동 ⓒ**데이터 없는 기기(맥 데스크톱 위젯·건강 미동기화 아이패드)**: 건강 다짐 셀을 '수행일 아님' 문법 재사용(② 대시·③ 문구·④ 흐림)으로 '데이터 없음' 표시 + **combinedSpanRatio 모수에서 제외**(§4.3 하루 span 선례와 동일 문법) ✅확정(사용자 승인 2026-08-22) ⓓ③④ 슬롯 픽커에 건강 다짐 표시명 노출, 과금은 위젯=프리미엄이라 자연 정합.
- **파생 결정 2건**: ⓔ건강 다짐 v1 **마감 시각 옵션 미지원(숨김)** 추천 — 캐시가 하루 단위 값이라 부분 창은 시간대 캐시가 따로 필요, 실익 대비 과함(수면은 자체 구간 보유. §3.4의 "마감 적용 가능" 표기는 이 결정으로 대체) ✅확정(사용자 승인 2026-08-22) ⓕ**판정 보류 규칙(중요)**: 건강 다짐 포함 목표의 자동 판정(evaluateIfEnded)은 건강 데이터 가용 기기에서만 실행 — 불가 기기(맥 등)에선 보류해 다음 가용 기기 실행 때 판정(빈 캐시로 미달성 오판→CloudKit 전파 방지) ✅확정(사용자 승인 2026-08-22)
## 9. 착수 시 사용자에게 확인할 것
1. §3.4 지표 8종 제안 확정(빼기/더하기 — 사용자가 "지표 더 추가"만 선택하고 세트는 미지정)
2. 건강 다짐 프리미엄 만료 시 처리(기존 원칙대로 "이미 만든 건 유지"면 확인만)
3. 도움말 스크린샷 재촬영 범위 (모음 탭 이미지에 건강 타일 반영 여부 포함)
(§8의 3건은 2026-08-22 사용자 승인으로 확정 — 결정 이력 7 참조)
## 10. 구현 전 정밀 위험 검토 (2026-08-22 — "1.4 무결 보존" 지시에 따른 전수 점검)
### 10.1 실코드로 확인된 안전 근거 3건
- **R1 크로스 버전 동기화(최대 우려 해소)**: 1.5가 만든 건강 다짐이 CloudKit으로 1.4 기기에 내려가면 targetAction·targetTag 둘 다 nil인 다짐으로 보인다 — 1.4 코드는 이미 `Quest.targetName`이 "대상 없음"(Models.swift:422, l10n 완비)·`targetSymbol`이 tag.fill로 폴백하고, 진행률은 `targetActions` 빈 배열이라 0%(atLeast) 안전 강등. **크래시 경로 없음(실코드 확인)**. 잔여 무해 오표시: atMost 건강 다짐이 1.4에서 '한도 지킴'으로 보임 + 1.4 편집기로 그 다짐을 열어 저장하면 대상이 바뀔 수 있음(사용자 규모·단일 기기 위주로 위험 수용, 구현 시 재확인)
- **R2 QuestProgress 이음새**: 값 산출이 `agg.seconds/count(for: quest.targetActions, …)` 5개 지점(current 149-150 · spanProgress 267-268 · 287-288 · streak 411)으로 수렴 — 단일 값 공급 헬퍼로 묶어 기록/건강(캐시) 분기하면 **수학 로직 무변경**. 기존 `-progressSelfTest` 49건 무변경 통과가 1.4 보존의 회귀 증거(주기 몫 완료 때와 같은 검증 문법)
- **R3 워치 스냅숏 호환**: 직렬화가 JSONEncoder/Decoder(WatchPayload.swift:57-61) — 구워치×새스냅숏=미지 키 무시, 새워치×구캐시=optional nil. 양방향 안전(isFavorite·runningActionID 선례 동일)
### 10.2 위험 등록부 (상=회귀 가능성 실재 / 중=설계로 예방 / 하=QA로 커버)
- **[상] R4 MainView 금지구역**: 건강 섹션·3섹션 순서는 §6.1 실기기 버그 이력 지대(iPad 비-lazy AdaptiveColumnsLayout·셀 높이 규칙·드래그 델리게이트)를 지나감. 완화: `actionGrid` 빌더·레이아웃 코드 무변경, 건강 섹션은 독립 뷰로 VStack 순서만 재배열, **편집(배치) 모드에서는 건강 섹션 숨김**(드롭 델리게이트 상호작용 원천 차단), 순서 기본값=즐겨찾기→나머지→건강+표시 기본 ON(첫 타일은 권한 CTA — 권한 요청은 탭에서만)
- **[상] R5 판정 무결**: evaluateIfEnded는 아무 기기에서나 실행 — 건강 다짐 **없는** 목표의 판정 경로는 분기 없이 기존 코드 그대로(래핑 금지). 건강 포함 목표만: 판정은 인앱이므로 **판정 시점 HK 실조회(권위 경로 — 캐시 희소성 무관, judgmentReference 클리핑 자연 충족)**, 가용성 없으면 보류(§8ⓕ)
- **[상] R6 l10n 대량 변경**: 자연화+신규 문자열+가이드 문구 = §2.3 오염 함정(Xcode 재저장 stale 대란 실전 이력) 최대 노출 구간. 완화: 자연화는 **마지막 단계**로 분리, 단계마다 타깃별 sync·전 카탈로그 missing/stale 0 확인, DEBUG manual 문자열 불가침
- **[중] R7 makeSnapshot 비용**: 기간값은 옵트인 행동만 계산, `-seedBulk` 1만 건으로 커밋→푸시 지연 실측(필요 시 기간 창 1회 페치+버킷 공유 — StatsData 문법)
- **[중] R8 수면 귀속 총칙**: "수면 구간의 **끝이 속한 논리적 하루**에 귀속"으로 일반화 — 하루 시작 시간이 어떤 값이어도 정의됨(끝=하루 시작 정각이면 그 하루 포함 명시). 구간 길이 UI 상한(예 20시간). 구간·하루 시작 변경 시 재계산은 기존 설정 변경 동작과 동일(값은 HK 소유라 정의만 변경)
- **[중] R9 스트릭 백필**: 권한 승인 시 과거 400일 1회 백그라운드 백필 — 완료 전 연속 과소 표시 과도기(가이드 문구 한 줄). 캐시 보존 지표당 400일
- **[중] R10 초기화 상호작용**: '전체 초기화'에 HealthCache·건강 로컬 키 청소 추가(`-dataResetTest` 확장). 범위 삭제는 무관(값이 HK 소유)
- **[중] R11 엔타이틀먼트 격리**: HealthKit 엔타이틀먼트·usage description은 **iOS 앱 타깃만** — 위젯·워치 타깃 무변경(프로비저닝·심사 잡음 방지)
- **[중] R12 컴플리케이션 구성 잔존**: 옵트아웃/삭제 행동이 페이스에 남으면 첫 옵트인 행동 폴백→없으면 빈 상태+해결 안내(§11 목표 폴백 문법). recommendations description은 Text(verbatim:)만(§11 즉사 경고)
- **[하] R13 iOS 18 하한**: 신규 API 전부 iOS 18/watchOS 10 이하 확인(HK 통계·옵저버 쿼리는 구식 API라 안전), 18.5 심 **Release 포함** 빌드 확인(플랫폼 행 컴파일러 크래시 전례 — 제네릭 중첩 코디네이터 패턴 회피)
- **[하] R14 위젯 규칙**: 건강 셀은 버튼 없음이라 invalidatable/히트 영역 함정 해당 적음, 하루 경계는 기존 타임라인 안전망으로 새 날 0 리셋 자동(§8ⓑ)
- **[하] R15 도움말 이미지**: 자연화는 문구 변경이라 예시 이미지 18장 재촬영 원칙 불필요(앱 화면 예시), 모음 탭 이미지만 건강 타일 반영 여부 판단(§9-3) — ※스토어 스크린샷은 별개로 전면 신규(§6, 2026-08-22 확정)
- **[기록] R16 혼합 버전(1.0~1.4 × 1.5) 검토 결과(2026-08-22)**: 1.0 RC(f05e611) 실코드로 `targetName` "대상 없음"·`targetActions` [] 폴백이 **1.0부터 존재** 확인 — 전 버전 안전 강등, 대상 강제 언래핑 0, KVS 무변경, 워치는 과도기만(R3). 잔여 특이 2건: ⓐ구버전 기기가 건강 포함 목표를 먼저 자동 판정하면 미달성 오판 가능 — 1.5 기기에서 종료일 재저장→재판정으로 회복, 팝업(§11)·whats-new 全기기 업데이트 안내로 완화 ⓑ구버전 편집 시 이중 상태 — §3.4 정규화 규칙으로 해소
### 10.3 안정성 실행 수칙 (전 단계 공통 — 사용자 지시 2026-08-22 "1.4 무결 보존")
1. **격리 원칙**: 신규 코드는 신규 파일 우선(HealthStore/HealthCache/HealthProgress·신규 컴플리케이션·미니 화면), 기존 파일은 가산적 분기만. 금지구역(§6.1 lazy·§6.5 휠 구조·§10 invalidatable·§11 verbatim·§6.6 StatSpan) 진입 전 재확인
2. **단계 게이트**: §7 순서의 각 단계 끝마다 자가 검증 전체(기존 49·20·27·10 + 신규) ALL PASS + Debug/Store/워치 빌드 + 26·18.5 심(워치 11.5·26.2) 시각 QA + 커밋. 이전 단계 그린 없이 다음 단계 진입 금지
3. **출시 게이트**: 전 단계 완료 후 TestFlight 실기기 소킹(사용자) → PRIVACY.md·심사 체크(§3.5) 동반 제출
## 11. 기능 4 — 업데이트 신기능 소개 팝업 (2026-08-22 사용자 추가) ✅구현 완료(2026-08-22 — WhatsNewView·버전당 1회·신규 설치 시드·온보딩 우선·-showWhatsNew, 3언어)
- 업데이트 후 첫 실행 시 스플래시 뒤 **버전당 1회** 표시되는 신기능 소개 시트(통상의 "이번 업데이트" 팝업 관습): 1.5 신기능 카드(행동 컴플리케이션·건강 타일·건강 다짐·도움말 개편) + **"여러 기기를 쓰신다면 모든 기기에서 업데이트해 주세요" 안내 1줄**(혼합 버전 완화 — §10 R16 연계).
- 표시 규칙: standard defaults에 마지막 표시 버전 기록(예: `whatsnew.lastShownVersion`) — 저장된 버전과 현재 버전이 다르고 소개 콘텐츠가 있는 버전일 때만 표시, 닫는 즉시 기록(재표시 없음). **신규 설치는 미표시**(첫 실행 안내는 온보딩 담당 — 최초 실행 시 현재 버전을 시드). 온보딩과 동시 표시 금지(온보딩이 우선).
- 구조는 OnboardingView 스타일 재사용, 향후 버전에서 콘텐츠만 교체 가능한 구조로. l10n 3언어, 검증 인자(예: `-showWhatsNew`) 신설.
## 12. 1.5 추가분 — 소킹 중 사용자 요구 5건 (2026-08-22 저녁, 빌드 4) ✅구현 완료
사용자 결정: 1.6이 아니라 **1.5에서 해결**. 세부 UX는 아리나 위임(전제: 기존 기능·사용성 무변화, 버그·충돌 없음). 확정 4결정: ①아이폰 노트 필기= b안(맥 '그리기' 토글 문법, 손가락) ②타임테이블 건강 블록 기본 켬 ③건강 카드 지표 선택= 전 날짜 공통(기기 로컬) ④새 수면 다짐 기본 구간= 타일 설정 시드.
1. **맥 일기 필터창 건강 안내** — RecordFilterSheet 건강 섹션이 맥(HealthDataStore 불가)에선 토글 대신 안내 문구.
2. **아이폰 일기 탭** — AppTab.phoneCases 개방(+radialOrder 필터 제거, 버블 8개 자동 배치). 노트 도구줄= 맥과 같은 가로 스크롤+'그리기' 토글(DeviceLayout.isPhone 신설, drawingPolicy anyInput, 배치↔그리기 상호 배타). 일기 잠금 설정 전 기기 노출, 아이패드 경로 무변경.
3. **일기 '건강 데이터' 카드** — DiarySection.health(케이스 마지막 — 기존 사용자 목록 끝 추가), DiaryHealthCard(HealthCache 하루 값, 수면은 SleepWindowPrefs 유효 구간 키), 지표 선택 diary.healthMetrics(비면 타일 상속), 맥 숨김, 인쇄 요약 DiaryPrintHealthRow 동승.
4. **일기 타임테이블 수면·운동 실구간****HealthIntervals 캐시 신설**(App Group health.intervals.v1, 400일, 실구간을 논리적 하루로 분할·병합 저장 — 다짐의 '깨어난 날 통귀속'과 다른 사실 그대로 표시, CloudKit 금지 동일). refreshRecent(3일)+백필이 유지, 화면·내보내기는 injectingHealthBlocks 주입(캘린더 전례, 최하층 반투명+실선 스타일), 색= 수면 인디고·운동 주황(지표 고정색), 필터 시트 '건강 데이터' 토글(diary.timetableHealthHidden — 전 날짜 공통, 기본 켬), 일기 필터 버튼 상시 노출화.
5. **수면 표시 구간 설정** — SleepWindowPrefs(전체 스펙+요일별, 시작=끝이면 24시간 창), 설정 → 건강 데이터 → '수면 표시 구간'. 평문 "sleep" 캐시 키= 그날 유효 구간 값(타일·카드 공유), 백필 서명에 요일 매핑 포함, QuestEditor 새 수면 다짐 기본값 시드. 발단: 사용자 교대·야간 근무 실측(주말 낮 수면이 기본 창 밖 → 타일 0).
6. 부수 실측 수정: 일기 목표 카드 건강 다짐 값 단위("8,432회/8,000보" → 지표 단위).
검증: 자가 검증 61/20/27/10 ALL PASS, 3종 빌드 그린, 전 카탈로그 missing/stale 0, 시각 QA 10여 장(아이폰 요약·카드·블록·노트·필터·버블8·수면 구간, 아이패드, 맥 분기[카드 숨김], 18.5). 마케팅: 아이폰 06-bubble 재촬영(버블 8개)·10-week→**10-diary** 교체·아이패드 03-diary-summary 재촬영(건강 카드·블록), whats-new-1.5/설명 3언어 갱신. 빌드 4.
### §12 후속 — 소킹 실기기 피드백 반영 (같은 날 밤, 빌드 5)
- **버그 ⓐ**: 아이폰 더보기 탭 안 일기 달력에서 날짜를 눌러도 상세로 안 들어감(터치 반응만) — `AppRouter.morePath: [AppTab]`(고정 타입)에는 Date를 푸시할 수 없어 조용히 무시. → `NavigationPath`로 변경, 회귀 감시 인자 `-morePushDiaryToday`(더보기 스택에 [일기, 오늘] 프로그램 푸시 → 상세 착지 실측 확인). 라디얼·사이드바(비타입 스택)는 원래 정상 — "처음엔 됐다"는 증언과 일치.
- **버그 ⓑ**: 수면 블록이 수면 단계(코어·렘·깸) 로우데이터 그대로 칸칸이 갈라짐 — 표시 병합 규칙 신설: **10분 이하의 깸은 이어 붙임**(`sleepDisplayMergeGap`, mergedIntervals에 tolerance 파라미터). 사용자 규칙 "연속으로 잤으면 한 칸, 20분쯤 깼다 자면 분리". 값(합계)은 실제 잔 시간 그대로 무영향.
- **추가 요구 2건**: ①**타임테이블 표시 색 설정**(설정 → 건강 데이터 — 수면·운동 ColorPicker, 기본 인디고·주황=빈 값, App Group 기기 로컬, DiaryHealthTimetable.sleepColor/workoutColor 단일 지점이라 전 타임테이블·내보내기 자동 공통) ②**기록 탭 타임테이블에도 수면·운동 블록**(하루·주간 — 같은 공급 지점·같은 숨김 토글[기록 필터 시트에 건강 섹션 추가], 내보내기 `injectingHealthBlocks(forDayKeys:)` + trim 범위 확장. plan-1.6 후보 1의 잔여분 조기 흡수 — 1.6에 남은 것은 물 점 표시뿐).
- 도움말·whats-new·팝업 문구 갱신, l10n 0/0, 빌드 5.
### §12 후속 2 — 버블 찌그러짐 (2026-08-23, 빌드 6)
- **실기기 실측(사용자)**: 버블 메뉴 펼침 상태에서 각 원이 이웃 버블 방향으로 늘어나 찌그러짐("서로 인력을 가진 느낌"). 원인: 일기 버블 추가로 8개가 되며 이웃 가장자리 간격이 ~9.6pt로 줄었는데, 유리 합체 판정 거리 `glassBlendSpacing`이 7개 시절 기준 18pt 그대로라 **정지 상태에서도 이웃끼리 합체 판정에 걸림**(1.4까지 7개는 간격 ~20.7pt로 판정 밖 — "1.3까지는 문제없었다"는 증언과 일치).
- 수정: 18→6 (펼침 상태 정원 분리 확인 — 시각 QA. FAB에서 피어나는 모핑은 겹침 구간에서 일어나므로 유지). 마케팅 06-bubble ×3 재촬영(구 샷에 왜곡 찍혀 있었음), 코드 주석에 "탭 추가 시 간격 하한 재확인" 경고.