Conversation
|
""" Walkthrough스토리 상세 조회 기능이 새로 구현되었습니다. 서버에서 스토리 데이터를 미리 패칭하고, 클라이언트에서 하이드레이션 및 Suspense로 상세 내용을 표시합니다. 아바타, 스타일, 유틸, 쿼리, 타입, API 등 관련 파일이 추가·수정되었으며, motion 라이브러리 교체 및 기타 리팩토링이 포함되어 있습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant StoryDetailPage (Server)
participant API
participant HydrationBoundary
participant StoryDetailContent (Client)
participant QueryClient
User->>StoryDetailPage (Server): 페이지 접속 (스토리 id 포함)
StoryDetailPage->>API: getStoryDetail(storyId) 호출
API-->>StoryDetailPage: StoryDetailResponse 반환
StoryDetailPage->>HydrationBoundary: dehydrated state 전달
HydrationBoundary->>StoryDetailContent (Client): Suspense로 감싸서 렌더링
StoryDetailContent->>QueryClient: useSuspenseQuery로 데이터 요청
QueryClient-->>StoryDetailContent: 하이드레이션된 데이터 반환
StoryDetailContent-->>User: 상세 화면 렌더링
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Assessment against linked issues
Assessment against linked issues: Out-of-scope changes(해당 변경사항에서 요구사항과 무관한 기능적 코드 변경은 발견되지 않았습니다.) Possibly related PRs
Poem
Note ⚡️ Unit Test Generation is now available in beta!Learn more here, or try it out under "Finishing Touches" below. 📜 Recent review detailsConfiguration used: CodeRabbit UI ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
✨ Finishing Touches
🧪 Generate unit tests
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
|
🎨 Storybook Preview: https://685a32a1c0bbd269fdb67af4-jasvxeveay.chromatic.com/ |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (8)
src/app/member/_constants/profileColors.constants.ts (2)
1-14: 숫자 인덱스를 문자열 리터럴로 추론하는 타입 이슈
keyof typeof PROFILE_COLORS는"0" | "1" | "2"(문자열) 유니온을 생성합니다. 실제 사용처가 숫자 인덱스를 기대한다면 타입 불일치가 생깁니다. 배열 형태로 선언하면 타입·런타임 모두 간단히 맞출 수 있습니다.-export const PROFILE_COLORS = { - 0: { background: "#FFF1AF", name: "yellow" }, - 1: { background: "#FFDDDA", name: "pink" }, - 2: { background: "#C9ECFF", name: "blue" }, -} as const; +export const PROFILE_COLORS = [ + { background: "#FFF1AF", name: "yellow" }, + { background: "#FFDDDA", name: "pink" }, + { background: "#C9ECFF", name: "blue" }, +] as const;
19-19:PROFILE_COLOR_COUNT는 상수이므로 직접 리터럴을 써도 트리에이킹에 유리컴파일 타임에 3으로 결정되는 값이므로
const PROFILE_COLOR_COUNT = 3으로 두면 번들러가 최적화하기 쉽습니다.src/app/member/_utils/profileUtils.ts (1)
10-12: 타입 캐스팅 대신 더 안전한 방법을 고려하세요.현재
as ProfileColorIndex로 타입 캐스팅을 사용하고 있는데, 이는 런타임에서 타입 안전성을 보장하지 못합니다.더 안전한 구현을 위해 다음과 같이 개선할 수 있습니다:
export const getProfileColorIndex = (memberId: number): ProfileColorIndex => { - return (Math.abs(memberId) % PROFILE_COLOR_COUNT) as ProfileColorIndex; + const index = Math.abs(memberId) % PROFILE_COLOR_COUNT; + return index as ProfileColorIndex; };또는 런타임 검증을 추가:
export const getProfileColorIndex = (memberId: number): ProfileColorIndex => { const index = Math.abs(memberId) % PROFILE_COLOR_COUNT; + if (!(index in PROFILE_COLORS)) { + throw new Error(`Invalid profile color index: ${index}`); + } return index as ProfileColorIndex; };src/app/member/_components/Avatar/Avatar.tsx (1)
32-39: 스타일링 일관성과 접근성을 개선해보세요.현재 CSS 모듈과 인라인 스타일을 혼합 사용하고 있고, 접근성을 위한 속성이 누락되었습니다.
다음과 같이 개선할 수 있습니다:
<div className={`${styles.avatar} ${className || ""}`} style={{ backgroundColor: colorConfig.background, }} + role="img" + aria-label={`${memberNickname || '사용자'}의 프로필 아바타`} > <Bapurit width={23} height={23} /> </div>또는 CSS 변수를 사용하여 스타일링을 일관성 있게 관리:
<div - className={`${styles.avatar} ${className || ""}`} - style={{ - backgroundColor: colorConfig.background, - }} + className={`${styles.avatar} ${styles[colorConfig.name]} ${className || ""}`} >src/app/story/[id]/page.tsx (1)
22-22: 에러 처리 추가를 고려해보세요.prefetchQuery에서 실패할 경우에 대한 처리가 없습니다. 네트워크 오류나 API 에러 시 사용자 경험을 개선할 수 있습니다.
다음과 같이 에러 처리를 추가할 수 있습니다:
const queryClient = getQueryClient(); + try { await queryClient.prefetchQuery(storyDetailQueryOptions(storyId)); + } catch (error) { + // 프리페치 실패 시에도 클라이언트에서 재시도할 수 있도록 허용 + console.warn('Story detail prefetch failed:', error); + }또는 에러 바운더리와 함께 사용:
return ( <HydrationBoundary state={dehydrate(queryClient)}> + <ErrorBoundary fallback={<StoryDetailErrorFallback />}> <Suspense> <StoryDetailContent storyId={storyId} /> </Suspense> + </ErrorBoundary> </HydrationBoundary> );src/app/story/[id]/_components/StoryDetailContent/StoryDetailContent.css.ts (1)
101-101: CSS 속성값에 불필요한 공백이 있습니다.
background속성값 앞에 불필요한 공백이 있습니다.- background: " rgba(0, 0, 0, 0.28)", + background: "rgba(0, 0, 0, 0.28)",src/app/story/[id]/_components/StoryDetailContent/StoryDetailContent.tsx (2)
74-74: 옵셔널 체이닝 사용이 불필요합니다.이미 useSuspenseQuery를 사용하고 있어 data가 보장되므로 옵셔널 체이닝(
?.)이 불필요합니다.- {story?.description && ( + {story.description && (
102-102: TODO 주석이 있습니다.가게 상세페이지 이동 기능이 아직 구현되지 않았습니다. 이를 추적할 이슈를 생성하는 것이 좋겠습니다.
이 TODO를 해결하는 이슈를 생성해드릴까요?
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (5)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yamlsrc/assets/location.svgis excluded by!**/*.svgsrc/assets/logo/symbol.svgis excluded by!**/*.svgsrc/assets/market.svgis excluded by!**/*.svgsrc/assets/notification.svgis excluded by!**/*.svg
📒 Files selected for processing (18)
package.json(1 hunks)src/app/(search)/_components/SearchStoreBottomSheet/SearchStoreBottomSheet.tsx(1 hunks)src/app/member/_components/Avatar/Avatar.css.ts(1 hunks)src/app/member/_components/Avatar/Avatar.tsx(1 hunks)src/app/member/_components/Avatar/index.ts(1 hunks)src/app/member/_constants/index.ts(1 hunks)src/app/member/_constants/profileColors.constants.ts(1 hunks)src/app/member/_utils/index.ts(1 hunks)src/app/member/_utils/profileUtils.ts(1 hunks)src/app/member/profile/_components/Profile/ProfileLayout.tsx(1 hunks)src/app/story/[id]/_api/detail.api.ts(1 hunks)src/app/story/[id]/_api/detail.queries.ts(1 hunks)src/app/story/[id]/_api/detail.types.ts(1 hunks)src/app/story/[id]/_api/index.ts(1 hunks)src/app/story/[id]/_components/StoryDetailContent/StoryDetailContent.css.ts(1 hunks)src/app/story/[id]/_components/StoryDetailContent/StoryDetailContent.tsx(1 hunks)src/app/story/[id]/_components/StoryDetailContent/index.ts(1 hunks)src/app/story/[id]/page.tsx(1 hunks)
🧰 Additional context used
📓 Path-based instructions (7)
{src/app/**/_components/**/*.tsx,src/components/**/*.tsx}
📄 CodeRabbit Inference Engine (.cursor/rules/nextjs-folder-structure.mdc)
Component files must use PascalCase naming (e.g.,
Button.tsx,DomainLayout.tsx).
Files:
src/app/member/profile/_components/Profile/ProfileLayout.tsxsrc/app/(search)/_components/SearchStoreBottomSheet/SearchStoreBottomSheet.tsxsrc/app/member/_components/Avatar/Avatar.tsxsrc/app/story/[id]/_components/StoryDetailContent/StoryDetailContent.tsx
src/**/*.{ts,tsx}
📄 CodeRabbit Inference Engine (.cursor/rules/nextjs-folder-structure.mdc)
All files must use TypeScript.
Files:
src/app/member/profile/_components/Profile/ProfileLayout.tsxsrc/app/member/_components/Avatar/index.tssrc/app/story/[id]/_api/index.tssrc/app/member/_utils/index.tssrc/app/(search)/_components/SearchStoreBottomSheet/SearchStoreBottomSheet.tsxsrc/app/member/_components/Avatar/Avatar.css.tssrc/app/story/[id]/_api/detail.api.tssrc/app/member/_constants/index.tssrc/app/member/_utils/profileUtils.tssrc/app/story/[id]/_components/StoryDetailContent/index.tssrc/app/member/_components/Avatar/Avatar.tsxsrc/app/story/[id]/_components/StoryDetailContent/StoryDetailContent.css.tssrc/app/story/[id]/page.tsxsrc/app/member/_constants/profileColors.constants.tssrc/app/story/[id]/_api/detail.queries.tssrc/app/story/[id]/_api/detail.types.tssrc/app/story/[id]/_components/StoryDetailContent/StoryDetailContent.tsx
{src/lib/utils/*.ts,src/lib/api/*.ts,src/app/**/_utils/*.ts,src/app/**/_api/*.ts}
📄 CodeRabbit Inference Engine (.cursor/rules/nextjs-folder-structure.mdc)
Utility and API files must use camelCase naming (e.g.,
domainUtils.ts,domain.api.ts).
Files:
src/app/story/[id]/_api/index.tssrc/app/member/_utils/index.tssrc/app/story/[id]/_api/detail.api.tssrc/app/member/_utils/profileUtils.tssrc/app/story/[id]/_api/detail.queries.tssrc/app/story/[id]/_api/detail.types.ts
{src/styles/**/*.css.ts,src/app/**/_components/**/*.css.ts,src/components/**/*.css.ts}
📄 CodeRabbit Inference Engine (.cursor/rules/nextjs-folder-structure.mdc)
Style files must use camelCase naming with the
.css.tsextension (e.g.,Button.css.ts,theme.css.ts).
Files:
src/app/member/_components/Avatar/Avatar.css.tssrc/app/story/[id]/_components/StoryDetailContent/StoryDetailContent.css.ts
src/app/**/_api/*.{api,queries}.ts
📄 CodeRabbit Inference Engine (.cursor/rules/nextjs-folder-structure.mdc)
API calls should be implemented in
.api.tsfiles using ky, and queries in.queries.tsfiles using TanStack Query, both located in_apifolders.
Files:
src/app/story/[id]/_api/detail.api.tssrc/app/story/[id]/_api/detail.queries.ts
{src/constants/*.ts,src/app/**/_constants/*.ts}
📄 CodeRabbit Inference Engine (.cursor/rules/nextjs-folder-structure.mdc)
Constant files must use camelCase naming (e.g.,
domain.constants.ts).
Files:
src/app/member/_constants/index.tssrc/app/member/_constants/profileColors.constants.ts
src/app/**/_constants/*.ts
📄 CodeRabbit Inference Engine (.cursor/rules/nextjs-folder-structure.mdc)
Domain-specific constants should be defined in
_constantsfolders.
Files:
src/app/member/_constants/index.tssrc/app/member/_constants/profileColors.constants.ts
🧠 Learnings (9)
src/app/member/profile/_components/Profile/ProfileLayout.tsx (2)
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-07-20T14:21:47.408Z
Learning: Applies to {src/app//_components//.tsx,src/components/**/.tsx} : Component files must use PascalCase naming (e.g., Button.tsx, DomainLayout.tsx).
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-07-20T14:21:47.408Z
Learning: Applies to {src/app/**/_components/.css.ts,src/components/.css.ts} : Component-specific styles should be co-located with the component file.
src/app/story/[id]/_api/index.ts (5)
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-07-20T14:21:47.408Z
Learning: Applies to src/app/**/_api/*.{api,queries}.ts : API calls should be implemented in .api.ts files using ky, and queries in .queries.ts files using TanStack Query, both located in _api folders.
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-07-20T14:21:47.408Z
Learning: Applies to src/lib/api/*.ts : Global API client configuration and types should be placed in lib/api/.
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-07-20T14:21:47.408Z
Learning: Applies to src/app/**/_types/*.ts : Domain-specific types should be defined in _types folders.
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-07-20T14:21:47.408Z
Learning: Applies to src/lib/utils/*.ts : Global utility functions should be placed in lib/utils/ and separated by functionality.
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-07-20T14:21:47.408Z
Learning: Applies to {src/lib/utils/.ts,src/lib/api/.ts,src/app//_utils/*.ts,src/app//_api/*.ts} : Utility and API files must use camelCase naming (e.g., domainUtils.ts, domain.api.ts).
src/app/member/_utils/index.ts (3)
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-07-20T14:21:47.408Z
Learning: Applies to src/lib/utils/*.ts : Global utility functions should be placed in lib/utils/ and separated by functionality.
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-07-20T14:21:47.408Z
Learning: Applies to {src/lib/utils/.ts,src/lib/api/.ts,src/app//_utils/*.ts,src/app//_api/*.ts} : Utility and API files must use camelCase naming (e.g., domainUtils.ts, domain.api.ts).
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-07-20T14:21:47.408Z
Learning: Applies to src/lib/api/*.ts : Global API client configuration and types should be placed in lib/api/.
src/app/member/_components/Avatar/Avatar.css.ts (3)
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-07-20T14:21:47.408Z
Learning: Applies to {src/app/**/_components/.css.ts,src/components/.css.ts} : Component-specific styles should be co-located with the component file.
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-07-20T14:21:47.408Z
Learning: Applies to src/styles/*.css.ts : Global styles should be placed in the styles/ folder, using vanilla-extract.
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-07-20T14:21:47.408Z
Learning: Applies to {src/styles//*.css.ts,src/app//_components//*.css.ts,src/components//*.css.ts} : Style files must use camelCase naming with the .css.ts extension (e.g., Button.css.ts, theme.css.ts).
src/app/member/_constants/index.ts (3)
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-07-20T14:21:47.408Z
Learning: Applies to src/app/**/_constants/*.ts : Domain-specific constants should be defined in _constants folders.
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-07-20T14:21:47.408Z
Learning: Applies to {src/constants/.ts,src/app/**/_constants/.ts} : Constant files must use camelCase naming (e.g., domain.constants.ts).
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-07-20T14:21:47.408Z
Learning: Applies to src/lib/api/*.ts : Global API client configuration and types should be placed in lib/api/.
src/app/story/[id]/_components/StoryDetailContent/index.ts (1)
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-07-20T14:21:47.408Z
Learning: Applies to {src/app/**/_components/.css.ts,src/components/.css.ts} : Component-specific styles should be co-located with the component file.
src/app/story/[id]/_components/StoryDetailContent/StoryDetailContent.css.ts (3)
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-07-20T14:21:47.408Z
Learning: Applies to {src/app/**/_components/.css.ts,src/components/.css.ts} : Component-specific styles should be co-located with the component file.
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-07-20T14:21:47.408Z
Learning: Applies to src/styles/*.css.ts : Global styles should be placed in the styles/ folder, using vanilla-extract.
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-07-20T14:21:47.408Z
Learning: Applies to {src/styles//*.css.ts,src/app//_components//*.css.ts,src/components//*.css.ts} : Style files must use camelCase naming with the .css.ts extension (e.g., Button.css.ts, theme.css.ts).
src/app/member/_constants/profileColors.constants.ts (2)
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-07-20T14:21:47.408Z
Learning: Applies to src/app/**/_constants/*.ts : Domain-specific constants should be defined in _constants folders.
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-07-20T14:21:47.408Z
Learning: Applies to {src/constants/.ts,src/app/**/_constants/.ts} : Constant files must use camelCase naming (e.g., domain.constants.ts).
src/app/story/[id]/_api/detail.queries.ts (1)
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-07-20T14:21:47.408Z
Learning: Applies to src/app/**/_api/*.{api,queries}.ts : API calls should be implemented in .api.ts files using ky, and queries in .queries.ts files using TanStack Query, both located in _api folders.
🧬 Code Graph Analysis (5)
src/app/story/[id]/_api/detail.api.ts (2)
src/app/story/[id]/_api/detail.types.ts (1)
StoryDetailResponse(1-11)src/lib/api/client.ts (1)
http(69-74)
src/app/member/_utils/profileUtils.ts (1)
src/app/member/_constants/profileColors.constants.ts (2)
ProfileColorIndex(16-16)PROFILE_COLOR_COUNT(19-19)
src/app/member/_components/Avatar/Avatar.tsx (2)
src/app/member/_utils/profileUtils.ts (1)
getProfileColorIndex(10-12)src/app/member/_constants/profileColors.constants.ts (1)
PROFILE_COLORS(1-14)
src/app/story/[id]/_api/detail.queries.ts (1)
src/app/story/[id]/_api/detail.api.ts (1)
getStoryDetail(10-16)
src/app/story/[id]/_components/StoryDetailContent/StoryDetailContent.tsx (2)
src/app/story/[id]/_components/StoryDetailContent/index.ts (1)
StoryDetailContent(1-1)src/app/story/[id]/_api/detail.queries.ts (1)
storyDetailQueryOptions(8-12)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: test
🔇 Additional comments (22)
package.json (1)
33-33: framer-motion 임포트 잔여 없음 확인–
rg -n "from\s+['\"]framer-motion['\"]" --glob '*.[tj]s*'실행 결과 코드베이스에from "framer-motion"임포트가 전혀 남아 있지 않습니다.
–package.json에서"motion": "^12.23.11"로 정상 전환된 상태입니다.src/app/(search)/_components/SearchStoreBottomSheet/SearchStoreBottomSheet.tsx (1)
4-4: 새 패키지 서브패스(motion/react)가 실제 배포본에 포함되는지 확인 필요
motion/react서브패스는 ESM 전용 패키지에서만 제공됩니다. Next.js(webpack/RS) 설정, 트리 셰이킹, 타입 정의(@types/motion미제공) 호환성까지 반드시 로컬 빌드로 검증해 주세요. 문제가 있으면"motion"루트에서 import 하거나framer-motion을 유지하는 방안을 고려해야 합니다.src/app/member/profile/_components/Profile/ProfileLayout.tsx (1)
5-5: 확인 완료: 레거시 참조 없음
전역 검색 결과'front-bapurit'문자열이 더 이상 존재하지 않아,symbol.svg로의 변경이 올바르게 적용된 것을 확인했습니다.src/app/member/_constants/index.ts (1)
1-1: LGTM – 새 프로필 색상 상수 재-export 정상 추가재사용성을 높이는 올바른 구성입니다.
src/app/member/_components/Avatar/index.ts (1)
1-1: LGTM! 표준적인 barrel export 패턴이 잘 적용되었습니다.컴포넌트의 중앙 집중식 import를 위한 깔끔한 구조입니다.
src/app/story/[id]/_components/StoryDetailContent/index.ts (1)
1-1: LGTM! 일관된 barrel export 패턴이 적용되었습니다.스토리 상세 컴포넌트의 중앙 집중식 export 구조가 적절합니다.
src/app/member/_components/Avatar/Avatar.css.ts (1)
1-13: LGTM! 아바타 스타일이 잘 정의되었습니다.vanilla-extract를 사용한 깔끔한 스타일 정의와 공통 디자인 시스템(radius) 활용이 우수합니다. 컴포넌트별 스타일 co-location도 가이드라인에 맞게 적용되었습니다.
src/app/story/[id]/_api/index.ts (1)
1-3: LGTM! API 모듈 구조가 훌륭합니다.API, 쿼리, 타입을 분리한 관심사 분리와 barrel export를 통한 중앙 집중식 접근이 코딩 가이드라인에 완벽히 부합합니다.
src/app/member/_utils/index.ts (1)
1-2: LGTM! 유틸리티 모듈 export가 일관되게 개선되었습니다.wildcard export 사용으로 일관된 패턴을 적용하고, 새로운 profileUtils 추가로 기능이 확장되었습니다.
src/app/story/[id]/_api/detail.api.ts (1)
5-16: API 함수 구현이 잘 되었습니다.JSDoc 문서화, 타입 안전성, HTTP 클라이언트 사용이 적절합니다. 코딩 가이드라인의 camelCase 네이밍도 준수되었습니다.
src/app/story/[id]/_api/detail.types.ts (1)
1-11: 타입 정의가 잘 구성되었습니다.스토리 상세 정보를 나타내는 타입이 명확하게 정의되었고, nullable 필드(
description)도 적절히 처리되었습니다. 네이밍 규칙도 잘 지켜졌습니다.src/app/member/_components/Avatar/Avatar.tsx (1)
14-26: 훌륭한 JSDoc 문서화입니다.컴포넌트의 목적, 동작 방식, 사용 예제가 명확하게 작성되어 있어 개발자 경험이 향상됩니다.
src/app/story/[id]/page.tsx (1)
15-31: 서버 사이드 프리페칭 패턴이 잘 구현되었습니다.React Query의 prefetch, HydrationBoundary, Suspense를 활용한 현대적인 Next.js 패턴이 적절히 적용되었습니다.
src/app/story/[id]/_components/StoryDetailContent/StoryDetailContent.css.ts (2)
1-3: Import 구문이 올바르게 구성되어 있습니다.vanilla-extract와 스타일 토큰 import가 적절하게 되어 있습니다.
5-12: 컨테이너 스타일이 적절합니다.전체 뷰포트 높이와 다크 배경을 사용한 레이아웃이 스토리 상세 페이지에 적합합니다.
src/app/story/[id]/_api/detail.queries.ts (2)
3-6: 쿼리 키 구조가 잘 설계되어 있습니다.계층적 쿼리 키 구조와
as const사용으로 타입 안전성을 보장하고 있습니다.
8-12: 쿼리 옵션 설정이 적절합니다.
enabled옵션으로 storyId가 존재할 때만 쿼리가 실행되도록 하여 불필요한 API 호출을 방지하고 있습니다.src/app/story/[id]/_components/StoryDetailContent/StoryDetailContent.tsx (5)
1-17: Import 구문이 잘 구성되어 있습니다.필요한 라이브러리와 컴포넌트들이 적절하게 import되어 있으며, motion/react 라이브러리 사용도 적절합니다.
25-30: 훅 사용이 적절합니다.useSuspenseQuery를 통한 데이터 페칭과 useState를 통한 상태 관리가 올바르게 구현되어 있습니다.
46-54: 접근성이 잘 고려되어 있습니다.버튼에
aria-label이 적절하게 설정되어 있어 스크린 리더 사용자를 위한 접근성이 확보되어 있습니다.
76-95: 애니메이션 구현이 우수합니다.motion.div를 사용한 부드러운 높이 애니메이션과 적절한 easing 설정이 사용자 경험을 향상시킵니다.
121-131: AnimatePresence 사용이 적절합니다.설명 확장 시 오버레이의 부드러운 페이드 인/아웃 애니메이션이 잘 구현되어 있습니다.
✅ 이슈 번호
close #85
🪄 작업 내용 (변경 사항)
📸 스크린샷
2025-07-30.8.10.53.1.mov
💡 설명
랜덤 아바타
memberId를 기준으로 고정된 색상이 부여되도록Math.abs(memberId) % N을 사용해 색상 인덱스를 계산했습니다.PROFILE_COLORS상수로 관리하며, 피그마에서 정의된 3가지 색상(yellow, pink, blue)을 기준으로 선언해두었습니다~!Avatar 컴포넌트에서 해당 인덱스를 기반으로 지정됩니다.스토리 상세 조회
/story/[id]는 스토리 데이터가 필수인 페이지이기 때문에, 진입 시 서버 컴포넌트app/story/[id]/page.tsx에서queryClient.prefetchQuery로 데이터를 사전 fetch 하도록 구성했습니다~!HydrationBoundary로 감싸 클라이언트에 전달하고, 클라이언트 측에서는useSuspenseQuery를 통해 데이터를 사용할 수 있게 했습니다.🗣️ 리뷰어에게 전달 사항
📍 트러블 슈팅
Summary by CodeRabbit
Summary by CodeRabbit
신규 기능
스타일
버그 수정
기타