From 8a5df2233a590fe904c8418d45989d51a67bd3f2 Mon Sep 17 00:00:00 2001 From: songyc macbook Date: Sat, 22 Aug 2026 00:59:35 +0900 Subject: [PATCH] =?UTF-8?q?docs(plan-1.5):=20=C2=A78=203=EA=B1=B4=20?= =?UTF-8?q?=EC=82=AC=EC=9A=A9=EC=9E=90=20=EC=8A=B9=EC=9D=B8=20=ED=99=95?= =?UTF-8?q?=EC=A0=95=20+=20=EA=B1=B4=EA=B0=95=20=EA=B0=80=EC=9D=B4?= =?UTF-8?q?=EB=93=9C=20=EB=AC=B8=EA=B5=AC=20=EC=9A=94=EA=B5=AC=20+=20?= =?UTF-8?q?=C2=A710=20=EC=A0=95=EB=B0=80=20=EC=9C=84=ED=97=98=20=EA=B2=80?= =?UTF-8?q?=ED=86=A0(R1~R15)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 크로스 버전 동기화·QuestProgress 이음새·스냅숏 호환 실코드 확인 근거 기록 - 안정성 실행 수칙(격리·단계 게이트·출시 게이트) 명문화 — 1.4 무결 보존 지시 반영 Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01WtZwRRjbtM9pZJDM4FkTq6 --- myApp/HaruDanim/Docs/plan-1.5.md | 45 +++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/myApp/HaruDanim/Docs/plan-1.5.md b/myApp/HaruDanim/Docs/plan-1.5.md index ddc3347..14dc7c3 100644 --- a/myApp/HaruDanim/Docs/plan-1.5.md +++ b/myApp/HaruDanim/Docs/plan-1.5.md @@ -22,6 +22,7 @@ 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 위험 검토가 그 근거 문서 ## 2. 기능 1 — 워치 행동 컴플리케이션 @@ -59,6 +60,7 @@ - 형태: 가로 스크롤 컴팩트 타일 줄 + 접기(즐겨찾기/나머지 섹션과 같은 접힘 문법, 접힘 상태 기기 로컬). - **모음 탭 배치 = 설정으로 제어(사용자 요구 2026-08-20)**: 설정 탭 모음 탭 영역(목표 카드 선택 아래)에 ①**건강 데이터 표시 on/off** ②표시 시 **즐겨찾기 / 나머지 행동 / 건강 데이터 3섹션의 표시 순서 지정** UI 신설(기기 로컬 저장 — 보기 설정 계층). 목표 현황 카드·'현재 진행 중' 영역은 기존대로 상단 고정, 순서 지정 대상은 위 3섹션만(다른 해석 원하면 착수 전 확인). - 우상단 버튼 → **지표 선택 시트**(표시할 지표 체크+순서, 기기 로컬 — 표시 지표는 다짐 가능 8종보다 넓게 제공 가능). +- **안내 가이드 문구(사용자 요구 2026-08-22)**: 타일 영역에 정보 버튼(또는 각주) → 건강 데이터 특성 안내 시트: 값은 애플 건강 앱이 준 것(앱이 저장·전송하지 않음), 하루 경계·수면 귀속 규칙, 위젯 값의 신선도(실시간 아님), 기기별 차이(아이패드=건강 iCloud 설정 따름·맥=미지원). 도움말 해당 주제와 문구 일관 유지. - 상태 처리: 맥=섹션 숨김 / 권한 없음·데이터 없음=상태 문구 타일 / 아이패드=자기 HK 기준. - 운동은 종목별 집계 가능(HKWorkout.workoutActivityType) — 타일 v1은 '운동 시간(엑서사이즈 분)' 기준, 종목별은 후속 후보로만. @@ -66,7 +68,7 @@ - **모델**: `Quest`에 건강 대상 필드 신설(예: `healthMetricRaw` 기본 "" — §3 CloudKit 규칙 준수: 기본값+스키마 안전). 대상 3유형째(행동/꼬리표/건강 지표). 수면 구간 필드(시작·끝 분, 기본값) 추가. - **v1 지표 세트(제안 8종 — 착수 시 사용자 확인으로 확정)**: 걸음 수(회 표기 계열) · 운동 시간 · 수면(특수) · 활동 에너지(kcal) · 이동 거리(km) · 스탠드 시간 · 마음챙김 분 · 물 섭취(L). 수면 외 7종은 전부 "논리적 하루 창의 누적 수량"으로 구조 동일 — 한 어댑터로 처리. - **수면 귀속 규칙(사용자 설계, 2026-08-20)**: 다짐 전용 **수면 구간**(기본 전날 21:00 ~ 당일 09:00, 사용자 지정 가능) 안의 수면 합을 **'깨어난 날' 하루에 통귀속**. ⚠️ 시간 세션의 겹침 분할과 다른 규칙이지만 **의도된 예외**(수면은 깬 날의 것으로 세는 도메인 관습 — deadlineMinutes와 같은 '다짐 전용 측정 창' 계열의 확장). 소스 중복(아이폰+워치 동시 기록)은 '잠듦' 구간 **합집합 병합**. 하루 단위 전용(요일 스케줄 가능), 주간 합산 다짐 v1 제외. -- **진행률 의미론 — 기존 §4.2와 완전 동일 유지**: atLeast 게이지 min(값/목표,1)·퍼센트 초과 표기, atMost, 마감 시각(누적형 지표에 적용 가능), 연속 달성(하루 버킷·시작일 하한·400일 상한), 판정 시점 클리핑, 주기 몫 완료, 수행일 아님. HealthProgress 어댑터가 QuestProgress와 같은 수치 계약을 지키고, 값 공급원만 HealthCache로 다름. +- **진행률 의미론 — 기존 §4.2와 완전 동일 유지**: atLeast 게이지 min(값/목표,1)·퍼센트 초과 표기, atMost, 연속 달성(하루 버킷·시작일 하한·400일 상한), 판정 시점 클리핑, 주기 몫 완료, 수행일 아님. 단 **마감 시각 옵션은 건강 다짐 v1 미지원(§8ⓔ 확정 — 캐시가 하루 단위 값이라 부분 창 미지원, 편집기에서 숨김)**. HealthProgress 어댑터가 QuestProgress와 같은 수치 계약을 지키고, 값 공급원만 HealthCache로 다름. - **과금 게이트**: 건강 다짐 생성 = 프리미엄(`PremiumManager` 경유 — canAddQuest에 건강 분기 또는 전용 판정). 만료 정책은 기존 원칙(이미 만든 것은 유지, 추가 생성만 제한)을 따를지 착수 시 확정. - **파급 표면(전수)**: QuestEditorView(대상 3유형째+지표 픽커+수면 구간 UI — CollapsibleTimeWheel 재사용) · 목표 탭 행 · 모음 카드 · 일기 '이 날의 목표'(과거 날짜는 캐시/실조회) · 위젯 ②③④(캐시 조회) · 워치(스냅숏 동승) · 시리 다짐 조회 · evaluateIfEnded 판정 · CSV(다짐 CSV에 건강 다짐 행 — 기록 CSV 무영향, 가져오기 비대상 유지 §6.8) · 무료 한도 카운트(목표당 3개에 귀속). @@ -87,7 +89,7 @@ ## 5. 기능 3 — 도움말 한국어 자연화 (예약분, 사용자 지시 2026-08-12) - HelpView 전체 문구를 **한국어 기준으로 재작성** — 말투 컨셉(~해요체) 유지, 번역투·어색한 단어 선택·문장 구성 정리. en/ja도 함께 재검토. -- 1.5 신규 기능 주제 추가와 병행: 행동 컴플리케이션(워치 그룹), 건강 타일·건강 다짐(그룹 배치는 구현 시 결정, 이미지는 그룹당 대표 1주제 원칙 유지). +- 1.5 신규 기능 주제 추가와 병행: 행동 컴플리케이션(워치 그룹), 건강 타일·건강 다짐(그룹 배치는 구현 시 결정, 이미지는 그룹당 대표 1주제 원칙 유지). **건강 주제는 특성 설명을 상세히(사용자 요구 2026-08-22)**: 하루 경계 처리, 수면 구간·깨어난 날 귀속, 위젯 신선도(실시간 아님), 기기별 편차(아이폰/아이패드/맥), 판정 보류 규칙, 데이터가 기기 밖으로 나가지 않는다는 점 — 모음 탭 가이드 문구(§3.3)와 동일 내용의 확장판. - l10n 루틴(§2.3) 필수, 도움말 스크린샷은 문구·화면 변화 정도 보고 재촬영 판단. ## 6. 공통 마무리 작업 (출시 전) @@ -103,18 +105,43 @@ ## 8. 건강 다짐 × 위젯 전수 점검 (2026-08-20 후속 분석 — 사용자 질문 "③ 인터랙티브 위젯 처리") -- **③ 다짐 링(인터랙티브)**: 건강 다짐 셀은 **꼬리표 대상 다짐과 동일 문법** — 버튼 없는 표시 전용 셀, 탭=앱 열기(§10에 '의도된 동작'으로 기존 문서화). 누적값 줄은 HealthCache 값, atMost·주기 몫 완료 등 표시 상태 전부 상속. 셀에 지표 심볼 소표기(디자인 디테일). ⏳확정 대기 +- **③ 다짐 링(인터랙티브)**: 건강 다짐 셀은 **꼬리표 대상 다짐과 동일 문법** — 버튼 없는 표시 전용 셀, 탭=앱 열기(§10에 '의도된 동작'으로 기존 문서화). 누적값 줄은 HealthCache 값, atMost·주기 몫 완료 등 표시 상태 전부 상속. 셀에 지표 심볼 소표기(디자인 디테일). ✅확정(사용자 승인 2026-08-22) - **무관(행동·세션 전용)**: ① 행동 실행 · ⑥ 현재 진행 중 · 제어 센터 · Live Activity. - **표시 전용이라 구조 무관, 캐시 값만 소비**: ② 목표 바 · ④ 다짐 그리드 · 잠금화면(다짐 점·게이지 포함). - **⑤ 행동 통계 = 건강 비대상 선언** — 통계 탭·⑤는 행동 기반, 건강 표시는 모음 탭 타일 담당(범위 못 박기). -- **위젯 공통**: ⓐ갱신 경로 신설 — DataChange.commit 외에 백그라운드 딜리버리→캐시 갱신→reloadAllTimelines(주기 폴링 아님, §10 예산 전략과 충돌 없음. 신선도=시간 단위 감수 §3.1) ⓑ하루 경계는 기존 타임라인 안전망으로 새 날 0 리셋 자동 ⓒ**데이터 없는 기기(맥 데스크톱 위젯·건강 미동기화 아이패드)**: 건강 다짐 셀을 '수행일 아님' 문법 재사용(② 대시·③ 문구·④ 흐림)으로 '데이터 없음' 표시 + **combinedSpanRatio 모수에서 제외**(§4.3 하루 span 선례와 동일 문법) ⏳확정 대기 ⓓ③④ 슬롯 픽커에 건강 다짐 표시명 노출, 과금은 위젯=프리미엄이라 자연 정합. -- **파생 결정 2건**: ⓔ건강 다짐 v1 **마감 시각 옵션 미지원(숨김)** 추천 — 캐시가 하루 단위 값이라 부분 창은 시간대 캐시가 따로 필요, 실익 대비 과함(수면은 자체 구간 보유. §3.4의 "마감 적용 가능" 표기는 이 결정으로 대체) ⏳확정 대기 ⓕ**판정 보류 규칙(중요)**: 건강 다짐 포함 목표의 자동 판정(evaluateIfEnded)은 건강 데이터 가용 기기에서만 실행 — 불가 기기(맥 등)에선 보류해 다음 가용 기기 실행 때 판정(빈 캐시로 미달성 오판→CloudKit 전파 방지) ⏳확정 대기 +- **위젯 공통**: ⓐ갱신 경로 신설 — 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. 도움말 스크린샷 재촬영 범위 -4. §8 ③ 처리 — 건강 다짐 셀=꼬리표 다짐과 동일한 표시 전용(탭=앱 열기) 상속 -5. §8 ⓒⓕ — 데이터 없는 기기에서 건강 다짐 모수 제외 + 자동 판정 보류 규칙 -6. §8 ⓔ — 건강 다짐 v1 마감 시각 옵션 미지원(숨김) +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) + +### 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) 동반 제출