Conversation
Walkthrough익명 토큰 저장소를 localStorage에서 sessionStorage로 전환하고, 관련 가드/인터셉터/쿼리 활성화 조건을 수정. Discover 페이지에서 URL 동기화 및 인덱스 기반 선택 로직을 제거하고, 라우트 파라미터 또는 첫 항목 기준으로 재생목록을 직접 선택하도록 초기화 로직을 단순화. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant App as App
participant Auth as AuthStore
participant API as Axios Instance
participant Server as API Server
rect rgba(230,240,255,0.5)
note over App,API: 익명 토큰 세션 스코프 전환
App->>App: sessionStorage.getItem('anonymous_token')
App->>Auth: isLogin 확인
alt not isLogin and no token
App->>Server: 익명 로그인 요청
Server-->>App: anonymous_token
App->>App: sessionStorage.setItem('anonymous_token')
end
API->>API: 요청 인터셉터에서 sessionStorage 토큰 첨부(비로그인 시)
Server-->>API: 응답(필요 시 신규 토큰)
API->>API: sessionStorage.setItem('anonymous_token')
end
sequenceDiagram
autonumber
participant Page as DiscoverPage
participant Router as Router(useParams)
participant Store as Playlist Store
participant Query as Playlists Query
rect rgba(240,255,240,0.5)
note over Page,Store: 인덱스/URL 동기화 제거
Page->>Router: playlistId 파라미터 확인
Page->>Query: 플레이리스트 로드(셔플 포함)
Query-->>Page: playlists
alt currentPlaylist 없음
Page->>Page: playlistId로 find() 또는 첫 항목 선택
Page->>Store: setPlaylist(selected, 0, 0)
Page->>Query: 필요 시 fetchNextPage()
end
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Pre-merge checks (3 passed, 1 warning, 1 inconclusive)❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
Poem
Tip 👮 Agentic pre-merge checks are now available in preview!Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.
Please see the documentation for more information. Example: reviews:
pre_merge_checks:
custom_checks:
- name: "Undocumented Breaking Changes"
mode: "warning"
instructions: |
Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).Please share your feedback with us on this Discord post. ✨ 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. Comment |
There was a problem hiding this comment.
Summary of Changes
Hello @maylh, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!
이 PR은 둘러보기 페이지의 프로그레스 바가 올바르게 작동하지 않던 문제를 해결하고, 익명 사용자 토큰 관리 방식을 개선합니다. 백엔드 요청에 따라 익명 토큰이 세션 내에서 일관되게 유지되도록 저장소 메커니즘을 변경하여, 사용자 경험의 안정성을 높이는 데 중점을 두었습니다.
Highlights
- 둘러보기 프로그레스 바 미작동 오류 해결: 둘러보기 페이지에서 프로그레스 바가 제대로 작동하지 않던 오류를 해결했습니다.
- 익명 토큰 관리 방식 변경: 익명 토큰을
localStorage에서sessionStorage로 관리하도록 변경하여, 새로고침 시에도 동일한 세션 내에서 토큰이 유지되도록 개선했습니다.
Using Gemini Code Assist
The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.
Invoking Gemini
You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.
| Feature | Command | Description |
|---|---|---|
| Code Review | /gemini review |
Performs a code review for the current pull request in its current state. |
| Pull Request Summary | /gemini summary |
Provides a summary of the current pull request in its current state. |
| Comment | @gemini-code-assist | Responds in comments when explicitly tagged, both in issue comments and review comments. |
| Help | /gemini help |
Displays a list of available commands. |
Customization
To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.
Limitations & Feedback
Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.
You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.
Footnotes
-
Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩
|
🎵 Storybook Link 🎵 |
There was a problem hiding this comment.
Code Review
PR의 주요 변경 사항은 익명 토큰 저장 방식을 localStorage에서 sessionStorage로 변경하고, 둘러보기 페이지의 오류를 수정한 것으로 보입니다. 토큰 저장 방식 변경은 일관성 있게 잘 적용되었습니다. 둘러보기 페이지의 경우, useNavigate 등 불필요한 훅과 상태를 제거하여 코드가 간소화된 점은 좋습니다. 다만, 디버깅용 console.log가 남아있고, 플레이리스트 스와이프 시 URL이 동기화되지 않는 동작 변경이 있어 확인이 필요해 보입니다. 자세한 내용은 아래 주석을 참고해주세요.
|
|
||
| // 최초 playlist 초기화 | ||
| useEffect(() => { | ||
| if (playlistsData.length > 0 && isReady) { |
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/entities/playlist/model/usePlaylists.ts (1)
45-50: playlistId 미존재/비정상(NaN) 시 불필요한 API 호출 방지
usePlaylistDetail(Number(playlistId))가NaN을 전달받을 경우/.../NaN호출이 발생할 수 있습니다. 이 훅에서enabled를 추가해 방지하세요.다음 수정으로 안전하게 막을 수 있습니다.
export const usePlaylistDetail = (playlistId: number) => { - return useQuery({ + return useQuery({ queryKey: ['playlistDetail', playlistId], - queryFn: () => getPlaylistDetail(playlistId), + queryFn: () => getPlaylistDetail(playlistId), + enabled: Number.isFinite(playlistId), }) }src/shared/api/instance.ts (1)
60-66: 401 재시도 무한 루프 방지 가드 추가 권장익명 토큰 재발급 후 원요청을 재시도하는데, 다시 401이면 루프가 생길 수 있습니다. 1회만 재시도하도록 플래그를 추가하세요.
- // 원래 요청 재시도 - if (error.config) { - error.config.headers.Authorization = `Bearer ${token}` - return axiosInstance.request(error.config) - } + // 원래 요청 재시도 (한 번만) + if (error.config) { + const cfg = error.config as any + if (!cfg.__anonymousRetried) { + cfg.__anonymousRetried = true + cfg.headers = { ...(cfg.headers ?? {}), Authorization: `Bearer ${token}` } + return axiosInstance.request(cfg) + } + }
🧹 Nitpick comments (5)
src/entities/playlist/model/usePlaylists.ts (1)
41-41: enabled 조건의 반응성 개선 제안
enabled: !!useAuthStore.getState().accessToken || !!sessionStorage.getItem('anonymous_token')는 렌더링 타이밍에만 평가되어 토큰 발급/삭제에 즉시 반응하지 않을 수 있습니다. 스토어 구독 혹은 토큰 갱신 시 쿼리 무효화로 반응성을 확보하는 편이 안전합니다.다음과 같이 accessToken은 구독하고, 익명 토큰은 커스텀 이벤트로 통지하는 방식을 고려해 주세요.
- enabled: !!useAuthStore.getState().accessToken || !!sessionStorage.getItem('anonymous_token'), + const accessToken = useAuthStore((s) => s.accessToken) + const [anonToken, setAnonToken] = useState(sessionStorage.getItem('anonymous_token')) + useEffect(() => { + const onTok = () => setAnonToken(sessionStorage.getItem('anonymous_token')) + window.addEventListener('anonymous-token-updated', onTok) + return () => window.removeEventListener('anonymous-token-updated', onTok) + }, []) + enabled: !!accessToken || !!anonToken,그리고 토큰 세팅 지점(App.tsx, interceptor)에서
window.dispatchEvent(new Event('anonymous-token-updated'))를 호출해 갱신을 통지하면 됩니다.src/pages/discover/index.tsx (3)
99-99: 디버그 로그 제거
console.log는 린트 경고 대상입니다. 필요 시console.warn/console.error로 전환하거나 빌드 플래그로 가드해 주세요.- console.log(playlistsData) + // console.warn('[discover] playlistsData', playlistsData) // 필요 시 개발 모드에서만
88-97: 주석-구현 불일치 정정주석은 “기존에 존재하면 순서를 변경하지 않고 추가”로 읽히지만, 구현은 기존에 있으면 그대로 반환하여 “추가하지 않음”입니다. 혼동을 줄이려면 주석을 코드에 맞게 수정하세요.
- // 기존에 shufflePlaylists에 있는 경우, 순서를 변경하지 않고 추가 + // 기존에 shufflePlaylists에 있는 경우, 중복 추가하지 않고 원본 순서를 유지
121-131: 주석과 주기 불일치(10초 vs 5초)주석은 “10초마다”지만 인터벌은 5000ms입니다. 의도에 맞게 통일하세요.
- // 재생 중일 때 10초마다 refetch - const viewCountTimer = setInterval(() => { + // 재생 중일 때 5초마다 refetch + const viewCountTimer = setInterval(() => {src/App.tsx (1)
42-47: 익명 토큰 발급/보관의 세션 스코프 전환 OK + 후속 통지 제안세션 스토리지로의 전환은 의도와 일치합니다. 추가로 토큰 저장 직후 쿼리들이 반응하도록 커스텀 이벤트를 브로드캐스트하면 UX가 매끄럽습니다.
- sessionStorage.setItem('anonymous_token', response) + sessionStorage.setItem('anonymous_token', response) + window.dispatchEvent(new Event('anonymous-token-updated'))
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
src/App.tsx(2 hunks)src/entities/playlist/model/usePlaylists.ts(1 hunks)src/features/auth/store/authStore.ts(1 hunks)src/pages/discover/index.tsx(5 hunks)src/shared/api/instance.ts(2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js,jsx}
⚙️ CodeRabbit configuration file
**/*.{ts,tsx,js,jsx}: ## 1. 일반적인 코딩 컨벤션포맷팅
.prettierrc설정에 따라 포맷팅 확인- 들여쓰기: 2칸 스페이스
- 최대 줄 길이: 100자
- 세미콜론 사용 안함
- 따옴표: 작은따옴표 사용
- 괄호 안 공백: 있음
- 화살표 함수 괄호: 항상 사용
- 줄바꿈: LF 사용
네이밍 컨벤션
- 컴포넌트: PascalCase (예: UserProfile)
- 유틸리티/훅/변수: camelCase (예: getUserData, useUserInfo)
- 상수: UPPER_SNAKE_CASE (예: API_BASE_URL)
- 이미지 파일: kebab-case (예: user-profile-icon.png)
주석 사용
- 복잡한 로직에만 주석 추가
- 불필요한 주석 지양 (코드로 설명 가능한 것)
- TODO/FIXME 형식:
// TODO: 설명 - 작성자가독성
- 매직 넘버 지양, 의미있는 상수 사용
- 함수는 하나의 책임만 가지도록 작성 (최대 20줄 권장)
- 중첩 깊이 최소화 (3단계 이하 권장)
2. React 모범 사례
컴포넌트 작성
- 최신 React hooks 사용 권장
- 컴포넌트는 단일 책임 원칙 준수
- Presentational/Container 컴포넌트 분리
- 성능 최적화: memo, useCallback, useMemo 적절히 사용
- 대용량 리스트는 가상화 라이브러리 사용 고려
상태 관리
- Zustand와 Tanstack Query를 일관되게 사용
- 상태 구조는 정규화된 형태로 관리
- 에러 처리: Error Boundary와 try-catch 또는 onError 콜백 활용
3. 스타일링
Styled Components
- Styled Components 일관되게 사용
- 스타일드 컴포넌트명은 의미있게 작성
- 동적 스타일링은 props나 CSS 변수 활용
- 테마 시스템 활용하여 글로벌 스타일 관리
- 재사용 가능한 스타일은 mixin이나 확장으로 관리
- CSS 포맷팅 가독성 유지
- 사용하지 않는 스타일이나 중복 스타일 제거
4. Vite 및 빌드 최적화
- 모듈 import 최적화 (tree-shaking 고려)
- 환경변수는 .env 파일로 관리
- vite.config.ts에서 빌드 성능 튜닝 (sourcemap 설정, 플러그인 최적화 등)
5. 아키텍처 및 개발 환경
폴더 구조
- Feature-Sliced Design (FSD) 구조 준수
- 레이어별 참조 규칙 엄격히 적용
타입스크립트
- strict 모드 사용
- 타입 명시적으로 작성 (any 사용 지양)
- path alias (@/_) 절대 경로 import 사용
Git 훅
- Husky 설정으로 pre-commit, commit-msg 린팅 확인
6. 기타 가이드라인
- 충분한 근거와 함께 리뷰 제공
- 정보 검증 후 답변
- 간결하고 명확한 응답
- 필요시 추가 컨텍스트 요청
- 검증되지 않은 주장 지양
- 가능한 경우 출처 명시
- 별도 언급 없으면 JavaScript 기준
- 한국어로 응답
- 대부분 브라우저에서 지원하는 ES6+ 기능 활용
- 코드 리뷰를 통한 유지보수성 향상에 적극 활용
Files:
src/features/auth/store/authStore.tssrc/shared/api/instance.tssrc/App.tsxsrc/entities/playlist/model/usePlaylists.tssrc/pages/discover/index.tsx
🧠 Learnings (2)
📚 Learning: 2025-08-26T16:33:15.938Z
Learnt from: hansololiviakim
PR: dnd-side-project/dnd-13th-8-frontend#65
File: src/App.tsx:32-41
Timestamp: 2025-08-26T16:33:15.938Z
Learning: checkAnonymousLogin 함수에서 useAnonymousLogin의 response는 string 타입으로 고정되어 있으며, 객체가 아닌 토큰 문자열 자체가 반환됩니다.
Applied to files:
src/shared/api/instance.tssrc/App.tsx
📚 Learning: 2025-08-20T05:59:48.729Z
Learnt from: maylh
PR: dnd-side-project/dnd-13th-8-frontend#55
File: src/widgets/playlist/BackgroundPlayer.tsx:55-83
Timestamp: 2025-08-20T05:59:48.729Z
Learning: BackgroundPlayer 컴포넌트에서 네비게이션 후 컨트롤 버튼이 작동하지 않는 버그는 주로 다음 원인들로 발생한다: 1) DOM ID 충돌 (고정값 'yt-player' 사용), 2) window.YT가 이미 존재할 때 새 플레이어를 생성하지 않음, 3) onStateChange 의존성으로 인한 useEffect 재실행과 전역 콜백 덮어쓰기, 4) 리마운트 시 ref 상태 불일치. 해결책으로는 고유 DOM ID 생성, initPlayer 함수 분리를 통한 즉시 초기화, 콜백 ref 사용으로 의존성 최소화, 플레이리스트 변경 시 상태 초기화 등이 필요하다.
Applied to files:
src/pages/discover/index.tsx
🧬 Code graph analysis (1)
src/entities/playlist/model/usePlaylists.ts (1)
src/features/auth/store/authStore.ts (1)
useAuthStore(7-52)
🪛 GitHub Check: Build and Lint
src/pages/discover/index.tsx
[warning] 99-99:
Unexpected console statement. Only these console methods are allowed: warn, error
[warning] 115-115:
React Hook useEffect has a missing dependency: 'isReady'. Either include it or remove the dependency array
🔇 Additional comments (3)
src/features/auth/store/authStore.ts (1)
15-15: 로그인 시 익명 토큰 세션 정리, 방향성 적절로그인 성공 시
sessionStorage.removeItem('anonymous_token')로 세션 단위 토큰을 정리하는 변경이 전체 PR 의도와 일치합니다. 다른 파일들과도 일관됩니다.src/shared/api/instance.ts (1)
19-22: 세션 스토리지로의 전환 일관성 확인요청 인터셉터가 세션 스토리지에서 익명 토큰을 읽도록 바뀐 점은 PR 방향과 일치합니다. 회원/비회원 토큰 헤더 주입도 정상입니다.
src/App.tsx (1)
86-87: 로그인/콜백 경로 진입 시 세션 토큰 제거, 일관성 OK라우팅 기반 정리 로직이 다른 변경들과 잘 맞습니다.
hansololiviakim
left a comment
There was a problem hiding this comment.
오 익명토큰이 세션으로 바꼈군요! 감사합니다!
🛰️ 관련 이슈
✨ 주요 변경 사항
1️⃣ 둘러보기 프로그레스 바 미작동 오류 해결
2️⃣ 익명 토큰 세션 스토리지로 관리하도록 변경
🔍 테스트 방법 / 체크리스트
🗯️ PR 포인트
🚀 알게된 점
📖 참고 자료 (선택)
Summary by CodeRabbit
Refactor
Bug Fixes