feat(flow): focus session api v2 웹 계약 전환

This commit is contained in:
2026-03-16 17:30:52 +09:00
parent f4910238a0
commit 38abc1e0c7
30 changed files with 390 additions and 702 deletions

View File

@@ -12,7 +12,7 @@ Last Updated: 2026-03-16
- no-session `/app``goal + duration + atmosphere` 중심의 premium entry shell로 교체했다
- `microStep` 입력은 entry에서 제거했고, `예상 시간(분)` 입력과 12개 dummy atmosphere grid를 추가했다
- atmosphere는 `scene + sound`가 함께 묶인 선택 단위로 동작하며, 선택한 atmosphere가 `/app` 배경과 `/space` start payload에 같이 반영된다
- custom duration server contract 전까지는 입력한 분 값을 가장 가까운 기본 리듬(`25/5`, `50/10`, `90/20`)으로 매핑한
- 입력한 duration은 raw `focusDurationMinutes`로 server에 전달된
- weekly review entry는 main CTA를 먹지 않도록 no-session shell의 quiet secondary dock 위치로 이동했다
- `/app` Atmosphere Entry Shell visual premium polish:
- no-session shell을 `decision rail + selected atmosphere stage + curated atmosphere library` 구조로 다시 짰다
@@ -142,17 +142,13 @@ Last Updated: 2026-03-16
- current session이 없고 최근 7일 데이터가 충분할 때 `/app`의 quiet secondary review dock에서 `Weekly Review` entry를 노출한다
- current session이 있으면 `/app` 자체가 `/space`로 이동하므로, `/app` review entry는 no-session entry shell 안에서만 다룬다
- `/stats -> /app` handoff의 2차 연결:
- `/stats` 마지막 CTA는 `/app?review=weekly&carryHint=...&entryPreset=forest-50-10`으로 연결된다
- `/stats` 마지막 CTA는 `/app?review=weekly&carryHint=...&entryAtmosphereId=forest-draft&entryDurationMinutes=50`으로 연결된다
- `/app`은 이 query를 받아 entry stage 위의 review-aware return hint를 노출한다
- goal과 duration은 자동 입력하지 않고, 방향만 가볍게 제안한다
- Pro personalized handoff 3차 연결:
- Pro에서는 `/stats` carry-forward 섹션에 추천 ritual을 함께 보여준다
- `/stats` 마지막 CTA 카피가 generic start가 아니라 `가장 잘 맞은 ritual로 /app 돌아가기`로 바뀐다
- `/stats` 마지막 CTA 카피가 generic start가 아니라 `가장 잘 맞은 atmosphere로 /app 돌아가기`로 바뀐다
- `/app` teaser와 review return hint도 Pro에서 더 구체적인 next-session handoff 톤으로 표시된다
- `/space` secondary review teaser 4차 연결:
- goal complete로 setup 상태로 돌아왔을 때만 setup drawer 아래에 low-emphasis review teaser가 보인다
- teaser는 `주간 review 보기``/stats`를 열고, 방금 끝낸 흐름 반영을 과장하지 않는 카피만 사용한다
- 다시 시작하거나 dismiss하면 사라지며, live execution 중에는 보이지 않는다
- `Weekly Review` recovery의 서버 연결:
- server `focus-summary` 응답에 `recovery`가 추가됐다
- `pause_count / resume_count` 기반 `pause 뒤 복귀`를 실제 수치로 보여준다
@@ -184,7 +180,6 @@ Last Updated: 2026-03-16
- HUD 내부 status line을 제거하고 상단 중앙 고정 토스트로 통합
- Notes 저장/Undo, Goal 전환, 잠금 안내 피드백이 동일 위치에서 노출
- Free 코어 루프 개방:
- Quick Controls Time의 `90/20` 잠금을 제거
- 기본 Sound 잠금 제거로 Free에서도 기본 3~6 프리셋 선택 가능
- Pro 가치 재배치:
- Pro 잠금 대상을 `Daily Focus Plan / Rituals / Weekly Review`로 재정의
@@ -210,11 +205,11 @@ Last Updated: 2026-03-16
- 모드 설명 1줄(기본: 모든 컨트롤 표시, 몰입: 필수만 남기고 숨김) 추가
- 모드 상태를 workspace -> tools-dock -> focus-hud 경로로 연결해 HUD 톤 반영 유지
- `/space` Scene 기반 자동 추천 적용:
- `RoomTheme``recommendedSoundPresetId`, `recommendedTimerPresetId` 필드 추가
- 첫 진입/시작 시 Scene 추천 타이머/사운드가 자동 반영되도록 초기화 로직 정리
- Scene 변경 시 `override.sound/timer``false`인 항목만 자동 동기화
- `RoomTheme``recommendedSoundPresetId` 필드 추가
- 첫 진입/시작 시 Scene 추천 사운드와 atmosphere 기반 duration이 자동 반영되도록 초기화 로직 정리
- Scene 변경 시 `override.sound/duration``false`인 항목만 자동 동기화
- `/space` 사용자 override 존중 규칙 도입:
- `override.sound`, `override.timer` UI 상태 추가
- `override.sound`, `override.duration` UI 상태 추가
- 사용자가 직접 고른 항목은 이후 Scene 변경에도 자동 덮어쓰기되지 않도록 반영
- `추천으로 되돌리기(더미)` 액션으로 override 초기화 + 추천값 즉시 복원 지원
- `Control Center`를 Scene/Time 중심으로 단순화:
@@ -224,8 +219,8 @@ Last Updated: 2026-03-16
- 우하단 Sound Quick 경로를 override 적용의 명시적 경로로 분리:
- `onQuickSoundSelect` 콜백으로 연결해 `override.sound` 규칙을 코드 레벨에서 고정
- 세션 상태 더미 저장/복원 추가:
- `sceneId`, `timerPresetId`, `soundPresetId`, `goal`, `override(sound/timer)`를 localStorage에 저장
- 복원 우선순위: 쿼리 파라미터 > 저장 상태 > Scene 추천
- `sceneId`, `durationMinutes`, `soundPresetId`, `goal`, `override(sound/duration)`를 localStorage에 저장
- 복원 우선순위: 저장 상태 > 사용자 기본 설정 > atmosphere 추천
- `/space` 진입 Resume CTA 추가:
- 저장된 목표가 있고 쿼리 오버라이드가 없을 때 `지난 한 조각 이어서` 블록 1회 노출
- `이어서 시작`: 저장 목표로 즉시 Focus 진입

View File

@@ -10,9 +10,9 @@ Last Updated: 2026-03-15
관련 문서:
- `./19_app_atmosphere_entry_spec.md`
- `../../screens/app/current/19_app_atmosphere_entry_spec.md`
- `../../product/12_core_loop_execution_roadmap.md`
- `../stats/14_weekly_review_reframe_spec.md`
- `../../screens/stats/current/14_weekly_review_reframe_spec.md`
- `../../product_principles.md`
- `../../current_context.md`
@@ -237,7 +237,7 @@ review의 마지막 CTA는 아래 중 하나여야 한다.
추천:
- CTA를 `/app?review=weekly&preset=...` 같은 방식으로 연결
- CTA를 `/app?review=weekly&entryAtmosphereId=...&entryDurationMinutes=...` 같은 방식으로 연결
- 최소한 query 또는 client state로 ritual/context를 넘긴다
중요:
@@ -267,7 +267,7 @@ review-aware state가 된다.
예시:
- `이번 주에 가장 잘 맞았던 흐름 · Forest · 50/10`
- `이번 주에 가장 잘 맞았던 흐름 · Forest Draft · 50`
- `이번엔 시작을 더 작게 잡아보세요`
### 유지할 것
@@ -300,9 +300,9 @@ review-aware state가 된다.
### Pro
- teaser가 더 구체적일 수 있다
- `Forest · 50/10에서 pause 뒤 복귀율이 가장 높았어요`
- `Forest Draft · 50에서 pause 뒤 복귀율이 가장 높았어요`
- `/stats` 마지막 CTA가 더 개인화된다
- `가장 잘 맞은 ritual로 /app 돌아가기`
- `가장 잘 맞은 atmosphere로 /app 돌아가기`
- `/app` 복귀 후 ritual prefill / carry-forward hint가 더 정교하다
핵심:
@@ -399,7 +399,8 @@ review-aware state가 된다.
추천 query:
- `review=weekly`
- `entryPreset=forest-50-10`
- `entryAtmosphereId=forest-draft`
- `entryDurationMinutes=50`
- `carryHint=start-smaller`
주의:
@@ -412,7 +413,8 @@ review-aware state가 된다.
로컬 상태:
- `reviewSource`
- `suggestedEntryPreset`
- `suggestedEntryAtmosphereId`
- `suggestedEntryDurationMinutes`
- `carryForwardHint`
---

