Skip to content

Conversation

@kimnamheeee
Copy link
Contributor

@kimnamheeee kimnamheeee commented Dec 22, 2025

📝 설명

홈페이지 구성 컴포넌트를 리팩토링했습니다. navigation 컴포넌트의 경우 모든 페이지를 대상으로 한 번에 리팩토링 진행 예정이라 따로 건드리지 않았습니다.

🛠️ 주요 변경 사항

  • 홈페이지를 구성하는 컴포넌트를 server / client 역할에 맞게 분리

리뷰 시 고려해야 할 사항

나중에 수정해야 할 부분
현재 구성이 변경되면서 홈페이지가 pre-rendering 대상이 된 것 같은데, 이때 API_URL이 없어서 빌드에서 계속 에러가 남
해결 방법은 두 가지

  • getDefaultGame은 mocking을 제거하고 실제 백엔드 서버로 요청을 보내도록 해서 build과정에서도 문제가 없게 만들기
  • force-dynamic을 줘서 SSG 포기 (현재 구현)

원래 첫 번째 방법으로 가려고 했으나, 이렇게 하게 될 경우 getGameDetail (msw를 사용함) 와의 충돌이 발생 (mock data는 uuid 형식을 사용하지 않을 뿐더러, uuid를 사용한다고 하더라도 getGameDetail에서는 id가 동일한지를 검사하기 때문에 형식이 동일해도 서버에 저장된 실제 값을 모르면 404) -> ci에서 e2e 테스트가 무조건 터짐

그래서 현재 2안으로 수정해 둔 상태, 근본적인 해결 방법 찾을 필요 있음...

Summary by CodeRabbit

  • 새로운 기능

    • 홈에 가로 스크롤형 게임 섹션 추가 — 썸네일, 제목, 문제 수 배지, 공유 배지 및 카드 클릭 시 미리보기 지원
    • 게임 카드 로딩용 스켈레톤 UI 추가
  • 접근성

    • “게임 더 보기” 조작을 버튼에서 링크로 변경하여 역할 해석 개선
  • 리팩토링

    • 홈 페이지 렌더링 구조 단순화(인증/에러 경계 제거)
  • 버그 수정/안정성

    • API 클라이언트 동작 개선으로 세션 만료 처리 및 개발시 요청/응답 로깅 향상

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Dec 22, 2025

Walkthrough

GameSection 위젯을 제거하고 RSC(GameSection)와 클라이언트 컴포넌트(GameSectionClient)로 분리된 새 구현을 추가했으며, GameCard 관련 import 경로 정리, 홈 페이지 간소화, Playwright 테스트 헬퍼 추가, MSW 초기화 조건 변경, CI env 블록화 및 fetchClient에 ky 기반 훅/에러 처리 도입이 포함됩니다.

Changes

Cohort / File(s) 변경 요약
GameSection 새 컴포넌트
service/app/src/app/_components/GameSection/GameSection.tsx, service/app/src/app/_components/GameSection/GameSectionClient.tsx, service/app/src/app/_components/GameSection/GameSectionHeader.tsx, service/app/src/app/_components/GameSection/GameSectionSkeleton.tsx
GameSection을 RSC로 데이터 페칭(getDefaultGame)하고, 카드 렌더링/상호작용을 클라이언트 컴포넌트로 분리해 새 경로로 추가
기존 위젯 제거
service/app/src/widgets/GameSection.tsx
기존 GameSection 위젯 파일 전체 삭제(헤더, 카드 섹션, 오버레이/미리보기, 게임 시작 네비게이션 등 제거)
GameCard 스켈레톤 추가
service/app/src/entities/game/ui/GameCard/GameCardSkeleton.tsx
게임 카드 로딩 스켈레톤 컴포넌트 추가
임포트 경로 정리 (GameCard 등)
service/app/src/app/dashboard/components/dashboardGameSection.tsx, service/app/src/app/games/components/gamesLibrarySection.tsx, service/app/src/entities/game/ui/gameLibraryGrid.tsx, service/app/src/entities/game/ui/gamePreview.tsx, service/app/src/entities/game/hooks/useGamePreview.tsx
GameCard 및 관련 모듈 import 경로를 shared/...에서 entities/game/ui/... 등으로 업데이트
컴포넌트 인덱스 재내보내기 변경
service/app/src/entities/game/ui/components/index.ts
GameLibraryGrid의 재내보내기 제거
홈 페이지 구조 단순화
service/app/src/app/page.tsx
ErrorBoundary·인증 분기 제거, GameSection/HeroSection 경로 업데이트 및 Home 컴포넌트 간소화, export const dynamic = "force-dynamic" 추가
테스트 셀렉터 / Playwright 헬퍼
service/app/src/app/__tests__/homePOM.ts, service/app/src/app/__tests__/helpers/log.setup.ts
"게임 더 보기" 셀렉터 버튼→링크로 변경 및 브라우저 콘솔/오류/네트워크 로그를 붙이는 Playwright 헬퍼 추가
MSW 초기화 흐름 변경
service/app/src/mocks/mswProvider.tsx
shouldInitMsw 도입, 초기화 의존성 업데이트([shouldInitMsw]) 및 isMswReady 기반 렌더 가드 추가
fetchClient 및 CI 환경 변경
.github/workflows/ci.yml, service/app/src/shared/api/fetchClient.ts
CI 빌드 스텝 env 블록화(NEXT_PUBLIC_TEST), fetchClient를 ky 인스턴스 기반으로 전환하고 hooks(beforeRequest/afterResponse/beforeError)로 로깅·401 처리·에러 매핑 추가

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Browser as Browser (Client)
  participant HomeRSC as Home Page (RSC)
  participant API as getDefaultGame API
  participant ClientComp as GameSectionClient
  participant Preview as GamePreview Overlay

  HomeRSC->>API: getDefaultGame({ cache: "force-cache" })
  API-->>HomeRSC: games 데이터 반환
  HomeRSC-->>Browser: 섹션 HTML (헤더 + Suspense placeholder)
  Browser->>ClientComp: mount with props(games)
  ClientComp->>ClientComp: 카드 렌더링 & 이벤트 바인딩
  Browser->>ClientComp: 사용자가 카드 클릭
  ClientComp->>Preview: useGamePreview → 미리보기 오픈
  Preview-->>ClientComp: 미리보기 상태/종료 이벤트
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • 추가로 주의할 파일/영역:
    • service/app/src/widgets/GameSection.tsx 삭제로 인한 기존 오버레이/게임 시작 흐름과 새 구현 간 동작/접근성 일치 여부
    • service/app/src/shared/api/fetchClient.ts의 ky hooks(401 처리, 에러 매핑)가 현재 인증/세션 로직과 호환되는지 검증
    • 광범위한 import 경로 변경으로 인한 누락된 참조나 빌드/타입 오류 여부
    • Playwright 셀렉터(homePOM.ts)가 실제 DOM(role link vs button)과 일치하는지 E2E 확인

