Feat : info 페이지 홍보 신청 이력 확인 및 취소 기능 추가 (#233)#234
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
/describe |
|
/review |
|
/improve |
ⓘ You've reached your Qodo monthly free-tier limit. Reviews pause until next month — upgrade your plan to continue now, or link your paid account if you already have one. |
Code Review by Qodo
Context used✅ Tickets:
🎫 info 페이지 홍보 신청 이력 확인 및 취소 기능 추가 1. Cross-user cache leak
|
Review Summary by QodoAdd user promotion history viewing and cancellation feature
WalkthroughsDescription• Add promotion history viewing and cancellation feature to info page • Implement GET/DELETE APIs for user promotion management with validation • Create promotion history page with status badges and cancellation UI • Add React Query hooks for promotion data fetching and mutations Diagramflowchart LR
A["Info Page"] -->|"Add Menu Card"| B["Promotions Page"]
C["GET /api/user/promotions"] -->|"Fetch History"| B
B -->|"Display with Status"| D["Promotion Items"]
D -->|"Cancel if start_date > today"| E["DELETE /api/user/promotions"]
E -->|"Validate ownership & date"| F["Delete from DB"]
File Changes1. apps/web/src/app/api/user/promotions/route.ts
|
Code Review by Qodo
Context used✅ Tickets:
🎫 info 페이지 홍보 신청 이력 확인 및 취소 기능 추가 1. Cross-user cache leak
|
|
PR Description updated to latest commit (fd4efaf)
ⓘ You are approaching your monthly quota for Qodo. Upgrade your plan |
| export const useUserPromotionsQuery = (enabled: boolean) => { | ||
| return useQuery({ | ||
| queryKey: ['userPromotions'], | ||
| queryFn: async () => { | ||
| const response = await getUserPromotions(); | ||
| if (!response.success) return []; | ||
| return response.data ?? []; | ||
| }, | ||
| enabled, | ||
| staleTime: 1000 * 60, | ||
| }); |
There was a problem hiding this comment.
1. Cross-user cache leak 🐞 Bug ⛨ Security
useUserPromotionsQuery가 queryKey를 ['userPromotions']로 고정하고 staleTime을 1분으로 설정해, 같은 클라이언트 세션에서 계정 전환 시 이전 유저의 홍보 이력이 캐시에서 그대로 재사용될 수 있습니다. 이로 인해 다른 유저의 홍보 신청 이력이 일시적으로 노출될 수 있습니다.
Agent Prompt
## Issue description
`useUserPromotionsQuery` uses a static React Query `queryKey` (`['userPromotions']`). Because the cache key is not user-scoped and the query has a non-zero `staleTime`, cached promotions can be served for a different user after an account switch in the same client session.
## Issue Context
The app has access to the authenticated user's `id` (`User.id`). React Query identifies cached results strictly by `queryKey`.
## Fix Focus Areas
- apps/web/src/queries/userQuery.ts[55-80]
- apps/web/src/app/info/promotions/page.tsx[80-87]
- apps/web/src/stores/useAuthStore.ts[14-30]
## Suggested fix
- Change the hook signature to accept `userId` (or read it inside the hook via the auth store), and scope the key: `queryKey: ['userPromotions', userId]`.
- Gate with `enabled: enabled && !!userId`.
- Update invalidation in `useDeleteUserPromotionMutation` to invalidate the scoped key (or use a partial match that includes the prefix).
- In the page, pass the current `user?.id` (not just `isAuthenticated`).
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| export const useUserPromotionsQuery = (enabled: boolean) => { | ||
| return useQuery({ | ||
| queryKey: ['userPromotions'], | ||
| queryFn: async () => { | ||
| const response = await getUserPromotions(); | ||
| if (!response.success) return []; | ||
| return response.data ?? []; | ||
| }, | ||
| enabled, | ||
| staleTime: 1000 * 60, | ||
| }); |
There was a problem hiding this comment.
1. Cross-user cache leak 🐞 Bug ⛨ Security
useUserPromotionsQuery uses a static queryKey (['userPromotions']) with a 60s staleTime, so a logout→login as a different user within the same SPA session can reuse the previous user’s cached promotions without refetching, exposing another user’s history. This happens because the QueryClient persists for the app lifetime and logout does not clear React Query caches.
Agent Prompt
### Issue description
`useUserPromotionsQuery` caches promotions under a static key (`['userPromotions']`). If a user logs out and another logs in without a full reload, React Query can return the previous user’s cached promotions (still “fresh” due to `staleTime`).
### Issue Context
- QueryClient persists for the SPA lifetime.
- Logout only resets Zustand auth state; it does not clear React Query caches.
### Fix Focus Areas
- Use a user-specific queryKey (e.g. `['userPromotions', userId]`) and enable the query only when `userId` exists.
- Update the delete mutation invalidation to target the same user-scoped key.
- Update `/info/promotions` page to pass `userId` (or derive it inside the hook) instead of only `isAuthenticated`.
- apps/web/src/queries/userQuery.ts[55-80]
- apps/web/src/app/info/promotions/page.tsx[80-86]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
User description
📌 PR 제목
[Feat] : info 페이지 홍보 신청 이력 확인 및 취소 기능 추가
📌 변경 사항
GET /api/user/promotions— 로그인 유저의 홍보 신청 이력 조회 API 추가DELETE /api/user/promotions— 시작 날짜 이전 홍보 취소 API 추가 (소유권 및 날짜 검증 포함)src/lib/api/user.ts—getUserPromotions,deleteUserPromotion함수 추가src/queries/userQuery.ts—useUserPromotionsQuery,useDeleteUserPromotionMutation훅 추가src/app/info/promotions/page.tsx— 홍보 이력 목록 페이지 (상태 배지: 예정/진행중/종료, 시작 전 취소 버튼)src/app/info/page.tsx— 홍보 이력 메뉴 카드 추가 (Megaphone 아이콘)💬 추가 참고 사항
start_date > todayKST(KST 기준, 서버·클라이언트 모두 동일 유틸 사용)user_id일치) 및 시작일 검증 후 삭제PR Type
Enhancement
Description
Add promotion history viewing and cancellation feature for users
Implement GET/DELETE API endpoints for managing song promotions
Create React Query hooks for promotion data fetching and mutations
Add promotions page with status badges and cancellation functionality
Diagram Walkthrough
File Walkthrough
route.ts
API endpoints for promotion history managementapps/web/src/app/api/user/promotions/route.ts
details
violations
user.ts
API client functions for promotionsapps/web/src/lib/api/user.ts
getUserPromotions()function to fetch user's promotion listdeleteUserPromotion(id)function to cancel a promotionSongPromotiontype for type safetyuserQuery.ts
React Query hooks for promotion operationsapps/web/src/queries/userQuery.ts
useUserPromotionsQueryhook with conditional enabling and cachinguseDeleteUserPromotionMutationhook with query invalidationpage.tsx
Add promotions menu card to info pageapps/web/src/app/info/page.tsx
Megaphoneicon from lucide-reactpage.tsx
New promotions history page with cancellation UIapps/web/src/app/info/promotions/page.tsx
PromotionItemcomponent with status badges(pending/active/ended)