View File

@@ -61,7 +61,7 @@ Last Updated: 2026-03-15
| ALN-001 | P1 | `/space` Goal Complete / Break semantics | `잠깐 쉬기`는 블록을 닫고 break로 넘어가는 것처럼 읽힘 | 실제로는 overlay만 닫고 reminder만 예약되어 break 의미가 깨졌음 | `src/widgets/space-focus-hud/ui/SpaceFocusHudWidget.tsx`, `src/shared/i18n/messages/space.ts` | fixed-awaiting-browser | `잠시 비우기 -> pause + reminder`가 실제 체감상도 맞는지 브라우저 확인 |
| ALN-002 | P1 | `/app` Weekly Review primary entry | `/app`이 Weekly Review의 primary entry라고 정의됨 | current session이 있으면 review entry가 완전히 사라져 primary entry가 끊겼음 | `src/widgets/focus-dashboard/ui/FocusDashboardWidget.tsx`, `docs/flows/current/15_app_stats_entry_flow_spec.md` | fixed-awaiting-browser | resume 상태에서 review entry 발견성과 우선순위 확인 |
| ALN-003 | P2 | `/space` secondary review teaser | `방금 끝낸 흐름까지 review에 담아둘까요?`처럼 read-after-write를 약속했음 | 실제로는 generic `/stats`만 열고, 방금 끝낸 흐름을 별도 handoff하지 않았음 | `src/shared/i18n/messages/space.ts`, `src/widgets/space-workspace/ui/SpaceWorkspaceWidget.tsx` | fixed-awaiting-browser | setup drawer teaser가 과장 없이 자연스럽게 읽히는지 확인 |
| ALN-004 | P1 | Pro personalized handoff | `/stats`에서 추천 ritual로 돌아간다고 말했음 | 실제로는 `/app` 문구만 바뀌고 start behavior는 기본 ritual 그대로였음 | `src/widgets/focus-dashboard/ui/FocusDashboardWidget.tsx`, `src/shared/i18n/messages/app.ts` | fixed-awaiting-browser | `entryPreset` 실제 scene/sound/timer 시작값으로 적용되는지 검증 |
| ALN-004 | P1 | Pro personalized handoff | `/stats`에서 추천 atmosphere/duration으로 돌아간다고 말했음 | 실제로는 `/app` 문구만 바뀌고 start behavior는 기본 그대로였음 | `src/widgets/focus-dashboard/ui/FocusDashboardWidget.tsx`, `src/shared/i18n/messages/app.ts` | fixed-awaiting-browser | `entryAtmosphereId + entryDurationMinutes` 실제 start 값으로 적용되는지 검증 |
| ALN-005 | P2 | `/space` intent card interaction | rail, edit, expand/collapse의 역할이 분리돼야 함 | goal 클릭과 edit 진입이 섞여 예측 가능성이 낮았음 | `src/widgets/space-focus-hud/ui/IntentCapsule.tsx`, `docs/screens/space/current/13_space_intent_card_collapsed_expanded_spec.md` | fixed-awaiting-browser | desktop/mobile에서 expand와 edit 구분이 분명한지 확인 |
| ALN-006 | P2 | `/space` Goal Complete 2단계 인지 | 1단계 choice와 2단계 next 입력이 명확히 구분돼야 함 | 사용자 입장에서는 `돌아가기 / 다음 목표로 바로 시작` 화면이 top-level 분기처럼 읽히기 쉬움 | `src/widgets/space-focus-hud/ui/GoalCompleteSheet.tsx`, `src/shared/i18n/messages/space.ts` | open | choice view와 next view의 제목, 구조, motion, context label을 더 분리하는 기획 필요 |
| ALN-007 | P2 | Weekly Review discoverability | review는 `/app`의 primary ritual이어야 함 | 데이터 gate와 currentSession 조건에 따라 사용자에게 “아예 없는 기능”처럼 느껴질 수 있음 | `src/widgets/focus-dashboard/ui/FocusDashboardWidget.tsx`, `docs/flows/current/15_app_stats_entry_flow_spec.md` | open | low-data 상태와 resume 상태를 포함한 discoverability 정책 재정의 |

View File

@@ -8,7 +8,9 @@ Last Updated: 2026-03-16
- `Slice 1` no-session shell 구현 완료
- `Slice 1-2` visual premium polish 구현 완료
- `Custom Duration Contract``Weekly Review Dock Reposition`은 다음 slice로 남아 있음
- `Custom Duration Contract` 구현 완료
- `Weekly Review Dock Reposition` 구현 완료
- 다음 slice는 `/space` current-session-only cleanup과 browser QA다
핵심 정책 변경:
@@ -256,7 +258,7 @@ Last Updated: 2026-03-16
### E. Selection Rules
- no-session 상태에서는 atmosphere 1개가 기본 선택된 상태로 시작한다
- review handoff로 들어온 경우에는 handoff preset과 가장 가까운 atmosphere를 preselect한다
- review handoff로 들어온 경우에는 handoff `entryAtmosphereId + entryDurationMinutes`를 preselect한다
- 사용자가 duration을 직접 수정하기 전까지는 선택된 atmosphere의 기본 duration suggestion을 보여줄 수 있다
- 사용자가 duration을 직접 수정한 뒤에는 atmosphere를 바꿔도 duration 값을 덮어쓰지 않는다
@@ -397,31 +399,31 @@ Last Updated: 2026-03-16
---
## 10. Slice 1 구현 원칙
## 10. 구현 상태와 남은 작업
이번 구현 slice는 `/app`**no-session shell**을 먼저 바꾸는 단계다.
현재 `/app`의 no-session shell은 이미 구현되어 있고, focus-session API V2도 함께 연결됐다.
포함:
현재 포함된 범위:
- goal input
- duration input
- 12개 atmosphere grid
- selected atmosphere 기반 background 반영
- quiet review dock의 기본 위치
- raw `focusDurationMinutes` start payload
- review handoff의 `entryAtmosphereId + entryDurationMinutes`
제외:
이번 라운드에서 제외된 것:
- current session routing 재설계
- `/stats` IA 변경
- server custom duration contract
- `/space` current-session-only dead path cleanup
### Slice 1 임시 계약
### 현재 계약
- 사용자는 분 단위 duration을 입력한다
- 하지만 server contract가 아직 preset 기반이면, 이번 slice에서는 **입력 시간에 가장 가까운 기존 focus preset**으로 임시 매핑한
- 이 임시 매핑은 다음 slice(`Custom Duration Contract`)에서 실제 duration 연동으로 대체한
- UI에는 이 상태가 과장 없이 드러나야 한
- 예: `지금은 가장 가까운 기본 리듬으로 먼저 들어가요.`
- server`focusDurationMinutes`를 공식 start 계약으로 받는
- selected atmosphere는 `atmosphereId + sceneId + soundPresetId`로 함께 저장된
- `/space`는 current session 응답의 `focusDurationSeconds`, `atmosphereId`, `sceneId`, `soundPresetId`를 source of truth로 읽는
---
@@ -486,19 +488,10 @@ Last Updated: 2026-03-16
### 필요한 변화
1. `startSession`custom duration minutes를 받도록 확장
2. session에 `focusDurationMinutes` 저장
3. break duration 계산 정책 정의
4. atmosphere 선택 단위를 위한 `sceneId + soundPresetId` 조합 저장
### break duration 정책 제안
- 10~30분: 5분
- 31~60분: 10분
- 61~120분: 15분
- 121분 이상: 20분
이건 사용자가 break를 직접 고르지 않아도 자연스럽게 이어지게 하기 위한 기본 정책이다.
1. `startSession``focusDurationMinutes`를 공식 필드로 받는다
2. session에 `focusDurationSeconds``atmosphereId` 저장한다
3. `GET /focus-sessions/current``/space` hydration에 필요한 goal / duration / atmosphere / scene / sound를 모두 반환한다
4. `/stats -> /app` handoff는 preset이 아니라 atmosphere / duration 힌트를 사용한다
---

View File

@@ -266,7 +266,7 @@ Weekly Review는 `/stats` 안에서 아래 5개 구역으로 재구성한다.
예시:
- `Forest · 50/10에서 가장 오래 이어졌어요.`
- `Forest Draft · 50에서 가장 오래 이어졌어요.`
- `Rain 계열에서는 pause 후 복귀가 더 높았어요.`
중요:
@@ -400,7 +400,7 @@ Free에서 하지 않는 것:
- multi-week trend
- ritual 비교표
- scene/sound/timer 조합 비교
- atmosphere/duration 조합 비교
- archive 기반 long-term pattern
Free 가치:
@@ -471,7 +471,7 @@ trigger:
teaser 예시:
- `이번 주 pause 뒤 복귀가 3번 있었어요`
- `Forest 50/10에서 가장 잘 이어졌어요`
- `Forest Draft 50분에서 가장 잘 이어졌어요`
CTA:
@@ -482,7 +482,7 @@ CTA:
weekly review 마지막 CTA:
- `이 조합으로 다음 세션 시작`
- `/app`으로 연결하되 ritual preset을 prefill
- `/app`으로 연결하되 atmosphere와 duration을 prefill
즉 review는 읽고 끝나는 화면이 아니라 다음 entry에 연결돼야 한다.

View File