Possibly related PRs

Suggested labels

✨feature, 👩🏻‍💻frontend

Suggested reviewers

  • whdgur5717

Poem

🐇 새 섹션 왔네, 깡충깡충 뛴다,
서버 불러오면 클라가 반짝인다,
임포트 길도 정리돼 발걸음 가볍고,
로그 달고 에러 잡아 단단히,
당근처럼 달콤한 배포 축하해요 🥕🎮

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed 제목은 PR의 주요 변경 사항인 '홈페이지 컴포넌트를 server/client 역할에 맞게 분리'를 충분히 설명하고 있습니다.
Description check ✅ Passed 풀 리퀘스트 설명이 템플릿 구조를 따르고 있으며, 주요 변경 사항과 리뷰 시 고려사항이 명시되어 있습니다.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix-homepage

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link

테스트 실패

테스트가 실패했습니다. Actions 로그를 확인해주세요.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (2)
service/app/src/app/_components/GameSection/GameSectionClient.tsx (1)

19-19: 불필요한 옵셔널 체이닝

Line 19에서 games?.map을 사용하고 있지만, GameSectionClientProps 인터페이스에서 gamesGameListItem[]로 정의되어 있어 non-nullable입니다. 옵셔널 체이닝은 불필요하며, games가 undefined인 경우 TypeScript 타입 시스템이 컴파일 타임에 오류를 발생시켜야 합니다.

옵셔널 체이닝을 제거하고 games.map을 사용하는 것이 타입 안정성 측면에서 더 명확합니다.

