feat(retention): 코호트 기반 리텐션 대시보드 구현 - #71
Conversation
-PostHog HogQL로 12주(person_id, week) 데이터를 조회, - JS 순수 함수로 코호트 행렬과 잔존율 계산 - KPI 4개, 콤보 차트, 반원 파이, GA(Google Analytics) 스타일 히트맵으로 시각화 Resolves: #68 See also: None
|
Important Review skippedAuto incremental reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthrough
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (2)
src/entities/event/model/retention.test.ts (1)
1-1: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winexport된 날짜 포맷터에도 테스트를 추가해 주세요.
formatWeekRange,formatShortDate,formatWeekOfMonth는 export된 유틸 함수인데 검증이 빠져 있습니다. 특히formatWeekRange의 월 경계(예:"2026-06-29"→"6/29 ~ 7/5")와formatWeekOfMonth의 주차 계산은 회귀가 생기기 쉬운 지점이라 케이스로 고정해 두면 좋습니다.As per coding guidelines: "Test business logic in utility functions".
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/entities/event/model/retention.test.ts` at line 1, Add coverage in retention.test for the exported date-formatting utilities in retention, especially formatWeekRange, formatShortDate, and formatWeekOfMonth. Extend the existing test file to import these symbols and add focused cases for week-range formatting across a month boundary such as 2026-06-29 to 6/29 ~ 7/5, plus week-of-month calculations that verify the correct ordinal week is returned. Keep the tests aligned with the current behavior of buildRetentionResponse and addWeeks while locking the utility outputs to prevent regressions.Source: Coding guidelines
src/entities/event/model/retention.ts (1)
73-106: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value윈도우 경계 코호트의 "신규" 과대계상에 유의하세요.
84일 범위만 조회하므로, 윈도우 시작 이전부터 활동하던 사용자도 "윈도우 내 첫 방문 주"를 코호트 진입 주차로 잡습니다(
firstWeek = [...weeks].sort()[0]). 그 결과 가장 오래된 쪽 코호트는 실제로는 재방문자인데 신규로 분류되어 코호트 크기가 부풀고 잔존율 해석이 왜곡될 수 있습니다.데이터 파이프라인 한계상 즉시 고칠 필요는 없지만, 대시보드에 "최근 N주 코호트만 신뢰" 같은 가이드 문구를 추가하거나 경계 코호트를 별도 표기하는 방안을 고려해 보세요. 코호트 분석의 left-censoring 개념을 함께 살펴보면 도움이 됩니다.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/entities/event/model/retention.ts` around lines 73 - 106, In retention.ts, the cohort-building logic around sortedCohortWeeks and the firstWeek calculation is left-censored because users active before the 84-day window are being counted as new in their first week inside the window. Update the retention/cohort output or surrounding dashboard behavior to clearly flag or exclude the oldest boundary cohort, and add guidance that only recent N weeks should be treated as reliable. Keep the fix localized to the retention cohort generation flow so the misleading “new” classification does not affect interpretation.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@app/dashboard/events/retention/page.tsx`:
- Around line 9-17: `useRetention()` in `getRetention.ts` is missing a
`staleTime`, so the data prefetched in `RetentionDashboard` via `prefetchQuery`
becomes stale immediately after hydration and triggers an extra refetch. Update
the query options in `useRetention()` to set an appropriate `staleTime` so the
server-fetched retention data is reused on mount, and keep the existing
`queryKey`/`getRetentionServer` flow intact.
In `@src/widgets/posthog/RetentionHalfPieChart.tsx`:
- Around line 26-46: The retention pie chart in RetentionHalfPieChart computes
notRetainedPct as 100 when totalTrackedUsers is 0, which makes empty data render
as “미방문 100%”. Update the retainedUsersCount/totalTrackedUsers percentage logic
so the zero-user case returns 0 for both retainedPct and notRetainedPct, or
bypasses chartData generation entirely for that branch. Keep the fix localized
around the retainedPct, notRetainedPct, and chartData construction in
RetentionHalfPieChart.
In `@src/widgets/posthog/RetentionHeatmap.tsx`:
- Around line 99-119: The absolute user count in RetentionHeatmap is only
exposed via the hover-only tooltip, so keyboard and screen reader users can’t
access it. Update the cell rendering in RetentionHeatmap to include count in the
aria-label alongside the existing rate text, and make the tooltip open on focus
as well as hover by adding focus-visible/focus-based behavior to the same
cell/tooltip wrapper so both interactions reveal the count.
---
Nitpick comments:
In `@src/entities/event/model/retention.test.ts`:
- Line 1: Add coverage in retention.test for the exported date-formatting
utilities in retention, especially formatWeekRange, formatShortDate, and
formatWeekOfMonth. Extend the existing test file to import these symbols and add
focused cases for week-range formatting across a month boundary such as
2026-06-29 to 6/29 ~ 7/5, plus week-of-month calculations that verify the
correct ordinal week is returned. Keep the tests aligned with the current
behavior of buildRetentionResponse and addWeeks while locking the utility
outputs to prevent regressions.
In `@src/entities/event/model/retention.ts`:
- Around line 73-106: In retention.ts, the cohort-building logic around
sortedCohortWeeks and the firstWeek calculation is left-censored because users
active before the 84-day window are being counted as new in their first week
inside the window. Update the retention/cohort output or surrounding dashboard
behavior to clearly flag or exclude the oldest boundary cohort, and add guidance
that only recent N weeks should be treated as reliable. Keep the fix localized
to the retention cohort generation flow so the misleading “new” classification
does not affect interpretation.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 817bfcb1-8db7-455b-9591-b9f5a938e36d
📒 Files selected for processing (11)
app/api/posthog/retention/route.tsapp/dashboard/events/retention/page.tsxsrc/entities/event/api/getRetention.tssrc/entities/event/api/getRetentionServer.tssrc/entities/event/model/retention.test.tssrc/entities/event/model/retention.tssrc/views/posthog/RetentionDashboard.tsxsrc/widgets/posthog/RetentionComboChart.tsxsrc/widgets/posthog/RetentionDashboardSkeleton.tsxsrc/widgets/posthog/RetentionHalfPieChart.tsxsrc/widgets/posthog/RetentionHeatmap.tsx
- useRetention에 staleTime 추가해 SSR 프리패치 데이터 즉시 재조회 방지 - RetentionHalfPieChart: totalTrakedUsers=0 시, notRetainedPct 오표시 수정 - RetentionHeatmap: aria-label에 count 포함 및 포커스 툴팁 접근성 개선 - getRetentionServer: KST 월요일 계산을 dayjs로 교체 Resolves: #68 See also: None
🛠️ 설명 (Description)
PostHog 이벤트 데이터를 기반으로 코호트 기반 리텐션 분석 대시보드를 구현합니다.
같은 주에 처음 방문한 사용자 그룹(코호트)이 이후 주에도 재방문하는 비율을 최근 12주 기준으로 추적합니다.
📄 설계 문서 (Design Document)
📝 변경 사항 요약 (Summary)
💁 변경 사항 이유 (Why)
✅ 테스트 계획 (Test Plan)
buildRetentionResponse단위 테스트 작성 완료 (빈 데이터, W1 재방문, 미래 주차 null 처리, 중복 제거 등 8개 케이스)🔗 관련 이슈 (Related Issues)
☑️ 체크리스트 (Checklist)
👀 리뷰어를 위한 참고 사항 (Notes for Reviewers)
➕ 추가 정보 (Additional Information)
Summary by CodeRabbit
New Features
Bug Fixes