@@ -14,10 +14,10 @@ Last Updated: 2026-03-16
## 현재 우선순위
1. `/app` Atmosphere Entry Shell
2. `Custom Duration Contract`
3. `Weekly Review Dock Reposition`
4. `Core Loop Alignment` browser audit
1. `/space` current-session-only cleanup
2. `Core Loop Alignment` browser audit
3. `Weekly Review` carry-forward 고도화
4. `Premium Ambience` polish
## 최근 세션 상태
@@ -30,7 +30,7 @@ Last Updated: 2026-03-16
- no-session 상태는 더 이상 legacy `goal + microStep + fixed ritual` 화면을 쓰지 않는다.
- 현재는 `goal 1개 + 예상 시간(분) + atmosphere 12개 grid + start CTA`로 들어간다.
- 선택한 atmosphere는 `/app` 배경 preview와 `/space` start payload의 `scene/sound`에 같이 반영된다.
- duration은 우선 가장 가까운 기본 리듬으로 매핑하는 임시 계약을 사용한다.
- duration은 raw `focusDurationMinutes`로 server에 전달한다.
- weekly review entry는 right-side quiet dock 위치로 옮겨 main CTA보다 낮은 위계를 유지한다.
- `/app` Atmosphere Entry Shell visual premium polish를 반영했다.
- utility card 묶음 대신 `decision rail + selected atmosphere stage + curated library` 구조로 재구성했다.
@@ -122,10 +122,6 @@ Last Updated: 2026-03-16
- `Weekly Review Entry Flow`의 Pro personalized handoff까지 연결됐다.
- Pro에서는 `/stats` carry-forward에 추천 ritual을 함께 보여준다.
- `/stats` 마지막 CTA와 `/app` teaser / return hint가 더 구체적인 handoff 톤으로 바뀐다.
- `/space` complete 이후 secondary review teaser까지 연결됐다.
- goal complete로 setup 상태로 돌아왔을 때만 setup drawer 아래에 작은 review teaser가 보인다.
- full review 강제 이동 없이 `/stats`를 여는 secondary entry로만 동작한다.
- 방금 끝낸 흐름을 반영한다고 과장하지 않는 카피로 정리했다.
- `Weekly Review` recovery의 서버 연결이 들어갔다.
- server `focus-summary` 응답에 `recovery`가 추가됐다.
- 현재는 `pause 뒤 복귀`만 실집계이며, `자리 비움 뒤 복귀`는 partial note로 남아 있다.
@@ -166,7 +162,6 @@ Last Updated: 2026-03-16
- HUD 내부 status line 제거
- Notes/Goal/잠금 피드백이 동일 위치 토스트로 표시
- 기본 기능 잠금을 해소했다.
- Time `90/20`을 Free로 개방
- 기본 Sound 잠금 제거
- Pro 잠금 구조를 Session OS 중심으로 재구성했다.
- `Daily Focus Plan / Rituals / Weekly Review` 요약 카드 추가
@@ -182,17 +177,17 @@ Last Updated: 2026-03-16
- 옵션: `컨트롤 자동 숨김`
- ON 상태에서 Control Center가 8초 무입력이면 자동 닫힘 처리
- `/space`에 Scene 추천 자동 적용 규칙을 도입했다.
- Room 데이터에 `recommendedSoundPresetId`, `recommendedTimerPresetId`를 추가했다.
- Room 데이터에 `recommendedSoundPresetId`를 추가했다.
- 초기 진입/Scene 변경 시 override가 없는 항목만 추천값으로 자동 반영된다.
- `/space`에 override 상태(`sound`, `timer`)를 추가했다.
- 사용자가 직접 고른 사운드/타이머는 Scene 변경에도 자동 덮어쓰지 않는다.
- `/space`에 override 상태(`sound`, `duration`)를 추가했다.
- 사용자가 직접 고른 사운드/duration은 Scene 변경에도 자동 덮어쓰지 않는다.
- `추천으로 되돌리기(더미)` 액션으로 override 초기화 + 추천값 즉시 복원이 가능하다.
- Control Center를 Scene/Time 중심으로 단순화했다.
- Sound/Preset Packs 섹션 제거
- 추천 정보 1줄 + `추천으로 되돌리기`만 유지
- 우하단 Sound Quick 선택 경로를 `onQuickSoundSelect`로 분리해 override.sound 규칙을 명시했다.
- `/space` 선택 상태 로컬 저장/복원을 추가했다.
- 저장: `sceneId`, `timerPresetId`, `soundPresetId`, `goal`, `override(sound/timer)`
- 저장: `sceneId`, `durationMinutes`, `soundPresetId`, `goal`, `override(sound/duration)`
- 복원 우선순위: 쿼리 파라미터 > 저장 상태 > Scene 추천
- `/space` 진입 시 Resume CTA를 추가했다.
- 저장된 목표가 있고 쿼리 오버라이드가 없으면 `지난 한 조각 이어서`를 1회 노출