🔎 제안된 수정
-    {games?.map((game) => (
+    {games.map((game) => (
service/app/src/app/_components/GameSection/GameSection.tsx (1)

19-19: className 병합에 cn() 유틸리티 사용 권장

템플릿 리터럴로 className을 연결하는 것보다 cn() 유틸리티(clsx 또는 tailwind-merge 기반)를 사용하는 것이 더 안전합니다. cn()은 중복 클래스를 제거하고 조건부 클래스를 더 깔끔하게 처리합니다.

🔎 제안된 수정
+import { cn } from "@/shared/lib/utils" // 또는 적절한 경로

-  className={`flex w-full flex-col items-center justify-center self-stretch p-0 ${className}`}
+  className={cn("flex w-full flex-col items-center justify-center self-stretch p-0", className)}
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4bfbb68 and 9fe28da.

📒 Files selected for processing (18)
  • service/app/src/app/__tests__/homePOM.ts
  • service/app/src/app/_components/GameSection/GameSection.tsx
  • service/app/src/app/_components/GameSection/GameSectionClient.tsx
  • service/app/src/app/_components/GameSection/GameSectionHeader.tsx
  • service/app/src/app/_components/GameSection/GameSectionSkeleton.tsx
  • service/app/src/app/_components/HeroSection.tsx
  • service/app/src/app/dashboard/components/dashboardGameSection.tsx
  • service/app/src/app/games/components/gamesLibrarySection.tsx
  • service/app/src/app/page.tsx
  • service/app/src/entities/game/hooks/useGamePreview.tsx
  • service/app/src/entities/game/ui/GameCard/GameCardSkeleton.tsx
  • service/app/src/entities/game/ui/GameCard/gameCard.tsx
  • service/app/src/entities/game/ui/components/index.ts
  • service/app/src/entities/game/ui/gameCardOptions.tsx
  • service/app/src/entities/game/ui/gameLibraryGrid.tsx
  • service/app/src/entities/game/ui/gameLibrarySkeleton.tsx
  • service/app/src/entities/game/ui/gamePreview.tsx
  • service/app/src/widgets/GameSection.tsx
💤 Files with no reviewable changes (2)
  • service/app/src/entities/game/ui/components/index.ts
  • service/app/src/widgets/GameSection.tsx
🧰 Additional context used
📓 Path-based instructions (9)
**/*

📄 CodeRabbit inference engine (CLAUDE.md)

All file names must be camelCase (not PascalCase or kebab-case)

Files:

  • service/app/src/app/_components/GameSection/GameSectionHeader.tsx
  • service/app/src/app/_components/GameSection/GameSectionSkeleton.tsx
  • service/app/src/app/games/components/gamesLibrarySection.tsx
  • service/app/src/app/_components/GameSection/GameSectionClient.tsx
  • service/app/src/entities/game/ui/gameLibraryGrid.tsx
  • service/app/src/entities/game/ui/GameCard/GameCardSkeleton.tsx
  • service/app/src/entities/game/hooks/useGamePreview.tsx
  • service/app/src/app/dashboard/components/dashboardGameSection.tsx
  • service/app/src/app/__tests__/homePOM.ts
  • service/app/src/app/_components/GameSection/GameSection.tsx
  • service/app/src/entities/game/ui/gamePreview.tsx
  • service/app/src/app/page.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Component names must use PascalCase in the code (while file names use camelCase)
Use Zustand for client-side state management
Use TanStack Query for server state and API caching
Use async/await for promises instead of .then() chains
Use custom fetch client with interceptors from shared/lib/fetchClient.ts for API requests

**/*.{ts,tsx}: Use TypeScript with ES modules; keep files lower-case kebab or camel per existing folder conventions (e.g., gameLibraryGrid.tsx)
Favor explicit domain names (e.g., GameCardOptions, useInfiniteMyGames) and colocate UI, API, and hooks within each entities/<domain> module
Run ESLint using lint scripts; linting is enforced via lint-staged

Files:

  • service/app/src/app/_components/GameSection/GameSectionHeader.tsx
  • service/app/src/app/_components/GameSection/GameSectionSkeleton.tsx
  • service/app/src/app/games/components/gamesLibrarySection.tsx
  • service/app/src/app/_components/GameSection/GameSectionClient.tsx
  • service/app/src/entities/game/ui/gameLibraryGrid.tsx
  • service/app/src/entities/game/ui/GameCard/GameCardSkeleton.tsx
  • service/app/src/entities/game/hooks/useGamePreview.tsx
  • service/app/src/app/dashboard/components/dashboardGameSection.tsx
  • service/app/src/app/__tests__/homePOM.ts
  • service/app/src/app/_components/GameSection/GameSection.tsx
  • service/app/src/entities/game/ui/gamePreview.tsx
  • service/app/src/app/page.tsx
**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use shared ESLint configuration across all workspaces

Files:

  • service/app/src/app/_components/GameSection/GameSectionHeader.tsx
  • service/app/src/app/_components/GameSection/GameSectionSkeleton.tsx
  • service/app/src/app/games/components/gamesLibrarySection.tsx
  • service/app/src/app/_components/GameSection/GameSectionClient.tsx
  • service/app/src/entities/game/ui/gameLibraryGrid.tsx
  • service/app/src/entities/game/ui/GameCard/GameCardSkeleton.tsx
  • service/app/src/entities/game/hooks/useGamePreview.tsx
  • service/app/src/app/dashboard/components/dashboardGameSection.tsx
  • service/app/src/app/__tests__/homePOM.ts
  • service/app/src/app/_components/GameSection/GameSection.tsx
  • service/app/src/entities/game/ui/gamePreview.tsx
  • service/app/src/app/page.tsx
**/*.{js,ts,jsx,tsx,css}

📄 CodeRabbit inference engine (CLAUDE.md)

Use Prettier with Tailwind CSS plugin for formatting

Files:

  • service/app/src/app/_components/GameSection/GameSectionHeader.tsx
  • service/app/src/app/_components/GameSection/GameSectionSkeleton.tsx
  • service/app/src/app/games/components/gamesLibrarySection.tsx
  • service/app/src/app/_components/GameSection/GameSectionClient.tsx
  • service/app/src/entities/game/ui/gameLibraryGrid.tsx
  • service/app/src/entities/game/ui/GameCard/GameCardSkeleton.tsx
  • service/app/src/entities/game/hooks/useGamePreview.tsx
  • service/app/src/app/dashboard/components/dashboardGameSection.tsx
  • service/app/src/app/__tests__/homePOM.ts
  • service/app/src/app/_components/GameSection/GameSection.tsx
  • service/app/src/entities/game/ui/gamePreview.tsx
  • service/app/src/app/page.tsx
**/*.{ts,tsx,css}

📄 CodeRabbit inference engine (AGENTS.md)

Use 2-space indentation throughout the codebase

Files:

  • service/app/src/app/_components/GameSection/GameSectionHeader.tsx
  • service/app/src/app/_components/GameSection/GameSectionSkeleton.tsx
  • service/app/src/app/games/components/gamesLibrarySection.tsx
  • service/app/src/app/_components/GameSection/GameSectionClient.tsx
  • service/app/src/entities/game/ui/gameLibraryGrid.tsx
  • service/app/src/entities/game/ui/GameCard/GameCardSkeleton.tsx
  • service/app/src/entities/game/hooks/useGamePreview.tsx
  • service/app/src/app/dashboard/components/dashboardGameSection.tsx
  • service/app/src/app/__tests__/homePOM.ts
  • service/app/src/app/_components/GameSection/GameSection.tsx
  • service/app/src/entities/game/ui/gamePreview.tsx
  • service/app/src/app/page.tsx
**/*.{ts,tsx,css,json,md}

📄 CodeRabbit inference engine (AGENTS.md)

Apply Prettier formatting using yarn workspace <pkg> format; this is enforced via lint-staged

Files:

  • service/app/src/app/_components/GameSection/GameSectionHeader.tsx
  • service/app/src/app/_components/GameSection/GameSectionSkeleton.tsx
  • service/app/src/app/games/components/gamesLibrarySection.tsx
  • service/app/src/app/_components/GameSection/GameSectionClient.tsx
  • service/app/src/entities/game/ui/gameLibraryGrid.tsx
  • service/app/src/entities/game/ui/GameCard/GameCardSkeleton.tsx
  • service/app/src/entities/game/hooks/useGamePreview.tsx
  • service/app/src/app/dashboard/components/dashboardGameSection.tsx
  • service/app/src/app/__tests__/homePOM.ts
  • service/app/src/app/_components/GameSection/GameSection.tsx
  • service/app/src/entities/game/ui/gamePreview.tsx
  • service/app/src/app/page.tsx
**/src/app/**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

In the Next.js app workspace, UI routes live in src/app

Files:

  • service/app/src/app/_components/GameSection/GameSectionHeader.tsx
  • service/app/src/app/_components/GameSection/GameSectionSkeleton.tsx
  • service/app/src/app/games/components/gamesLibrarySection.tsx
  • service/app/src/app/_components/GameSection/GameSectionClient.tsx
  • service/app/src/app/dashboard/components/dashboardGameSection.tsx
  • service/app/src/app/_components/GameSection/GameSection.tsx
  • service/app/src/app/page.tsx
**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

Tailwind CSS utilities should be ordered via the Prettier Tailwind plugin; avoid inline style objects unless necessary

Files:

  • service/app/src/app/_components/GameSection/GameSectionHeader.tsx
  • service/app/src/app/_components/GameSection/GameSectionSkeleton.tsx
  • service/app/src/app/games/components/gamesLibrarySection.tsx
  • service/app/src/app/_components/GameSection/GameSectionClient.tsx
  • service/app/src/entities/game/ui/gameLibraryGrid.tsx
  • service/app/src/entities/game/ui/GameCard/GameCardSkeleton.tsx
  • service/app/src/entities/game/hooks/useGamePreview.tsx
  • service/app/src/app/dashboard/components/dashboardGameSection.tsx
  • service/app/src/app/_components/GameSection/GameSection.tsx
  • service/app/src/entities/game/ui/gamePreview.tsx
  • service/app/src/app/page.tsx
**/src/entities/**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

In the Next.js app workspace, place feature logic under src/entities and colocate Vitest specs in feature folders

Files:

  • service/app/src/entities/game/ui/gameLibraryGrid.tsx
  • service/app/src/entities/game/ui/GameCard/GameCardSkeleton.tsx
  • service/app/src/entities/game/hooks/useGamePreview.tsx
  • service/app/src/entities/game/ui/gamePreview.tsx
🧠 Learnings (5)
📚 Learning: 2025-11-27T13:46:12.950Z
Learnt from: CR
Repo: JECT-Study/JECT-5-FE PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-27T13:46:12.950Z
Learning: Applies to **/*.{ts,tsx} : Favor explicit domain names (e.g., `GameCardOptions`, `useInfiniteMyGames`) and colocate UI, API, and hooks within each `entities/<domain>` module

Applied to files:

  • service/app/src/app/_components/GameSection/GameSectionHeader.tsx
  • service/app/src/app/games/components/gamesLibrarySection.tsx
  • service/app/src/app/_components/GameSection/GameSectionClient.tsx
  • service/app/src/entities/game/ui/gameLibraryGrid.tsx
  • service/app/src/entities/game/ui/GameCard/GameCardSkeleton.tsx
  • service/app/src/entities/game/hooks/useGamePreview.tsx
  • service/app/src/app/dashboard/components/dashboardGameSection.tsx
  • service/app/src/app/__tests__/homePOM.ts
  • service/app/src/entities/game/ui/gamePreview.tsx
  • service/app/src/app/page.tsx
📚 Learning: 2025-11-27T13:46:12.950Z
Learnt from: CR
Repo: JECT-Study/JECT-5-FE PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-27T13:46:12.950Z
Learning: Applies to **/*.{ts,tsx} : Use TypeScript with ES modules; keep files lower-case kebab or camel per existing folder conventions (e.g., `gameLibraryGrid.tsx`)

Applied to files:

  • service/app/src/app/games/components/gamesLibrarySection.tsx
  • service/app/src/entities/game/ui/gameLibraryGrid.tsx
📚 Learning: 2025-11-27T13:45:59.426Z
Learnt from: CR
Repo: JECT-Study/JECT-5-FE PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-27T13:45:59.426Z
Learning: Applies to entities/*/api/**/*.{ts,tsx} : Organize API functions by entity in entities/*/api/

Applied to files:

  • service/app/src/app/games/components/gamesLibrarySection.tsx
📚 Learning: 2025-11-27T13:46:12.950Z
Learnt from: CR
Repo: JECT-Study/JECT-5-FE PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-27T13:46:12.950Z
Learning: Applies to **/src/components/**/*.{ts,tsx} : In `shared/design` package, define reusable UI components in `src/components` and use them in the app workspace instead of redefining widgets

Applied to files:

  • service/app/src/app/dashboard/components/dashboardGameSection.tsx
📚 Learning: 2025-11-27T13:46:12.950Z
Learnt from: CR
Repo: JECT-Study/JECT-5-FE PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-27T13:46:12.950Z
Learning: Applies to **/src/icons/**/*.{ts,tsx} : In `shared/design` package, define reusable icons in `src/icons` and import from this shared package instead of duplicating icon definitions

Applied to files:

  • service/app/src/app/dashboard/components/dashboardGameSection.tsx
🧬 Code graph analysis (5)
service/app/src/app/_components/GameSection/GameSectionHeader.tsx (1)
shared/design/src/components/button/primaryBoxButton.tsx (1)
  • PrimaryBoxButton (53-66)
service/app/src/app/_components/GameSection/GameSectionSkeleton.tsx (1)
service/app/src/entities/game/ui/GameCard/GameCardSkeleton.tsx (1)
  • GameCardSkeleton (1-8)
service/app/src/app/_components/GameSection/GameSectionClient.tsx (2)
service/app/src/entities/game/hooks/useGamePreview.tsx (1)
  • useGamePreview (17-56)
shared/design/src/components/gameCard/index.tsx (1)
  • GameCard (104-109)
service/app/src/app/_components/GameSection/GameSection.tsx (4)
service/app/src/entities/game/api/getDefaultGame.ts (1)
  • getDefaultGame (5-10)
service/app/src/app/_components/GameSection/GameSectionHeader.tsx (1)
  • GameSectionHeader (4-15)
service/app/src/app/_components/GameSection/GameSectionSkeleton.tsx (1)
  • GameSectionSkeleton (3-11)
service/app/src/app/_components/GameSection/GameSectionClient.tsx (1)
  • GameSectionClient (11-45)
service/app/src/app/page.tsx (1)
service/app/src/widgets/HomeNavigation.tsx (1)
  • HomeNavigation (13-21)
⏰ 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: ci
🔇 Additional comments (8)
service/app/src/entities/game/ui/gamePreview.tsx (1)

15-15: 임포트 경로 업데이트 확인 완료

공유 경로에서 엔티티 기반 경로로 GameCard 임포트를 업데이트하여 코딩 가이드라인에 맞게 UI를 entities/<domain> 모듈 내에 배치했습니다.

service/app/src/app/games/components/gamesLibrarySection.tsx (1)

8-9: 임포트 경로 마이그레이션 정상 처리됨

GameCardGameLibrarySkeleton을 엔티티 기반 경로로 업데이트하여 새로운 프로젝트 구조에 맞게 정리되었습니다.

service/app/src/entities/game/ui/gameLibraryGrid.tsx (1)

10-12: 임포트 경로 정상 업데이트됨

엔티티 기반 구조에 맞게 GameCard 임포트를 업데이트하고, 상대 경로 깊이를 조정하여 리팩토링된 파일 구조를 반영했습니다.

service/app/src/entities/game/hooks/useGamePreview.tsx (1)

9-9: 임포트 경로 간소화 확인

GamePreview 컴포넌트가 ui/ 디렉토리로 이동하여 경로가 단순화되었습니다.

service/app/src/app/__tests__/homePOM.ts (1)

61-63: 테스트 셀렉터 업데이트 정상 반영됨

UI 변경에 맞춰 "게임 더 보기" 컨트롤이 버튼에서 링크로 변경된 것을 테스트 셀렉터에 정확히 반영했습니다.

service/app/src/app/dashboard/components/dashboardGameSection.tsx (1)

8-10: 대시보드 컴포넌트 임포트 경로 업데이트 완료

게임 관련 UI 컴포넌트들을 엔티티 기반 경로로 일관성 있게 업데이트했습니다.

service/app/src/app/page.tsx (1)

1-13: 홈 페이지 구조 단순화 확인

홈 페이지 컴포넌트의 구조 단순화가 일관되게 적용되었습니다:

  • ErrorBoundary 래퍼 제거 (page.tsx, layout.tsx 모두에서)
  • HomeNavigation 컴포넌트의 isLoggedIn prop 제거 (현재 className 만 수용)
  • 인증 기반 조건부 로직 완전 제거
  • 컴포넌트 임포트 경로 올바르게 업데이트

변경사항이 의도적이며 일관되게 적용되었습니다. 에러 처리는 Next.js의 error.tsx 패턴이나 상위 Providers 컴포넌트 레벨에서 처리되도록 설계되었습니다.

service/app/src/app/_components/GameSection/GameSectionClient.tsx (1)

20-42: 구현이 적절합니다

게임 카드 렌더링 로직이 올바르게 구현되었습니다. GameCard 컴포지트 컴포넌트 사용, 접근성 속성 추가, 이미지 최적화(placeholder, blur) 등이 적절하게 적용되었습니다.

Comment on lines +1 to +29
import { Suspense } from "react"

import { getDefaultGame } from "@/entities/game/api/getDefaultGame"

import { GameSectionClient } from "./GameSectionClient"
import { GameSectionHeader } from "./GameSectionHeader"
import { GameSectionSkeleton } from "./GameSectionSkeleton"

interface GameSectionProps {
className?: string
}

export const GameSection = async ({ className = "" }: GameSectionProps) => {
const response = await getDefaultGame({ cache: "force-cache" })
const games = response.data.games

return (
<section
className={`flex w-full flex-col items-center justify-center self-stretch p-0 ${className}`}
>
<div className="flex min-w-[952px] flex-col gap-28">
<GameSectionHeader />
<Suspense fallback={<GameSectionSkeleton />}>
<GameSectionClient games={games} />
</Suspense>
</div>
</section>
)
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

파일명 규칙 위반

코딩 가이드라인에 따르면 모든 파일명은 camelCase를 사용해야 하지만, 이 파일은 PascalCase(GameSection.tsx)를 사용하고 있습니다. gameSection.tsx로 변경해야 합니다.

코딩 가이드라인 기준

🤖 Prompt for AI Agents
In service/app/src/app/_components/GameSection/GameSection.tsx around lines 1 to
29, the filename uses PascalCase (GameSection.tsx) which violates the project's
camelCase file naming convention; rename the file to gameSection.tsx and update
any imports/exports that reference the old filename (search the repo for
"GameSection" imports and change them to "gameSection"), verify
TypeScript/ESLint build passes, and ensure any path-sensitive references (tests,
storybook, index files) are updated accordingly.

Comment on lines +23 to +25
<Suspense fallback={<GameSectionSkeleton />}>
<GameSectionClient games={games} />
</Suspense>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Suspense 경계가 효과가 없습니다

Line 14에서 getDefaultGame을 호출하고 await한 후, 이미 해결된 데이터를 Line 24에서 GameSectionClient에 props로 전달하고 있습니다. GameSectionClient는 클라이언트 컴포넌트이며 이미 사용 가능한 데이터를 렌더링하기만 하므로 suspend되지 않습니다.

Suspense는 비동기 작업이 진행 중일 때만 fallback을 표시합니다. 현재 구조에서는 데이터가 이미 fetching 완료된 후이므로 GameSectionSkeleton이 표시되지 않습니다.

다음 중 하나를 선택하세요:

  1. 데이터 fetching을 별도의 서버 컴포넌트로 분리하고 해당 컴포넌트를 Suspense로 감싸기
  2. Suspense를 제거하고 로딩 상태를 다른 방식으로 처리하기
🔎 제안된 수정 (옵션 1: 데이터 fetching 분리)

별도의 서버 컴포넌트를 생성:

// GameSectionContent.tsx
import { getDefaultGame } from "@/entities/game/api/getDefaultGame"
import { GameSectionClient } from "./GameSectionClient"

export const GameSectionContent = async () => {
  const response = await getDefaultGame({ cache: "force-cache" })
  const games = response.data.games
  
  return <GameSectionClient games={games} />
}

그런 다음 GameSection에서 사용:

-export const GameSection = async ({ className = "" }: GameSectionProps) => {
-  const response = await getDefaultGame({ cache: "force-cache" })
-  const games = response.data.games
-
+export const GameSection = ({ className = "" }: GameSectionProps) => {
   return (
     <section
       className={`flex w-full flex-col items-center justify-center self-stretch p-0 ${className}`}
     >
       <div className="flex min-w-[952px] flex-col gap-28">
         <GameSectionHeader />
         <Suspense fallback={<GameSectionSkeleton />}>
-          <GameSectionClient games={games} />
+          <GameSectionContent />
         </Suspense>
       </div>
     </section>
   )
 }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In service/app/src/app/_components/GameSection/GameSection.tsx around lines 23
to 25 (and noting getDefaultGame is awaited at line 14), the Suspense boundary
is ineffective because the data is already fetched and passed into the client
component; either move the data fetching into a separate async server component
and render the client inside Suspense, or remove the Suspense and handle loading
state another way. To fix, choose one: (A) create a new server component (e.g.,
GameSectionContent) that calls getDefaultGame and returns <GameSectionClient
games={...} />, then keep Suspense around that server component so the fallback
displays during fetch; or (B) delete the Suspense wrapper here and implement
explicit loading handling inside the client component (or via a prop) since the
data is provided synchronously.

Comment on lines +1 to +45
"use client"

import type { GameListItem } from "@/entities/game"
import { useGamePreview } from "@/entities/game/hooks/useGamePreview"
import * as GameCard from "@/entities/game/ui/GameCard/gameCard"

interface GameSectionClientProps {
games: GameListItem[]
}

export const GameSectionClient = ({ games }: GameSectionClientProps) => {
const { openPreview } = useGamePreview()

return (
<div
className="flex items-center justify-between"
data-testid="game-section-cards"
>
{games?.map((game) => (
<GameCard.Root
key={game.gameId}
className="w-[178px]"
title={game.gameTitle}
onClick={() => openPreview(game)}
aria-label="게임 카드"
tabIndex={0}
>
<GameCard.Image
src={game.gameThumbnailUrl ?? "/checker.svg"}
alt={game.gameTitle}
sizes="178px"
placeholder="blur"
blurDataURL="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNzI3IiBoZWlnaHQ9IjQ1OSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZTVlN2ViIi8+PC9zdmc+"
>
<GameCard.Badge>{game.questionCount}문제</GameCard.Badge>
{game.isShared && (
<GameCard.Badge variant="bottom-left">공유</GameCard.Badge>
)}
</GameCard.Image>
<GameCard.Description>{game.gameTitle}</GameCard.Description>
</GameCard.Root>
))}
</div>
)
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

파일명 규칙 위반

코딩 가이드라인에 따르면 모든 파일명은 camelCase를 사용해야 하지만, 이 파일은 PascalCase(GameSectionClient.tsx)를 사용하고 있습니다. gameSectionClient.tsx로 변경해야 합니다.

코딩 가이드라인 기준

🤖 Prompt for AI Agents
In service/app/src/app/_components/GameSection/GameSectionClient.tsx lines 1-45:
the filename uses PascalCase but your project requires camelCase; rename the
file to gameSectionClient.tsx (use git mv to preserve history), update all
imports and any barrel/index exports that reference GameSectionClient to the new
filename, adjust any export/default names if your linter enforces
filename-export parity, run the TypeScript/ESLint build to find remaining
references and fix them, then commit the rename.

Comment on lines +1 to +15
import { PrimaryBoxButton } from "@ject-5-fe/design/components/button"
import Link from "next/link"

export const GameSectionHeader = () => {
return (
<div className="flex w-full items-center justify-between">
<h2 className="typography-heading-lg-semibold text-text-interactive-secondary">
어떤 게임으로 시작해 볼까요?
</h2>
<PrimaryBoxButton size="md" _style="outline" asChild>
<Link href="/games">게임 더 보기</Link>
</PrimaryBoxButton>
</div>
)
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

파일명 규칙 위반

코딩 가이드라인에 따르면 모든 파일명은 camelCase를 사용해야 하지만, 이 파일은 PascalCase(GameSectionHeader.tsx)를 사용하고 있습니다. gameSectionHeader.tsx로 변경해야 합니다.

컴포넌트 구현은 적절합니다. asChild 패턴을 사용한 Link 래핑이 올바르게 적용되었습니다.

코딩 가이드라인 기준

🤖 Prompt for AI Agents
In service/app/src/app/_components/GameSection/GameSectionHeader.tsx lines 1-15,
the file name violates the camelCase rule; rename the file to
gameSectionHeader.tsx and update all references/imports to the new path. Perform
a git mv to preserve history, update any barrel/index exports or test/storybook
imports that reference the old filename, and ensure TypeScript import paths and
Next.js any-case-sensitive environments reflect the change.

Comment on lines +1 to +11
import { GameCardSkeleton } from "@/entities/game/ui/GameCard/GameCardSkeleton"

export const GameSectionSkeleton = () => {
return (
<div className="flex items-center justify-between">
{Array.from({ length: 4 }).map((_, index) => (
<GameCardSkeleton key={index} />
))}
</div>
)
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

파일 이름 규칙 위반

코딩 가이드라인에 따르면 모든 파일 이름은 camelCase를 사용해야 하지만, 이 파일은 PascalCase를 사용하고 있습니다.

  • 현재: GameSectionSkeleton.tsx
  • 권장: gameSectionSkeleton.tsx

마찬가지로 디렉토리 이름도 GameSection/이 아닌 gameSection/이어야 합니다. 코드베이스의 다른 파일들(예: gamePreview.tsx, gameLibraryGrid.tsx)은 camelCase 규칙을 따르고 있으므로 일관성을 위해 이 파일도 동일한 규칙을 따라야 합니다.

기준 코딩 가이드라인

코딩 가이드라인 명시 사항:

  • **/*: All file names must be camelCase (not PascalCase or kebab-case)
  • **/*.{ts,tsx}: Component names must use PascalCase in the code (while file names use camelCase)
🤖 Prompt for AI Agents
In service/app/src/app/_components/GameSection/GameSectionSkeleton.tsx around
lines 1 to 11, the file and containing directory use PascalCase which violates
the camelCase file naming guideline; rename the file to gameSectionSkeleton.tsx
and the directory to gameSection/, keep the exported component name
GameSectionSkeleton (PascalCase) unchanged in the code, and update all import
paths across the codebase to point to the new
./gameSection/gameSectionSkeleton.tsx location (including barrel/index files and
any tests) so no import breaks occur.

Comment on lines +1 to +8
export const GameCardSkeleton = () => {
return (
<div className="flex w-[178px] flex-col items-start gap-[14px]">
<div className="size-[178px] animate-pulse rounded-[10px] bg-gray-200" />
<div className="h-[46px] w-[178px] animate-pulse rounded bg-gray-200" />
</div>
)
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

파일명 규칙 위반

코딩 가이드라인에 따르면 모든 파일명은 camelCase를 사용해야 하지만, 이 파일은 PascalCase(GameCardSkeleton.tsx)를 사용하고 있습니다. gameCardSkeleton.tsx로 변경해야 합니다.

컴포넌트 구현 자체는 적절합니다. 스켈레톤 UI가 명확하게 정의되어 있고 Tailwind 유틸리티가 올바르게 사용되었습니다.

코딩 가이드라인 기준

🤖 Prompt for AI Agents
In service/app/src/entities/game/ui/GameCard/GameCardSkeleton.tsx lines 1-8: the
file name uses PascalCase which violates the camelCase filename rule; rename the
file to gameCardSkeleton.tsx and update all imports/exports that reference this
path (including any index/barrel files, tests, storybooks, and build configs) to
the new path, keeping the component identifier GameCardSkeleton unchanged; run a
project-wide search to replace old path references, adjust any relative import
casing, and run tests/linter to verify nothing breaks.

@github-actions
Copy link

테스트 실패

테스트가 실패했습니다. Actions 로그를 확인해주세요.

1 similar comment
@github-actions
Copy link

테스트 실패

테스트가 실패했습니다. Actions 로그를 확인해주세요.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
service/app/src/app/__tests__/helpers/log.setup.ts (1)

1-25: 파일명 컨벤션 확인 권장

코딩 가이드라인에 따르면 모든 파일명은 camelCase를 사용해야 합니다. 현재 log.setup.ts는 점(.)으로 구분되어 있는데, 더 엄격하게 준수하려면 logSetup.ts로 변경할 수 있습니다. 다만 .setup.ts는 Playwright에서 널리 사용되는 패턴이므로 현재 형태도 허용 가능합니다.

선택적 개선 사항: 파일명을 camelCase로 변경

파일명을 log.setup.ts에서 logSetup.ts로 변경하여 camelCase 컨벤션을 엄격하게 준수할 수 있습니다.

service/app/src/mocks/mswProvider.tsx (1)

21-37: 선택사항: useEffect 로직을 최적화할 수 있습니다.

현재 로직은 올바르게 동작하지만 다음과 같은 경미한 개선이 가능합니다:

  1. 의존성 배열: shouldInitMsw는 환경 변수 기반 상수로 런타임에 변경되지 않습니다. ESLint exhaustive-deps 규칙을 만족하지만, 실제로는 effect가 한 번만 실행됩니다.

  2. 중복 상태 업데이트: shouldInitMswfalse일 때, isMswReady는 이미 true로 초기화되어 있으므로 라인 28의 setIsMswReady(true) 호출은 불필요합니다.

🔎 최적화된 구현 제안
  useEffect(() => {
    const init = async () => {
      try {
        if (shouldInitMsw) {
          const { initMsw } = await import("./index")
          await initMsw()
+         setIsMswReady(true)
-       }
-       setIsMswReady(true)
+       }
      } catch (error) {
        console.error("Failed to initialize MSW:", error)
        setIsMswError(true)
        setIsMswReady(false)
      }
    }

    init()
+   // shouldInitMsw는 환경 변수 기반으로 런타임에 변경되지 않음
-   }, [shouldInitMsw])
+   // eslint-disable-next-line react-hooks/exhaustive-deps
+   }, [])
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e24be11 and 7164565.

📒 Files selected for processing (2)
  • service/app/src/app/__tests__/helpers/log.setup.ts
  • service/app/src/mocks/mswProvider.tsx
🧰 Additional context used
📓 Path-based instructions (7)
**/*

📄 CodeRabbit inference engine (CLAUDE.md)

All file names must be camelCase (not PascalCase or kebab-case)

Files:

  • service/app/src/app/__tests__/helpers/log.setup.ts
  • service/app/src/mocks/mswProvider.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Component names must use PascalCase in the code (while file names use camelCase)
Use Zustand for client-side state management
Use TanStack Query for server state and API caching
Use async/await for promises instead of .then() chains
Use custom fetch client with interceptors from shared/lib/fetchClient.ts for API requests

**/*.{ts,tsx}: Use TypeScript with ES modules; keep files lower-case kebab or camel per existing folder conventions (e.g., gameLibraryGrid.tsx)
Favor explicit domain names (e.g., GameCardOptions, useInfiniteMyGames) and colocate UI, API, and hooks within each entities/<domain> module
Run ESLint using lint scripts; linting is enforced via lint-staged

Files:

  • service/app/src/app/__tests__/helpers/log.setup.ts
  • service/app/src/mocks/mswProvider.tsx
**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use shared ESLint configuration across all workspaces

Files:

  • service/app/src/app/__tests__/helpers/log.setup.ts
  • service/app/src/mocks/mswProvider.tsx
**/*.{js,ts,jsx,tsx,css}

📄 CodeRabbit inference engine (CLAUDE.md)

Use Prettier with Tailwind CSS plugin for formatting

Files:

  • service/app/src/app/__tests__/helpers/log.setup.ts
  • service/app/src/mocks/mswProvider.tsx
**/*.{ts,tsx,css}

📄 CodeRabbit inference engine (AGENTS.md)

Use 2-space indentation throughout the codebase

Files:

  • service/app/src/app/__tests__/helpers/log.setup.ts
  • service/app/src/mocks/mswProvider.tsx
**/*.{ts,tsx,css,json,md}

📄 CodeRabbit inference engine (AGENTS.md)

Apply Prettier formatting using yarn workspace <pkg> format; this is enforced via lint-staged

Files:

  • service/app/src/app/__tests__/helpers/log.setup.ts
  • service/app/src/mocks/mswProvider.tsx
**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

Tailwind CSS utilities should be ordered via the Prettier Tailwind plugin; avoid inline style objects unless necessary

Files:

  • service/app/src/mocks/mswProvider.tsx
🧠 Learnings (5)
📚 Learning: 2025-11-27T13:45:59.426Z
Learnt from: CR
Repo: JECT-Study/JECT-5-FE PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-27T13:45:59.426Z
Learning: Applies to **/__tests__/**/*.spec.tsx : Use Playwright for E2E testing

Applied to files:

  • service/app/src/app/__tests__/helpers/log.setup.ts
📚 Learning: 2025-11-27T13:45:59.426Z
Learnt from: CR
Repo: JECT-Study/JECT-5-FE PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-27T13:45:59.426Z
Learning: Applies to **/*.test.ts : Use Vitest for unit testing with browser mode using Playwright

Applied to files:

  • service/app/src/app/__tests__/helpers/log.setup.ts
📚 Learning: 2025-11-27T13:46:12.950Z
Learnt from: CR
Repo: JECT-Study/JECT-5-FE PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-27T13:46:12.950Z
Learning: Applies to **/src/app/__tests__/**/*.{spec,test}.{ts,tsx} : In the Next.js app workspace, co-locate Playwright specs in `src/app/__tests__`

Applied to files:

  • service/app/src/app/__tests__/helpers/log.setup.ts
📚 Learning: 2025-11-27T13:45:59.426Z
Learnt from: CR
Repo: JECT-Study/JECT-5-FE PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-27T13:45:59.426Z
Learning: Applies to **/*.{test.ts,msw.config.ts} : Use MSW (Mock Service Worker) for API mocking in development and testing

Applied to files:

  • service/app/src/app/__tests__/helpers/log.setup.ts
  • service/app/src/mocks/mswProvider.tsx
📚 Learning: 2025-11-27T13:46:12.950Z
Learnt from: CR
Repo: JECT-Study/JECT-5-FE PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-27T13:46:12.950Z
Learning: Mock network calls with MSW when running `test:msw`; rely on `fetchClient` interceptors for auth/session coverage

Applied to files:

  • service/app/src/mocks/mswProvider.tsx
⏰ 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: ci
🔇 Additional comments (3)
service/app/src/app/__tests__/helpers/log.setup.ts (1)

3-25: 브라우저 로깅 설정이 잘 구현되었습니다.

Playwright 테스트 디버깅을 위한 브라우저 로그 캡처 기능이 적절하게 구현되었습니다. console, pageerror, requestfailed, response 이벤트를 모두 처리하여 테스트 중 발생하는 문제를 추적하는 데 유용합니다.

service/app/src/mocks/mswProvider.tsx (2)

14-44: MSW 초기화 로직이 올바르게 구현되었습니다.

전체적인 구현이 잘 되어 있습니다:

  • 환경에 따라 MSW 초기화 여부를 적절히 결정합니다.
  • isMswReady 게이팅을 통해 MSW가 준비될 때까지 children 렌더링을 차단합니다.
  • 프로덕션 환경에서는 MSW를 건너뛰고 즉시 렌더링합니다.

한 가지 확인사항: MSW 초기화 실패 시 (라인 29-32) children이 전혀 렌더링되지 않습니다. 이것이 의도된 동작인지 확인하세요. 개발/테스트 환경에서는 적절하지만, 이러한 동작이 예상된 것인지 검증이 필요합니다.

Based on learnings, MSW는 개발 및 테스트 환경에서의 API 모킹에 사용되므로, 초기화 실패 시의 동작이 팀의 개발 워크플로우와 일치하는지 확인하세요.


15-16: NEXT_PUBLIC_TEST 환경 변수의 용도와 설정 방식을 명확히 하세요.

환경 변수 NEXT_PUBLIC_TEST가 코드에서 참조되고 있으나 프로젝트 내 어디에서도 정의되거나 문서화되지 않았습니다. 이 변수가 다음을 충족하는지 확인하세요:

  • 언제 설정되는지 (CI/CD, 로컬 개발 환경 등)
  • 프로젝트의 테스트 전략과 일치하는지
  • .env.test, .env.development 등의 환경 파일에서 명시적으로 정의되었는지
  • test:msw 스크립트 실행 시 올바르게 설정되는지

현재 vitest.msw.config.ts에서 이 변수를 설정하지 않고 있으므로, MSW 초기화는 NODE_ENV !== "production" 조건에만 의존합니다. 이것이 의도한 동작인지 확인하고, 필요시 문서화하거나 리팩토링하세요.

@github-actions
Copy link

테스트 실패

테스트가 실패했습니다. Actions 로그를 확인해주세요.

@github-actions
Copy link

테스트 실패

테스트가 실패했습니다. Actions 로그를 확인해주세요.

@github-actions
Copy link

테스트 실패

테스트가 실패했습니다. Actions 로그를 확인해주세요.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 90dbe26 and bf4d7dc.

📒 Files selected for processing (1)
  • service/app/src/app/page.tsx
🧰 Additional context used
📓 Path-based instructions (8)
**/*

📄 CodeRabbit inference engine (CLAUDE.md)

All file names must be camelCase (not PascalCase or kebab-case)

Files:

  • service/app/src/app/page.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Component names must use PascalCase in the code (while file names use camelCase)
Use Zustand for client-side state management
Use TanStack Query for server state and API caching
Use async/await for promises instead of .then() chains
Use custom fetch client with interceptors from shared/lib/fetchClient.ts for API requests

**/*.{ts,tsx}: Use TypeScript with ES modules; keep files lower-case kebab or camel per existing folder conventions (e.g., gameLibraryGrid.tsx)
Favor explicit domain names (e.g., GameCardOptions, useInfiniteMyGames) and colocate UI, API, and hooks within each entities/<domain> module
Run ESLint using lint scripts; linting is enforced via lint-staged

Files:

  • service/app/src/app/page.tsx
**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use shared ESLint configuration across all workspaces

Files:

  • service/app/src/app/page.tsx
**/*.{js,ts,jsx,tsx,css}

📄 CodeRabbit inference engine (CLAUDE.md)

Use Prettier with Tailwind CSS plugin for formatting

Files:

  • service/app/src/app/page.tsx
**/*.{ts,tsx,css}

📄 CodeRabbit inference engine (AGENTS.md)

Use 2-space indentation throughout the codebase

Files:

  • service/app/src/app/page.tsx
**/*.{ts,tsx,css,json,md}

📄 CodeRabbit inference engine (AGENTS.md)

Apply Prettier formatting using yarn workspace <pkg> format; this is enforced via lint-staged

Files:

  • service/app/src/app/page.tsx
**/src/app/**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

In the Next.js app workspace, UI routes live in src/app

Files:

  • service/app/src/app/page.tsx
**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

Tailwind CSS utilities should be ordered via the Prettier Tailwind plugin; avoid inline style objects unless necessary

Files:

  • service/app/src/app/page.tsx
🧠 Learnings (1)
📚 Learning: 2025-11-27T13:46:12.950Z
Learnt from: CR
Repo: JECT-Study/JECT-5-FE PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-27T13:46:12.950Z
Learning: Applies to **/*.{ts,tsx} : Favor explicit domain names (e.g., `GameCardOptions`, `useInfiniteMyGames`) and colocate UI, API, and hooks within each `entities/<domain>` module

Applied to files:

  • service/app/src/app/page.tsx
🧬 Code graph analysis (1)
service/app/src/app/page.tsx (2)
service/app/src/widgets/HomeNavigation.tsx (1)
  • HomeNavigation (13-21)
service/app/src/app/_components/HeroSection.tsx (1)
  • HeroSection (5-21)
⏰ 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: ci
🔇 Additional comments (2)
service/app/src/app/page.tsx (2)

1-2: LGTM! 새로운 컴포넌트 구조에 맞게 import 경로가 업데이트되었습니다.

리팩토링된 컴포넌트 구조에 맞춰 GameSection과 HeroSection의 import 경로가 @/app/_components/로 적절히 변경되었습니다.


5-13: 컴포넌트 단순화가 적절하고 에러 핸들링이 올바르게 구성되어 있습니다.

Home 컴포넌트의 인증 로직과 ErrorBoundary 제거는 적절한 단순화입니다. 에러 경계 처리는 service/app/src/app/error.tsx의 루트 레벨 에러 바운더리가 담당하고 있으며, 이는 Next.js 13+ 아키텍처에서의 올바른 패턴입니다.

</ErrorBoundary>
)
}
export const dynamic = "force-dynamic"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check page.tsx and GameSection for dynamic data fetching requirements

echo "=== Checking page.tsx content ==="
if [ -f "service/app/src/app/page.tsx" ]; then
  cat -n "service/app/src/app/page.tsx"
else
  echo "File not found"
fi

echo ""
echo "=== Checking GameSection directory ==="
find service/app/src/app/_components -name "*GameSection*" -type f 2>/dev/null | head -20

echo ""
echo "=== Checking GameSection implementation ==="
find service/app/src/app/_components -path "*GameSection*" -type f -name "*.tsx" -o -name "*.ts" 2>/dev/null | head -5

Repository: JECT-Study/JECT-5-FE

Length of output: 1268


🏁 Script executed:

#!/bin/bash
# Check GameSection components for dynamic data patterns

echo "=== GameSection.tsx ==="
cat -n "service/app/src/app/_components/GameSection/GameSection.tsx"

echo ""
echo "=== GameSectionClient.tsx ==="
wc -l "service/app/src/app/_components/GameSection/GameSectionClient.tsx"
head -60 "service/app/src/app/_components/GameSection/GameSectionClient.tsx"

Repository: JECT-Study/JECT-5-FE

Length of output: 2760


force-dynamic 설정을 재검토하세요 - 현재 구조상 불필요합니다.

페이지에 export const dynamic = "force-dynamic"이 설정되어 있지만, GameSection은 이미 cache: "force-cache"로 데이터를 페칭하고 Suspense 경계로 클라이언트 컴포넌트를 적절히 감싸고 있습니다. page.tsx는 동적 함수(cookies, headers, searchParams)를 직접 사용하지 않으므로 force-dynamic이 필요하지 않습니다.

제안:

  • force-dynamic 제거 - Suspense 경계가 비동기 데이터 처리를 올바르게 관리합니다
  • 현재 구조는 Partial Prerendering(PPR)에 이상적이므로 정적 쉘은 캐시되고 동적 부분만 스트리밍됩니다
🤖 Prompt for AI Agents
In service/app/src/app/page.tsx around line 15, remove the unnecessary export
const dynamic = "force-dynamic" since this page does not use dynamic functions
(cookies, headers, searchParams) and GameSection already handles data fetching
with cache: "force-cache" wrapped by Suspense; delete that line so the page can
use the default PPR/static shell behavior and confirm dev build/SSR behaves as
expected.

@github-actions
Copy link

Deploy preview for re-creation ready!

✅ Preview
https://re-creation-5s28hxxzd-whdgur5717s-projects.vercel.app

Built with commit bf4d7dc.
This pull request is being automatically deployed with vercel-action

@kimnamheeee kimnamheeee merged commit 147f2a1 into dev Dec 22, 2025
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants