diff --git a/docs/12_core_loop_execution_roadmap.md b/docs/12_core_loop_execution_roadmap.md index 69c8c31..d877c12 100644 --- a/docs/12_core_loop_execution_roadmap.md +++ b/docs/12_core_loop_execution_roadmap.md @@ -328,7 +328,10 @@ Away / Return이 끼어들기 전, 다음으로 예정된 축은 아래 두 가 - `Weekly Review Entry Flow` Slice 2 - `/stats` 마지막 CTA가 `/app?review=weekly&carryHint=...` handoff로 연결 - `/app`은 review-aware return hint를 먼저 보여주고, goal 입력은 그대로 사용자가 결정한다 - - 다음 구현은 Pro personalized handoff +- `Weekly Review Entry Flow` Slice 3 + - Pro에서는 `/stats` carry-forward에 추천 ritual을 함께 보여준다 + - `/stats` 마지막 CTA와 `/app` return hint가 더 구체적인 next-session handoff로 바뀐다 + - 다음 구현은 `/space` secondary review teaser --- diff --git a/docs/90_current_state.md b/docs/90_current_state.md index f9fa614..9cc55a8 100644 --- a/docs/90_current_state.md +++ b/docs/90_current_state.md @@ -121,6 +121,10 @@ Last Updated: 2026-03-14 - `/stats` 마지막 CTA는 `/app?review=weekly&carryHint=...&entryPreset=forest-50-10`으로 연결된다 - `/app`은 이 query를 받아 hero 위에 review-aware return hint를 노출한다 - goal과 microStep은 자동 입력하지 않고, 방향만 가볍게 제안한다 +- Pro personalized handoff 3차 연결: + - Pro에서는 `/stats` carry-forward 섹션에 추천 ritual을 함께 보여준다 + - `/stats` 마지막 CTA 카피가 generic start가 아니라 `가장 잘 맞은 ritual로 /app 돌아가기`로 바뀐다 + - `/app` teaser와 review return hint도 Pro에서 더 구체적인 next-session handoff 톤으로 표시된다 - paywall / plan / landing 메시지 재정렬: - paywall 가치 포인트를 multi-queue, rituals, weekly review 중심으로 재작성 - landing pricing에서 구현되지 않은 1:1 매칭 / 오픈 코워킹 / 팀 대시보드를 메인 판매 포인트에서 제거 diff --git a/docs/session_brief.md b/docs/session_brief.md index 78ac0bf..445f779 100644 --- a/docs/session_brief.md +++ b/docs/session_brief.md @@ -89,7 +89,10 @@ Last Updated: 2026-03-14 - `/stats` 마지막 CTA의 `/app` return handoff가 연결됐다. - carry-forward CTA는 `/app?review=weekly&carryHint=...`로 돌아온다. - `/app`은 review-aware return hint를 먼저 보여주되, goal은 사용자가 직접 입력하게 유지한다. - - 다음 구현은 Pro personalized handoff다. +- `Weekly Review Entry Flow`의 Pro personalized handoff까지 연결됐다. + - Pro에서는 `/stats` carry-forward에 추천 ritual을 함께 보여준다. + - `/stats` 마지막 CTA와 `/app` teaser / return hint가 더 구체적인 handoff 톤으로 바뀐다. + - 다음 구현은 `/space` complete 이후 secondary review teaser다. - 유료화 포지셔닝을 `Calm Session OS`로 재정의했다. - Free는 기본 집중 시작, Pro는 더 잘 이어가기라는 메시지로 정리했다. - old `Scene Packs / Sound Packs / Profiles` 중심 카피를 `Daily plan / Rituals / Weekly review` 구조로 교체했다. diff --git a/docs/work.md b/docs/work.md index c2c6c2a..3341bed 100644 --- a/docs/work.md +++ b/docs/work.md @@ -110,7 +110,8 @@ - Slice 1 완료: `/app` hero 아래 low-emphasis weekly review teaser 추가 - Slice 2 완료: `/stats` 마지막 CTA가 `/app?review=weekly&carryHint=...` handoff로 연결 - `/app`은 query를 받아 review-aware return hint를 먼저 보여준다 - - 다음 slice: Pro personalized handoff + - Slice 3 완료: Pro에서 추천 ritual과 더 구체적인 CTA / return hint가 연결된다 + - 다음 slice: `/space` complete 이후 secondary review teaser - 검증: - `/app -> /stats -> /app` 실제 브라우저 플로우 확인 - hero와 teaser의 시각 우선순위 확인 diff --git a/src/features/stats/model/useFocusStats.ts b/src/features/stats/model/useFocusStats.ts index a068017..5c0eca1 100644 --- a/src/features/stats/model/useFocusStats.ts +++ b/src/features/stats/model/useFocusStats.ts @@ -80,6 +80,8 @@ export interface WeeklyReviewViewModel { completionQuality: WeeklyReviewSection; carryForward: { hintKey: ReviewCarryHint; + presetId: string; + presetLabel: string; keepDoing: string; tryNext: string; ctaLabel: string; @@ -176,6 +178,8 @@ const buildCarryForward = (summary: FocusStatsSummary): WeeklyReviewViewModel['c return { hintKey, + presetId: 'forest-50-10', + presetLabel: 'Forest · 50/10 · Forest Birds', keepDoing, tryNext, ctaLabel: copy.stats.reviewCarryCta, diff --git a/src/shared/i18n/messages/app.ts b/src/shared/i18n/messages/app.ts index 93407b6..a74a35a 100644 --- a/src/shared/i18n/messages/app.ts +++ b/src/shared/i18n/messages/app.ts @@ -73,8 +73,10 @@ export const app = { reviewCarryTryClosure: '시작은 있었지만 마무리가 약했어요. 다음 주에는 완료 직전에 다른 블록으로 넘어가지 않는 흐름을 한 번 만들어 보세요.', reviewCarryTryStart: '시작 횟수가 적었어요. 다음 주에는 길이를 늘리기보다 첫 세션을 한 번 더 여는 것에 집중해 보세요.', reviewCarryCta: '이 흐름으로 다음 세션 시작', + reviewCarryCtaPro: '가장 잘 맞은 ritual로 /app 돌아가기', reviewCarryKeepTitle: '다음 주에 유지할 것', reviewCarryTryTitle: '다음 주에 바꿔볼 것', + reviewCarryPresetLabel: '추천 ritual', today: '오늘', last7Days: '최근 7일', chartTitle: '집중 흐름 그래프', diff --git a/src/widgets/focus-dashboard/ui/FocusDashboardWidget.tsx b/src/widgets/focus-dashboard/ui/FocusDashboardWidget.tsx index ee39df4..da0b5ad 100644 --- a/src/widgets/focus-dashboard/ui/FocusDashboardWidget.tsx +++ b/src/widgets/focus-dashboard/ui/FocusDashboardWidget.tsx @@ -42,6 +42,9 @@ const entryCopy = { reviewTitle: '이번 주 review를 잠깐 보고 갈까요?', reviewCta: '주간 review 보기', reviewHelper: '다음 세션 전에 가볍게 보고 갈 수 있어요.', + reviewTitlePro: '나에게 잘 맞았던 흐름을 다시 보고 갈까요?', + reviewCtaPro: '나에게 맞는 흐름 보기', + reviewHelperPro: '가장 잘 맞았던 ritual과 carry-forward를 보고 돌아올 수 있어요.', reviewReturnEyebrow: '방금 본 review 기준', reviewReturnTitleSteady: '이번 주에 잘 맞았던 흐름을 그대로 가져가 보세요.', reviewReturnTitleSmaller: '이번엔 목표를 더 작게 잡아보세요.', @@ -148,7 +151,11 @@ export const FocusDashboardWidget = () => { const reviewReturnCopy = normalizedReviewCarryHint !== null ? reviewCarryCopyByHint[normalizedReviewCarryHint] : null; const reviewReturnRitualLabel = - reviewEntryPreset === 'forest-50-10' ? entryCopy.reviewReturnRitualLabel : null; + isPro && reviewEntryPreset === 'forest-50-10' ? entryCopy.reviewReturnRitualLabel : null; + const reviewTeaserTitle = isPro ? entryCopy.reviewTitlePro : entryCopy.reviewTitle; + const reviewTeaserSummary = isPro ? review.carryForward.keepDoing : review.snapshotSummary; + const reviewTeaserHelper = isPro ? entryCopy.reviewHelperPro : entryCopy.reviewHelper; + const reviewTeaserCta = isPro ? entryCopy.reviewCtaPro : entryCopy.reviewCta; useEffect(() => { let cancelled = false; @@ -417,15 +424,15 @@ export const FocusDashboardWidget = () => { {entryCopy.reviewEyebrow}

- {entryCopy.reviewTitle} + {reviewTeaserTitle}

- {review.snapshotSummary} + {reviewTeaserSummary}

-

{entryCopy.reviewHelper}

+

{reviewTeaserHelper}

- {entryCopy.reviewCta} + {reviewTeaserCta} diff --git a/src/widgets/stats-overview/ui/StatsOverviewWidget.tsx b/src/widgets/stats-overview/ui/StatsOverviewWidget.tsx index 70d14e7..dc692ce 100644 --- a/src/widgets/stats-overview/ui/StatsOverviewWidget.tsx +++ b/src/widgets/stats-overview/ui/StatsOverviewWidget.tsx @@ -1,6 +1,7 @@ 'use client'; import Link from 'next/link'; +import { usePlanTier } from '@/entities/plan'; import { useFocusStats } from '@/features/stats'; import { copy } from '@/shared/i18n'; import { cn } from '@/shared/lib/cn'; @@ -79,7 +80,9 @@ const ReviewSection = ({ export const StatsOverviewWidget = () => { const { stats } = copy; + const { isPro } = usePlanTier(); const { review, isLoading, error, source, refetch } = useFocusStats(); + const carryForwardCtaLabel = isPro ? stats.reviewCarryCtaPro : review.carryForward.ctaLabel; return (
@@ -193,11 +196,22 @@ export const StatsOverviewWidget = () => {

+ {isPro ? ( +
+

+ {stats.reviewCarryPresetLabel} +

+

+ {review.carryForward.presetLabel} +

+
+ ) : null} + - {review.carryForward.ctaLabel} + {carryForwardCtaLabel}