- 의도(사용자 TestFlight 피드백): 폰으로 운동해도 워치를 차고 있으면 워치가 심박을 재고, 진동은 시작한 기기에서만. 종전 '워치 연동됨' 배지는 워치 앱 포그라운드 여부(isReachable)만 보여 주던 것이라 폐지 - iOS: WatchHeartRateBridge — 시작 시 HKHealthStore.startWatchApp(폰 설정 운동 유형)으로 워치 앱을 깨우고, 워치가 미러링한 HKWorkoutSession을 workoutSessionMirroringStartHandler로 받아 심박 수신, 완주/중단 명령 전송(finish/discard). 워치를 못 열거나 30초 안에 미러링이 안 붙으면 폰 단독 (+설정에 따라 '워치 앱을 열지 못했어요' 알럿, app.watchWarn 재사용) 및 WatchConnectivity로 워치 세션 폐기 명령. 워치 저장 결과(saved/failed)는 WC로 회신받고 15초 내 미회신이면 폰 사후 저장 폴백. 워치 깨우기는 폰 건강 권한 응답 뒤에(첫 실행 경합 방지). 건강 읽기 권한(심박·활성 에너지) 추가 — 워치 세션 센서 수집용(권한 공유) - 워치: WatchAppDelegate.handle(workoutConfiguration) → MirroredWorkoutSession(라이브 빌더, 무진동·무타이머, 심박을 미러링 채널로 전송, finish 시 저장+강도 relate 후 WC로 결과 통보, discard/끊김 시 폐기, 미러링 30초 타임아웃, 앱 재기동 시 잔류 세션 복구·폐기). 화면 '아이폰에서 진행 중 ♥bpm'(중단 버튼). WatchHealthAuth로 권한 공용화 - UI: 첫 화면 배지·확인 창 제거, 운동 화면 횟수 아래 워치 상태 줄(연결 중/♥bpm/아이폰만), 설정 토글 '워치 연결 실패 경고', 도움말 3건 갱신. l10n 카탈로그 3종 missing/stale 0 - DEBUG: -testConfig(35초 세트), -mockWatchHeartRate <bpm>(상태 줄 QA·스크린샷). watchHR 카테고리 notice 로그 - 시뮬 검증(페어링 심): startWatchApp → 워치 기동·권한·세션·가짜 심박·'아이폰에서 진행 중'까지 동작, 워치 startMirroring 성공 반환 — 그러나 폰 미러링 핸들러는 시뮬에서 불리지 않음(애플 샘플도 실기기 전용) → 30초 타임아웃·알럿·WC 폐기·폰 폴백 저장 경로 확인, 워치 자체 세트 정상. 3타깃 빌드 그린·경고 0. 미러링 수신·완주 저장·회신은 실기기 TestFlight 재테스트 필요 - 문서·마케팅: CLAUDE.md §3.8 신설·§1/§3.7/§4/§6/§7 갱신, 설명 3언어·whats-new·review-notes·PRIVACY.md (아이폰 읽기 권한 설명 — GitHub 게시본 갱신 필요), 스크린샷 01·08(배지 제거)·02·03(♥78 상태 줄) 재촬영·합성 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UPmp29DQHY6Ahfss5SRopT
Marketing — App Store 등록 자료 (케깅)
ASC(App Store Connect) 등록 때 그대로 붙여넣을 자료 모음. 하루 다님 Marketing/ 구성을 그대로 옮겨 왔다.
앱 기능·문구가 바뀌면 이 폴더도 함께 갱신한다 — 특히 description의 기능 목록, 스크린샷에 보이는 화면.
구성
AppStore/
app-name-subtitle.txt 로케일별 이름·부제목 (각 30자 이내)
description-{ko,en,ja}.txt 앱 설명 (4000자 이내) — 로케일별 '설명' 란
keywords.txt 키워드 (로케일별 100자 이내) — '키워드' 란
promotional-text.txt 프로모션 텍스트 (170자 이내, 심사 없이 수정 가능)
whats-new-1.0.txt 버전 1.0 '새로운 기능'
review-notes.txt ASC 입력값(카테고리·URL·연령 등급) + App Review 메모(영문) + 업로드 체크
Screenshots/
iphone-6.9/{ko,en,ja}/ 아이폰 6.9″ 원본 (1320×2868px — iPhone 17 Pro Max 시뮬레이터)
watch/{ko,en,ja}/ 애플워치 원본 (416×496px — Series 11 46mm. 워치 앱이 있는 앱은 워치 스크린샷 필수)
framed-iphone-6.9/… ★ 업로드 대상: 홍보 문구+브랜드 배경 합성판 (같은 캔버스 크기라 ASC에 그대로)
framed-watch/… ★ 업로드 대상: 〃
tools/
frame_screenshots.swift 합성 도구 — `swift Marketing/tools/frame_screenshots.swift` (Keging 폴더에서).
문구·색은 파일 상단에서 수정, 원본을 다시 찍으면 이 도구만 재실행하면 됨
../Docs/PRIVACY.md 개인정보처리방침(ko/en/ja) — GitHub 공개 저장소에 올려 URL로 등록 (아래 ⚠️)
- 아이패드 슬롯 없음(iPhone 전용 앱, TARGETED_DEVICE_FAMILY=1). ASC는 6.9″ 아이폰 + 워치 한 세트씩 필수, 나머지 크기는 자동 축소
- 스크린샷 구성 (1.0, 2026-09-05):
- 아이폰 9장 = 01 첫 화면 / 02 운동 중·수축(워치 심박 줄) / 03 운동 중·이완 / 04 하루 통계(오늘의 타임라인) / 05 주간 통계 / 06 운동 세팅 시트 / 07 다이나믹 아일랜드 확장 뷰(홈 화면에서 길게 누름) / 08 다크 모드 / 09 완료 화면
- 워치 3장 = 01 시작 화면 / 02 운동 중 / 03 세팅 페이지
- 상태바는 9:41·배터리 100%로 오버라이드된 상태로 촬영 (워치 시뮬레이터는 오버라이드 미지원 — 실제 시각 표시)
- 문구 오버레이 규정: Apple은 스크린샷에 마케팅 문구·배경 합성을 허용(실제 앱 화면이 반영되어 있으면 됨) — framed 세트는 이 관행을 따른 것
- ⚠️ 개인정보처리방침 URL은 하루 다님과 같은 방식 — GitHub에
PRIVACY.md하나만 든 공개 저장소(notalentprogrammer/Keging)를 만들고Docs/PRIVACY.md를 올린다(저장소 생성은 사용자 계정으로). URL이 달라지면 description 3종·review-notes의 링크를 함께 고칠 것
스크린샷 재생성 방법
케깅은 데모 시드가 통계뿐(-seedStats)이라 로케일마다 앱을 지울 필요는 없고, 실행마다 -AppleLanguages "(xx)" -AppleLocale xx_XX만 바꾸면 된다.
촬영 스크립트 원본은 세션 스크래치에 있었으므로 아래 요령을 기준으로 재작성한다.
# 0) Debug 빌드 후 앱 경로 (Keging 스킴이 워치 앱까지 빌드·내장)
DD=$(ls -dt ~/Library/Developer/Xcode/DerivedData/Keging-* | head -1)
APP=$DD/Build/Products/Debug-iphonesimulator/Keging.app
PHONE=9142EFF2-892B-4C87-B5A2-937527A3E3A2 # iPhone 17 Pro Max (iOS 26.5) — 마케팅용
WATCH=B3B2F7F0-0414-4170-834B-E820BC4F2595 # Apple Watch Series 11 46mm (watchOS 26.5) — PHONE과 페어링됨(simctl pair)
# 1) 부팅 (시간대 주입 — 아래 '시간대 정합') + 상태바 오버라이드
SIMCTL_CHILD_TZ=Pacific/Auckland xcrun simctl boot $PHONE
xcrun simctl status_bar $PHONE override --time "9:41" --batteryState charged --batteryLevel 100 --wifiBars 3 --cellularBars 4
SIMCTL_CHILD_TZ=Pacific/Auckland xcrun simctl boot $WATCH
# 2) 설치 — 워치 앱은 페어링돼 있어도 자동 설치되지 않으므로 내장 번들을 직접 설치
xcrun simctl install $PHONE "$APP"
xcrun simctl install $WATCH "$APP/Watch/KegingWatch Watch App.app"
# 3) 화면별 런치 인자 (매 실행 공통: -noHealth -AppleLanguages "(ko)" -AppleLocale ko_KR / en en_US / ja ja_JP)
# ★ 폰 첫 화면의 '워치 연결됨' 배지는 워치 시뮬에서 케깅 워치 앱이 포그라운드일 때만 뜬다 — 01·08 촬영 직전에 워치 앱을 launch
# 01-main : -resetConfig (기본 세팅 10·5·20 — 9차부터 워치 배지 없음)
# 09-finished : -quickConfig -autoStart → 8초 뒤 (완주 화면. 다음 실행에 -resetConfig 필수)
# 06-setup : -resetConfig -openTimerSettings
# 02-workout : -autoStart -mockWatchHeartRate 78 → 약 36초 뒤 (3회차 수축, 7초 남음) / 03-relax: 같은 실행 약 45초 뒤 (3회차 이완)
# (-mockWatchHeartRate = 워치 없이 '♥78 워치 심박' 상태 줄을 흉내 — 실제 미러링은 시뮬 미지원)
# 08-dark : simctl ui $PHONE appearance dark → 기본 실행 → 촬영 → appearance light
# 05-stats-week : -seedStats -openStats -statsScope week
# 04-stats-day : -seedStats -openStats ← ⚠️ '시간대 정합' 2단계 부팅 후 촬영
# 07-dynamic-island : -autoStart 로 운동 중 → Device > Home → 아일랜드 길게 누름(확장 뷰) → 촬영 (아래 '다이나믹 아일랜드')
# 워치 01-main: 기본 / 03-settings: -openSettings / 02-workout: -autoStart → 약 36초 뒤
# 4) 합성: swift Marketing/tools/frame_screenshots.swift
- ⚠️
simctl io screenshot은 기존 파일을 덮어쓰지 않음 — 재촬영 전 rm 필수 - ⚠️
simctl launch는 실행 중인 앱을 재시작하지 않는다 — 매번simctl terminate후 launch (DEBUG 인자는 콜드 스타트에서만 읽음)
시간대 정합 (상태바 9:41 ↔ 앱 안의 시각)
하루 다님 요령 계승: 부팅 시 SIMCTL_CHILD_TZ=<IANA id>로 주입해야 전 프로세스에 적용된다(launch 시점 주입은 유실됨).
- 일반 화면(01
03·0509): "지금이 오전 9시대"인 시간대 — 2026-09-05 새벽(KST 0506시) 촬영은09시대)Pacific/Auckland(UTC+12 → 08 - 하루 탭(04)만 2단계 부팅:
-seedStats의 오늘 세션이 08:00·13:17·21:34 고정이고 타임라인은 '지금' 뒤의 세션도 그리므로, "지금"이 21:34 이후(밤)인 시간대로 폰을 재부팅해 찍는다(같은 시각 KST 새벽이면Europe/London(UTC+1) → 22시대). 이때 상태바는--time "10:41"로 바꿔 '지금' 룰과 어긋나지 않게(자정을 넘기면 오늘 기록이 사라지니 23시대는 피할 것)
다이나믹 아일랜드 확장 뷰 (07) — Simulator.app 창을 마우스로 조작
simctl에는 터치 주입이 없다. open -a Simulator로 창을 띄운 뒤 AppleScript(System Events)로 Device 메뉴를 클릭하고,
CGEvent로 마우스 클릭·길게 누름을 보낸다(세션 스크래치의 mouse/longpress 스위프트 헬퍼 — 재작성 요령: CGEvent(mouseEventSource:mouseType:mouseCursorPosition:mouseButton:)로 down/up 게시).
- 창 좌표 매핑: Window > Show Device Bezels 끄기 + Window > Pixel Accurate → 창 position/size를 AppleScript로 읽는다(2026-09-05: position {1033,31}, size {625,1409}, 1x 디스플레이).
스크린샷 px → 맥 pt:
x = 1033 + px × (625/1320),y = 31 + 51(툴바) + py × (625/1320). 케깅 아이콘 클릭으로 검증 후 사용 - 절차:
-autoStart→ 20초 → Device > Home(메뉴 클릭) → 아일랜드 중앙(px 660,110 → 맥 1345.5,134)을 1.2초 길게 누름 → 확장 뷰 촬영 → 아일랜드 탭으로 앱 복귀 - ⚠️ 잠금화면(Device > Lock)은 시뮬이 항상 켜짐(AOD) 형태로 그려 Live Activity의 초 단위가 "3:——"로 나와 스토어용 부적합 — 첫 잠금 때 "실시간 현황 허용" 물음창이 뜨므로(허용 버튼 클릭 필요) 굳이 잠금화면을 찍을 땐 참고
- 홈 화면 컴팩트 아일랜드(두 색 점+남은 시간)는 정상 렌더 — 필요하면 Home 직후 촬영
워치 상태바의 빨간 '아이폰 연결 끊김' 아이콘 (실측 2026-09-05)
- 비페어링 워치를 새로 부팅하면 앱 화면 상태바가 깨끗하지만, 워치에서 운동을 한 번 시작하면(HKWorkoutSession/런타임 세션) 그 순간부터 아이콘이 붙고 재부팅 전엔 사라지지 않는다. 페어링 워치는 폰이 켜져 있어도 처음부터 붙어 있었다
- 그래서 01·03(시작 화면·세팅)은 로케일마다 워치를 재부팅한 직후(부팅 완료 + 12초 → 01 → 03) 찍고, 02(운동 중)는 아이콘이 붙은 채 찍은 뒤
python3 Marketing/tools/clean_watch_statusbar.py Marketing/Screenshots/watch/*/02-workout.png로 상태바 아이콘만 배경색으로 지운다(실기기에선 실제로 끊겼을 때만 뜨는 시뮬 잔재 — 앱 내용은 무수정). 검출은 상태바 우상단 빨간 픽셀 수(도구 내부) -AppleLanguages런치 인자로 워치 앱 문구는 바뀌지만 워치 상태바 시각은 실제 시각(오버라이드 불가)
Live Activity(아일랜드)는 시스템 언어를 따른다
위젯 확장은 앱의 -AppleLanguages 인자를 받지 않으므로 en/ja 07 컷은 시뮬 시스템 언어를 바꿔 재부팅 후 찍는다:
xcrun simctl spawn $PHONE defaults write "Apple Global Domain" AppleLanguages -array en + AppleLocale -string en_US → shutdown/boot(TZ 주입) → 부팅 완료 후 25초 대기 → 상태바 오버라이드 → 앱을 한 번 워밍업 실행(5초)·종료 → -autoStart 콜드 스타트 → 18초 → Home → 길게 누름 → 촬영. 끝나면 ko로 복원. 홈 화면 앱 라벨도 함께 바뀐다.
⚠️ 부팅 직후(8초) 바로 -autoStart하면 Live Activity가 등록되지 않아 아일랜드가 비어 있었다(2026-09-05 실측) — 대기·워밍업이 필요
출시 절차 체크리스트 (케깅 — 무료·인앱 없음·CloudKit 없음)
하루 다님 README §①~⑪에서 케깅에 해당하는 것만. ⏳ = 처리 대기. 금액·세무가 걸린 내용은 ASC 안내문으로 최종 확인 권장.
① 계약
- 무료 앱이라 유료 앱 계약 불필요 — ASC → 비즈니스에서 무료 앱 계약(Free Apps) 활성 상태만 확인 (하루 다님 출시로 이미 활성)
② 개인정보처리방침 공개 (앱 생성 전)
- GitHub에 공개 저장소
notalentprogrammer/Keging생성 →Docs/PRIVACY.md를PRIVACY.md로 올림 →https://github.com/notalentprogrammer/Keging/blob/main/PRIVACY.md열리는지 확인
③ ASC 앱 생성 · 앱 정보 (review-notes.txt에 입력값 정리)
- 신규 앱: iOS / 이름
케깅 - 케겔 운동 타이머/ 기본 언어 한국어 / 번들 IDcom.yechan.Keging/ SKUkeging-ios - 카테고리 건강 및 피트니스 / 연령 등급 설문 전부 없음 → 4+ / 개인정보 URL·지원 URL 입력 / 현지화 en·ja 추가(이름·부제목은 app-name-subtitle.txt)
- 앱 개인정보 보호: 데이터 수집 안 함 → 게시 / 가격: 무료, 국가 전체
④ 버전 1.0 페이지 (ko/en/ja 전환하며 입력)
- 스크린샷: iPhone 6.9″ =
framed-iphone-6.9/<언어>/01~09/ Apple Watch =framed-watch/<언어>/01~03 - 프로모션 텍스트 / 설명 / 키워드 / 새로운 기능(whats-new-1.0) / 지원 URL
- App Review 정보: 로그인 필요 없음 + 연락처 + 메모(review-notes.txt 영문 그대로 — HealthKit·백그라운드 오디오·워치 설명)
- 출시 방식: 자동 또는 수동
⑤ 아카이브 → 업로드 → TestFlight (⏳ 처리 10~60분)
- 세 타깃 버전·빌드 일치(1.0/1) 확인 → 스킴 Keging + Any iOS Device → Archive → Distribute → Upload
- 수출 규정 질문에 '아니요'(표준 암호화만)
- TestFlight 내부 테스트: 진동 3종·완료 진동·백그라운드 진동·DI/잠금화면·워치 기록 합류·건강 기록
⑥ 심사 제출 (⏳ 보통 24~48시간)
- 빌드 선택 → 제출. 거절 시 해결 센터 — 예상 쟁점: 백그라운드 오디오 모드(2.5.4) 용도 소명(review-notes 메모), HealthKit 용도 문구(Info.plist 3언어 등록됨)
⑦ 승인 → 출시 → 직후
- 스토어 다운로드로 첫 실행·워치 앱 설치·건강 기록 확인
- CLAUDE.md §1 현재 상태·§8에 출시 완료 반영