Repository navigation
[URECA-74] Feat: 요약페이지 및 마이페이지 연동 - #71
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughWalkthrough마이페이지와 요약 관련 코드가 API 연동 중심으로 재구성되었습니다. 사용자 정보 조회를 위한 Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes 🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
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: 7
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/hooks/summary/useSummaryList.ts (1)
31-32:JSON.parse에러 처리 필요
keywords가 유효하지 않은 JSON 문자열인 경우JSON.parse가 런타임 에러를 발생시킵니다. 다른 파일(src/app/(private)/bookmark/page.tsx)에서는try-catch로 안전하게 처리하고 있으니, 여기서도 동일한 패턴을 적용하는 것이 좋습니다.제안 코드
keywords: - typeof item.keywords === 'string' ? JSON.parse(item.keywords) : (item.keywords ?? []), + typeof item.keywords === 'string' + ? (() => { + try { + const parsed = JSON.parse(item.keywords); + return Array.isArray(parsed) ? parsed : [item.keywords]; + } catch { + return [item.keywords]; + } + })() + : (item.keywords ?? []),src/app/(private)/summary/_components/SummarySuccessPage.tsx (1)
82-89: keywords 배열에서 React key로 고유 식별자 사용 필수현재 코드는
keyword문자열을 key로 사용하고 있으나,keywords: string[]타입에는 유일성 보장이 없습니다. 동일한 키워드가 중복되면 React 콘솔 경고가 발생하고, 상태 업데이트 시 예상치 못한 동작이 발생할 수 있습니다.개선 방안:
- API에서 중복 제거 보장 (권장): 백엔드에서 keywords 배열이 항상 고유값이도록 처리
- 클라이언트 측 중복 제거:
keywords.filter((v, i, a) => a.indexOf(v) === i).map(...)- 인덱스 + 키워드 조합:
key={${index}-${keyword}}현재 API 설계 관점에서 keywords는 중복되면 안 되는 값이므로(태그 성격), API 응답 단계에서 유일성을 보장하는 것이 가장 깔끔한 해결책입니다. 그 전까지는 위의 2번 방식으로 중복을 클라이언트에서 필터링하는 것을 권장합니다.
🤖 Fix all issues with AI agents
In `@src/app/`(private)/mypage/page.tsx:
- Around line 32-41: The page currently ignores isError from useMe,
useSummaryList, and useBookmarkedSummaryList so API failures silently render
empty data; update the component to handle each hook's isError by showing
feedback—e.g., import your toast/error UI and in a useEffect watch isError flags
for useMe, useSummaryList, and useBookmarkedSummaryList and call
toast.error(...) with a clear message (or set local error state to render an
error panel) when any isError becomes true; also guard rendering of
me/summary/bookmark-derived values (me, summaries, bookmarks, summaryCount,
bookmarkCount, statsLoading) so you show the error UI instead of empty stats
when an error is present.
In `@src/app/`(private)/summary/_components/SummarySuccessPage.tsx:
- Around line 25-32: Destructure loading/error from useMe (e.g. const { data:
me, isLoading: meLoading, isError: meError } = useMe()), derive userId = me?.id,
and compute a disable flag (e.g. const bookmarkDisabled = meLoading || meError
|| isPending) to disable the bookmark button; guard the toggle handler so it
bails out if bookmarkDisabled or !userId before calling mutateAsync, and update
any UI/disabled props for the bookmark button accordingly; also ensure
bookmarked state syncs if me changes (update setBookmarked when isBookmarked or
me changes) and keep using useToggleBookmark({ summaryId, userId }) but prevent
its action when userId is undefined.
In `@src/app/`(private)/summary/bookmarks/page.tsx:
- Around line 21-25: The back button(s) that render only an arrow (e.g., the
<button type="button" onClick={() => router.push('/mypage')} className="ml-4
text-sm"> and the other similar buttons around the same block) need an
accessible label; add an aria-label (e.g., aria-label="뒤로가기" or aria-label="이전
페이지로 이동") to each arrow-only button so screen readers get meaningful context
while keeping existing onClick behavior and classes unchanged.
- Around line 13-17: Capture and handle the error from useMe by destructuring
error as meError (const { data: me, isLoading: meLoading, error: meError } =
useMe()) and early-return an error/unauthenticated UI when meError is truthy or
me is null; ensure useBookmarkedSummaryList is only enabled when a valid userId
exists (useBookmarkedSummaryList(Boolean(userId) ? userId : undefined, {
enabled: !!userId }) or pass enabled: !!userId) so React Query won't leave data
undefined, and adjust the loading/error checks to include meError alongside
meLoading/isLoading/isError; additionally add aria-label="뒤로가기" to all
back-button elements (the buttons used for navigation/back actions in this
component) for accessibility.
In `@src/app/`(private)/summary/page.tsx:
- Around line 12-15: Rename the `meloading` variable returned from `useMe()` to
`meLoading` (update all references) to follow camelCase, and ensure you derive
`userId` from `me?.id` as before; additionally handle the `isError` state from
`useMe()` by showing an appropriate error message or fallback UI when user info
fails to load (update the component logic where `useMe`, `me`, `meLoading`, and
`userId` are used, and ensure `useSummaryList(userId)` handles `userId` when
undefined).
In `@src/hooks/summary/useBookmarkedSummaryList.ts`:
- Around line 25-33: The mapping that sets keywords in useBookmarkedSummaryList
currently calls JSON.parse(item.keywords) unguarded which can throw and break
the whole list; update the mapping in the returned list (the object with
id/title/status/keywords/createdAt) to safely parse: wrap JSON.parse in a
try/catch, treat non-string or parse failures as an empty array, and ensure the
final keywords value is always an array (e.g., if parsed value is not an array
fall back to [] or item.keywords if already an array).
In `@src/hooks/summary/useSummaryList.ts`:
- Around line 16-19: The queryKey in useSummaryList currently uses a raw array
which is inconsistent with the queryKeys utility used elsewhere. Refactor
useSummaryList to import and use queryKeys.summaries.list(userId) for the
queryKey property in useQuery. This change centralizes queryKey definitions,
improves type safety, and ensures consistency. Also consider applying the same
pattern to similar hooks like useBookmarkedSummaryList and useSummaryDetail.
🧹 Nitpick comments (6)
src/app/(public)/onboarding/page.tsx (1)
17-31: 시맨틱 HTML 개선 👍
div에서section으로 변경하여 문서 구조의 의미를 명확히 한 점 좋습니다.다만, 접근성 관점에서
<section>은 보조 기술(스크린 리더 등)이 영역을 인식할 수 있도록aria-label또는 내부에 heading 요소(<h1>,<h2>등)를 포함하는 것이 권장됩니다. 현재 온보딩 슬라이더 내부에 heading이 있다면 괜찮지만, 없다면 추가를 고려해 주세요.- <section className="flex min-h-screen flex-col items-center justify-evenly"> + <section aria-label="온보딩" className="flex min-h-screen flex-col items-center justify-evenly">src/app/(public)/oauth/callback/[provider]/page.tsx (1)
94-97: 시맨틱 태그 선택 재고려로딩 상태를 표시하는 단순한 UI에
<section>보다는<main>또는<div>가 더 적절할 수 있습니다.<section>은 문서의 독립적인 콘텐츠 영역을 나타내는데, 이 페이지는 일시적인 로딩 상태만 표시하므로 의미론적 가치가 낮습니다.온보딩 페이지와의 일관성을 위한 변경이라면 유지해도 무방하지만, 접근성 도구가 불필요한 영역을 인식할 수 있으니 참고해 주세요.
src/app/(private)/summary/_components/SummarySuccessPage.tsx (1)
40-46: 북마크 토글 실패 시 사용자 피드백 부재현재 북마크 토글 실패 시
console.error로만 로깅하고 사용자에게 피드백이 없습니다. 다른 페이지(예:mypage)에서는toastActions를 사용하여 에러를 알리고 있으므로, 일관성 있게 토스트 메시지를 추가하는 것이 좋습니다.제안 코드
+ import { toastActions } from '@/store/slices/ToastSlice'; + import { useAppDispatch } from '@/store/hooks'; // 컴포넌트 내부에서 + const dispatch = useAppDispatch(); try { await mutateAsync(); } catch (e) { setBookmarked((prev) => !prev); - console.error(e); + console.error(e); + dispatch(toastActions.show({ text: '북마크 처리에 실패했습니다.', variant: 'error' })); }src/app/(private)/mypage/page.tsx (2)
139-147: 로딩 플레이스홀더 접근성 개선로딩 중
'...'텍스트는 스크린 리더 사용자에게 의미를 전달하기 어렵습니다.aria-busy속성이나 시각적으로 숨겨진 로딩 텍스트를 추가하면 접근성이 향상됩니다.제안 코드
- <div className="flex flex-col gap-1"> + <div className="flex flex-col gap-1" aria-busy={isLoading}> <p className="text-base font-semibold text-gray-900"> - {isLoading ? '...' : (me?.name ?? '')} + {isLoading ? <span aria-label="로딩 중">...</span> : (me?.name ?? '')} </p>
85-91: 한글 변수명 사용에 대한 일관성 검토
상담Rows,설정Rows,지원Rows등 한글 변수명을 사용하고 있습니다. 팀 내 컨벤션이라면 유지해도 되지만, 일반적으로 영문 변수명(consultationRows,settingsRows,supportRows)이 권장됩니다. 특히 다국어 환경이나 외부 개발자 협업 시 가독성 문제가 발생할 수 있습니다.src/hooks/summary/useBookmarkedSummaryList.ts (1)
17-19: 쿼리 키 헬퍼 사용으로 일관성 강화
queryKeys를 도입한 맥락상, 이 훅도 동일하게 사용하면 캐시 관리가 더 안정적입니다.♻️ 제안 변경
import { useQuery } from '@tanstack/react-query'; +import { queryKeys } from '@/lib/queryKeys'; ... - queryKey: ['summaries', 'bookmarks', userId], + queryKey: queryKeys.summaries.bookmarks(userId),
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/hooks/summary/useSummaryList.ts (2)
16-39: 심각한 구문 오류: 삼항 연산자 구조가 불완전합니다.현재 코드에서
queryFn정의 부분이 문법적으로 잘못되어 있습니다. Line 38의: skipToken은 삼항 연산자의 일부로 보이지만, 조건(?앞부분)이 누락되어 있습니다. 이 코드는 런타임 에러를 발생시킵니다.원인:
enabled옵션과skipToken을 함께 사용하려는 의도로 보이나, 구문이 올바르게 작성되지 않았습니다.개선안: React Query v5에서는
enabled와skipToken중 하나만 사용하면 됩니다.enabled옵션이 이미 쿼리 실행을 제어하므로skipToken은 제거하세요.🐛 수정 제안
export const useSummaryList = (userId?: number) => { return useQuery<SummaryListItem[]>({ queryKey: ['summaries', 'list', userId], enabled: Number.isFinite(userId), queryFn: async () => { const res = await apiClient.get('/api/summaries', { params: { userId }, }); const list: ApiSummaryItem[] = Array.isArray(res.data) ? res.data : res.data.data; return list.map((item) => ({ id: item.summaryId, title: item.title, status: mapSummaryStatus(item.status), keywords: typeof item.keywords === 'string' ? JSON.parse(item.keywords) : (item.keywords ?? []), createdAt: item.createdAt, })); - } - : skipToken, + }, }); };
31-34: JSON.parse 예외 처리 누락
item.keywords가 유효하지 않은 JSON 문자열일 경우JSON.parse가 예외를 던져 전체 쿼리가 실패합니다.개선안: try-catch로 안전하게 파싱하거나 유틸리티 함수로 분리하세요.
🔧 안전한 파싱 예시
const safeParseKeywords = (keywords: unknown): string[] => { if (Array.isArray(keywords)) return keywords; if (typeof keywords === 'string') { try { const parsed = JSON.parse(keywords); return Array.isArray(parsed) ? parsed : []; } catch { return []; } } return []; };
🤖 Fix all issues with AI agents
In `@src/app/`(private)/summary/page.tsx:
- Line 10: Remove the unused import useAppSelector from the top of the file (the
import statement importing useAppSelector in page.tsx) — locate the import line
that reads "import { useAppSelector } from '@/store/hooks';" and delete it so
ESLint rule unused-imports/no-unused-imports is satisfied and there are no
leftover references to useAppSelector in the file.
🧹 Nitpick comments (3)
src/app/(private)/summary/page.tsx (1)
46-49: 중복된 keywords 타입 체크 제거 가능
useSummaryList훅에서 이미keywords를 배열로 정규화하고 있습니다(Line 31-34 참조). 따라서 이 컴포넌트에서 다시 문자열 여부를 체크할 필요가 없습니다.원인: 훅과 컴포넌트 간 데이터 흐름에 대한 이해 부족 또는 방어적 코딩
♻️ 간소화 제안
{data?.map((summary) => { - const badges = - typeof summary.keywords === 'string' ? [summary.keywords] : summary.keywords; + const badges = summary.keywords; return ( <Link key={summary.id} href={`/summary/${summary.id}`}> <SummaryNavigateCard status={summary.status} title={summary.title} badges={badges} createdAt={summary.createdAt} /> </Link> ); })}src/app/(private)/summary/_components/SummarySuccessPage.tsx (2)
71-81: 접근성(a11y) 개선: 북마크 버튼에 aria-label 추가 필요북마크 버튼에 텍스트 레이블이 없어 스크린 리더 사용자가 버튼의 목적을 파악하기 어렵습니다.
aria-label과aria-pressed속성을 추가하여 접근성을 개선하세요.♿ 접근성 개선 제안
<button type="button" onClick={handleToggleBookmark} - disabled={isPending} + disabled={isPending || !userId} + aria-label={bookmarked ? '북마크 해제' : '북마크 추가'} + aria-pressed={bookmarked} className="mr-4 ml-auto" >
96-103: React key로 keyword 사용 시 중복 위험
keyword값이 중복될 수 있는 경우, 동일한 key가 생성되어 React 렌더링 경고 및 예기치 않은 동작이 발생할 수 있습니다.🔧 안전한 key 사용 제안
- {keywords.map((keyword) => ( + {keywords.map((keyword, index) => ( <span - key={keyword} + key={`${keyword}-${index}`} className="rounded-full bg-pink-100 px-2 py-0.5 text-[11px] font-medium text-pink-600" >
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/app/(private)/summary/page.tsx (1)
11-34: 인증 오류와 일반 오류를 분리하여 안정성 높여주세요.Line 26에서
meError를 곧바로 "로그인이 필요합니다"로 처리하면 401/403 인증 실패뿐 아니라 네트워크/서버 오류(500, 503 등)도 동일한 메시지로 노출돼 사용자 경험이 저하됩니다.useQuery는
error객체도 반환하므로,error?.response?.status로 HTTP 상태 코드를 구분할 수 있습니다:const { data: me, isLoading: meLoading, isError: meError, error: meErrorObj } = useMe(); const userId = me?.id; const { data, isLoading, isError } = useSummaryList(userId); // 로딩 상태 if (meLoading || isLoading) { return <LoadingPage />; } // 인증 오류 (401/403) const isAuthError = meError && [401, 403].includes(meErrorObj?.response?.status); if (isAuthError) { return <AuthErrorPage message="로그인이 필요합니다" />; } // userId 미확보 if (!Number.isFinite(userId)) { return <ErrorPage message="사용자 정보를 불러올 수 없습니다" />; } // 일반 오류 (서버/네트워크) if (meError) { return <ErrorPage message="오류가 발생했습니다. 잠시 후 다시 시도해주세요" />; } if (isError) { return <ErrorPage message="요약을 불러오지 못했습니다" />; } // 성공 return <SuccessPage />;이렇게 구분하면 사용자에게 정확한 안내를 제공하고, 개발 과정에서 에러 원인도 명확히 파악할 수 있습니다.
🤖 Fix all issues with AI agents
In `@src/app/`(private)/summary/_components/SummarySuccessPage.tsx:
- Around line 68-72: The bookmark icon button lacks ARIA attributes; update the
button rendered in SummarySuccessPage (the element using
onClick={handleToggleBookmark} and disabled={disabled}) to include an aria-label
(e.g., "Toggle bookmark" or localized text) and an aria-pressed attribute bound
to the current bookmark state variable (e.g., isBookmarked or bookmarked) so
screen readers get meaningful state; keep the existing onClick/disabled behavior
and ensure the aria-label text reflects the action and aria-pressed reflects the
boolean state.
In `@src/hooks/summary/useSummaryList.ts`:
- Around line 32-33: The current inline use of JSON.parse for item.keywords can
throw if the string is invalid; update the code in useSummaryList (where
keywords is assigned) to defensively parse: either call a new utility function
(e.g., parseKeywords) that accepts string | string[] | undefined and returns
string[] with try/catch, or wrap the JSON.parse in a try/catch and return [] on
error; ensure you handle Array.isArray(item.keywords) and non-string cases too
so keywords becomes a safe string[] before further use.
🧹 Nitpick comments (4)
src/app/(public)/splash/page.tsx (1)
23-43: 시맨틱 HTML 변경: 접근성 고려 필요
<main>요소는 페이지의 주요 콘텐츠 영역을 나타내며, 스크린 리더 사용자가 메인 콘텐츠로 바로 이동할 수 있도록 돕습니다.<div>로 변경하면 이러한 시맨틱 정보가 사라집니다.스플래시 페이지는 2초 후 자동 리다이렉트되므로 실제 영향은 적지만, 페이지 컴포넌트의 루트 요소로는
<main>이 더 적합합니다.♻️ 시맨틱 요소 복원 제안
- <div className="relative h-dvh w-full overflow-hidden bg-[`#FFF7F8`]"> + <main className="relative h-dvh w-full overflow-hidden bg-[`#FFF7F8`]"> ... - </div> + </main>src/app/(policy)/policy/_components/policy-header/index.tsx (1)
48-75: 시맨틱 요소 개선 제안:<header>고려
<main>을<div>로 변경한 것은 올바른 수정입니다. 다만, 이 컴포넌트는 페이지의 헤더 역할(로고, 환영 메시지, 뒤로가기 버튼)을 수행하므로<header>요소가 더 적합할 수 있습니다.♻️ 시맨틱 요소 개선 제안
- <div className="flex flex-col"> + <header className="flex flex-col"> ... - </div> + </header>src/hooks/summary/useBookmarkedSummaryList.ts (1)
28-43: 키워드 파싱 로직 공통화 고려.Line 32-43의 파싱 로직은 요약 리스트 등 다른 훅에서도 반복될 여지가 큽니다. 공통 유틸로 분리하면 중복/테스트 비용을 줄이고 유지보수성이 좋아집니다.
♻️ 예시 리팩터링
+const normalizeKeywords = (keywords?: string[] | string): string[] => { + if (Array.isArray(keywords)) return keywords; + if (typeof keywords === 'string') { + try { + const parsed = JSON.parse(keywords); + return Array.isArray(parsed) ? parsed : [keywords]; + } catch { + return [keywords]; + } + } + return []; +}; ... - keywords: (() => { - if (Array.isArray(item.keywords)) return item.keywords; - if (typeof item.keywords === 'string') { - try { - const parsed = JSON.parse(item.keywords); - return Array.isArray(parsed) ? parsed : [item.keywords]; - } catch { - return [item.keywords]; - } - } - return []; - })(), + keywords: normalizeKeywords(item.keywords),As per coding guidelines 새로운 기능 추가나 수정 시, 기존 코드와의 호환성, 재사용성뿐 아니라 확장 가능한 구조인지도 검토.
src/app/(private)/summary/_components/SummarySuccessPage.tsx (1)
28-33:bookmarked상태를 props 변경과 동기화하세요.Line 28-33에서
useState(isBookmarked)로 초기화만 하면 refetch로isBookmarked가 바뀔 때 UI가 stale할 수 있습니다.useEffect로 동기화하면 일관성이 좋아집니다.♻️ 제안 수정
-import { useState } from 'react'; +import { useEffect, useState } from 'react'; ... const [bookmarked, setBookmarked] = useState(isBookmarked); +useEffect(() => { + setBookmarked(isBookmarked); +}, [isBookmarked, summaryId]);
There was a problem hiding this comment.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/app/(private)/summary/_components/SummarySuccessPage.tsx (2)
95-102: keywords 중복 시 key 충돌 가능성
keyword를 직접 key로 사용하면 동일한 키워드가 여러 개일 경우 React key 경고가 발생합니다. 인덱스를 조합하거나 고유 식별자를 사용하는 것이 안전합니다.🔧 key 충돌 방지
- {keywords.map((keyword) => ( + {keywords.map((keyword, idx) => ( <span - key={keyword} + key={`${keyword}-${idx}`} className="rounded-full bg-pink-100 px-2 py-0.5 text-[11px] font-medium text-pink-600" >
62-64: 뒤로가기 동작:router.back()사용 권장현재 코드는
router.push('/summary')로 항상 목록 페이지로 이동합니다. 문제는 사용자가/summary/bookmarks에서 상세 페이지로 진입한 경우, 뒤로가기를 클릭하면 북마크 페이지가 아닌 일반 목록으로 이동한다는 점입니다.개선안:
router.back()을 사용하면 사용자가 어느 페이지에서 왔든 직전 페이지로 돌아갈 수 있습니다. 이는 사용자의 네비게이션 맥락을 존중하고 더 자연스러운 UX를 제공합니다.코드 변경 예시
// Before <button type="button" onClick={() => router.push('/summary')} className="ml-4"> // After <button type="button" onClick={() => router.back()} className="ml-4">
🧹 Nitpick comments (2)
src/app/(private)/summary/_components/SummarySuccessPage.tsx (2)
40-43: 에러 발생 시 사용자 피드백 부재현재 북마크 토글 실패 시
console.error만 호출하고 있어 사용자는 실패 여부를 알 수 없습니다. 네트워크 오류나 인증 만료 등의 상황에서 사용자 경험을 위해 토스트나 알림을 제공하는 것을 권장합니다.💡 사용자 피드백 추가 예시
} catch (e) { setBookmarked((prev) => !prev); console.error(e); + // 예: toast 라이브러리 사용 시 + // toast.error('북마크 처리에 실패했습니다. 다시 시도해주세요.'); }Based on learnings: 가독성과 안정성(에러/예외 처리)을 최우선으로 검토하고, 로직이 단순하고 직관적으로 읽히는지 확인
46-56: convertDate 함수를 컴포넌트 외부로 분리 권장순수 함수이므로 컴포넌트 외부로 이동하면 매 렌더링마다 재생성되지 않고, 재사용성과 테스트 용이성이 향상됩니다.
♻️ 컴포넌트 외부로 분리
+ const convertDate = (date: string): string => { + const toDate = new Date(date); + return toDate.toLocaleString('ko-KR', { + year: 'numeric', + month: 'long', + day: 'numeric', + hour: 'numeric', + minute: '2-digit', + hour12: true, + }); + }; + export const SummarySuccessPage = ({ data }: SummarySuccessPageProps) => { const router = useRouter(); // ... - const convertDate = (date: string): string => { - const toDate = new Date(date); - return toDate.toLocaleString('ko-KR', { - year: 'numeric', - month: 'long', - day: 'numeric', - hour: 'numeric', - minute: '2-digit', - hour12: true, - }); - };
Key Changes
작업 내역
마이페이지 연동 (이름, 이메일, 전체 상담 건수, 북마크한 상담 건수)
북마크 토글 API 연동
마이페이지에 북마크한 요약페이지 연결
close: [URECA-74] Feat: 마이페이지 api 연동 #69
📸 스크린샷
💬 공유사항 to 리뷰어
비고
PR Checklist
PR이 다음 요구 사항을 충족하는지 확인하세요.
Summary by CodeRabbit
New Features
Improvements
Chores
Style
✏️ Tip: You can customize this high-level summary in your review settings.