Skip to content

[Feat] : 포인트 사용 내역 조회 + 포인트/홍보 시스템 통합 (#226)#227

Merged
GulSam00 merged 13 commits into
developfrom
feat/226-pointLogs
May 11, 2026
Merged

[Feat] : 포인트 사용 내역 조회 + 포인트/홍보 시스템 통합 (#226)#227
GulSam00 merged 13 commits into
developfrom
feat/226-pointLogs

Conversation

@GulSam00
Copy link
Copy Markdown
Owner

@GulSam00 GulSam00 commented May 7, 2026

📌 PR 제목

[Feat] : 포인트 사용 내역 조회 + 포인트/홍보 시스템 통합 (#226)

📌 변경 사항

포인트 시스템

  • Supabase point_logs 테이블 설계 및 INSERT 로직 추가
  • GET /api/user/point-logs API 라우트 신규 구현
  • 포인트 증감 RPC 적용 및 /user/point 엔드포인트 통합
  • 포인트 사용 내역 페이지(/info/point-logs) 신규 구현
    • 잔액(balance_after) 표시
    • 양/음수 색상 분기 (획득 emerald / 사용 red)
  • ThumbUpModal에서 사용처 설명 자동 전달 (노래 추천: \${title} - \${artist})

홍보 시스템

  • 홍보 등록/취소에 포인트 RPC 통합 및 취소 확인 모달 추가
  • 홍보 이력 페이지(/info/promotions) 레이아웃 정리
    • 삭제 버튼 위치/크기 개선, 본문 강조 콜아웃 스타일 적용
    • 곡 정보(원문/번역) 전체 렌더링
  • PromotionBanner 디자인 개선
    • 곡 정보 가로 배치 + 원문/번역 동시 표시
    • nickname 배지 + content 본문 형태로 정리
    • 배경 불투명화, 노출 시간 5초로 조정

검색 UX

  • 곡 제목/가수 클릭 시 클립보드 복사 (기존 input 자동 입력 동작 제거)
  • 전역 텍스트 드래그/선택 차단 (input/textarea 예외)

기타

  • mutation 후 관련 query 캐시 무효화 누락 보강
  • /info 메뉴 순서 및 라벨 정리
  • sitemap 갱신

💬 추가 참고 사항

@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented May 7, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
singcode Ready Ready Preview, Comment May 11, 2026 0:03am

@GulSam00
Copy link
Copy Markdown
Owner Author

GulSam00 commented May 7, 2026

/describe

@GulSam00
Copy link
Copy Markdown
Owner Author

GulSam00 commented May 7, 2026

/review

@GulSam00
Copy link
Copy Markdown
Owner Author

GulSam00 commented May 7, 2026

/improve

@qodo-code-review
Copy link
Copy Markdown

Review Summary by Qodo

Add point usage history tracking and display feature

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Add point usage history tracking with new point_logs table
• Implement GET /api/user/point-logs endpoint to retrieve user's point logs
• Update PATCH /api/user/spend-point to record point deductions with description
• Create /info/point-logs page displaying point usage history in reverse chronological order
• Add point logs menu card to /info page with History icon
• Integrate TanStack Query hook usePointLogsQuery for client-side data fetching
Diagram
flowchart LR
  A["User spends point"] -->|PATCH /spend-point| B["Update user point"]
  B -->|Insert log| C["point_logs table"]
  D["User navigates to info"] -->|Click point-logs| E["/info/point-logs page"]
  E -->|GET /point-logs| F["Fetch point logs"]
  F -->|Display| G["Point usage history list"]
Loading

Grey Divider

File Changes

1. apps/web/src/app/api/user/point-logs/route.ts ✨ Enhancement +37/-0

Create point logs retrieval API endpoint

• New API endpoint to retrieve authenticated user's point logs
• Queries point_logs table ordered by creation date descending
• Includes SQL schema documentation for required Supabase table
• Returns array of PointLog objects with proper error handling

apps/web/src/app/api/user/point-logs/route.ts


2. apps/web/src/app/api/user/spend-point/route.ts ✨ Enhancement +5/-1

Add point log recording to spend-point endpoint

• Add amount and description parameters to request body
• Insert point log entry when both parameters are provided
• Maintains backward compatibility with existing point deduction logic

apps/web/src/app/api/user/spend-point/route.ts


3. apps/web/src/lib/api/user.ts ✨ Enhancement +11/-1

Add point logs API client function

• Add getUserPointLogs() function to fetch point logs from API
• Update patchUserSpendPoint() signature to include amount and description
• Import new PointLog type for type safety

apps/web/src/lib/api/user.ts


View more (5)
4. apps/web/src/queries/userQuery.ts ✨ Enhancement +16/-2

Add TanStack Query hooks for point logs

• Add usePointLogsQuery hook for fetching point logs with authentication check
• Update usePatchSetPointMutation to accept amount and description parameters
• Invalidate pointLogs query cache on successful point spending

apps/web/src/queries/userQuery.ts


5. apps/web/src/types/pointLog.ts ✨ Enhancement +7/-0

Create PointLog type definition

• Define PointLog interface with id, user_id, description, amount, and created_at fields
• Provides type safety for point log data structures

apps/web/src/types/pointLog.ts


6. apps/web/src/app/info/page.tsx ✨ Enhancement +7/-1

Add point logs menu card to info page

• Import History icon from lucide-react
• Add new menu item for point usage history with description and icon
• Routes to /info/point-logs page

apps/web/src/app/info/page.tsx


7. apps/web/src/app/info/point-logs/page.tsx ✨ Enhancement +58/-0

Create point logs history display page

• New page displaying user's point usage history in reverse chronological order
• Shows point log description, date/time, and amount deducted
• Includes loading state, empty state, and back navigation button
• Displays total count of point logs

apps/web/src/app/info/point-logs/page.tsx


8. apps/web/src/components/ThumbUpModal.tsx ✨ Enhancement +5/-1

Update ThumbUpModal to log point spending

• Update patchSetPoint call to include amount and description parameters
• Auto-generate description with format "노래 추천: ${title} - ${artist}"
• Passes point amount being spent for logging purposes

apps/web/src/components/ThumbUpModal.tsx


Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Copy Markdown

qodo-code-review Bot commented May 7, 2026

Code Review by Qodo

🐞 Bugs (4) 📘 Rule violations (0) 📎 Requirement gaps (2)

Context used

Grey Divider


Action required

1. point_logs insert not enforced 📎 Requirement gap ≡ Correctness
Description
/api/user/spend-point only inserts into point_logs when amount && description are truthy and
it ignores insert errors, so point 차감이 성공해도 로그가 누락될 수 있습니다. This violates the requirement to always
record point spend details on success.
Code

apps/web/src/app/api/user/spend-point/route.ts[R21-23]

+    if (amount && description) {
+      await supabase.from('point_logs').insert({ user_id: userId, amount, description });
+    }
Evidence
The checklist requires that each successful point spend writes a point_logs row with user_id,
amount, and description. The current implementation conditionally inserts and does not
check/throw on insert failure, allowing successful responses without a created log record.

포인트 차감 시 point_logs에 사용 내역이 기록되어야 함 (spend-point API)
apps/web/src/app/api/user/spend-point/route.ts[21-23]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`spend-point`에서 `point_logs` 적재가 조건부(`amount && description`)로 되어 있고, insert 결과의 `error`를 확인하지 않아 로그 누락이 발생할 수 있습니다.
## Issue Context
컴플라이언스 요구사항상 포인트 차감 성공 시마다 `user_id`, `amount`, `description`이 반드시 기록되어야 합니다.
## Fix Focus Areas
- apps/web/src/app/api/user/spend-point/route.ts[10-25]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Client-controlled point balance 🐞 Bug ⛨ Security
Description
PATCH /api/user/spend-point updates users.point using the request body’s point value without any
server-side computation/validation, so an authenticated user can set an arbitrary point balance
(including increasing it). This breaks the integrity of the points system and is inconsistent with
the server-side computation approach used in check-in.
Code

apps/web/src/app/api/user/spend-point/route.ts[1]

Evidence
The spend-point endpoint directly writes the client-provided point into the users table, enabling
point inflation. In contrast, the check-in endpoint fetches the current point from DB and computes
the updated value on the server, which is the safe pattern.

apps/web/src/app/api/user/spend-point/route.ts[9-19]
apps/web/src/app/api/user/check-in/route.ts[12-26]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`PATCH /api/user/spend-point` trusts a client-provided `point` and writes it to `users.point`, allowing any authenticated user to arbitrarily increase their points.
### Issue Context
The check-in route already demonstrates the safer pattern: load current point from DB, then compute the new value server-side.
### Fix (high-level)
- Change the API contract to accept only `amount` (required, positive int) and `description` (required, non-empty string). Do **not** accept an absolute `point` value from the client.
- In the route:
- Fetch the user’s current `point` from `users`.
- Validate `amount > 0` and `currentPoint - amount >= 0`.
- Update `users.point` to `currentPoint - amount`.
### Fix Focus Areas
- apps/web/src/app/api/user/spend-point/route.ts[7-23]
- apps/web/src/app/api/user/check-in/route.ts[12-26]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Point logs cache leak 🐞 Bug ⛨ Security
Description
usePointLogsQuery uses a static React Query key ['pointLogs'] and only gates fetching with
isAuthenticated, so cached logs can persist across logout/login and be shown to a different user on
the same device/session. This is a privacy leak of point usage history.
Code

apps/web/src/queries/userQuery.ts[R51-60]

+export const usePointLogsQuery = (isAuthenticated: boolean) => {
+  return useQuery({
+    queryKey: ['pointLogs'],
+    queryFn: async () => {
+      const response = await getUserPointLogs();
+      if (!response.success) return [];
+      return response.data ?? [];
+    },
+    enabled: isAuthenticated,
+  });
Evidence
React Query caches by queryKey; since the key does not include a user identifier and logout does
not clear the query cache, a subsequent user session can reuse the previous cached data. The
point-logs page renders data ?? [] regardless of authentication state, so stale cached data can be
displayed.

apps/web/src/queries/userQuery.ts[51-60]
apps/web/src/stores/useAuthStore.ts[124-134]
apps/web/src/app/info/point-logs/page.tsx[13-18]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Point logs are cached under a static key and are not cleared on logout, so another user can see the previous user’s cached point logs on shared browsers/devices.
### Fix (high-level)
- Include a stable user identifier in the query key, e.g. `['pointLogs', userId]`.
- That requires `usePointLogsQuery` to accept `userId` (or read it from the user/auth store).
- Additionally (recommended), clear user-scoped queries on logout:
- In the logout flow, call `queryClient.clear()` or `queryClient.removeQueries({ queryKey: ['pointLogs'] })` (and other user-scoped keys as needed).
### Fix Focus Areas
- apps/web/src/queries/userQuery.ts[51-60]
- apps/web/src/stores/useAuthStore.ts[124-134]
- apps/web/src/app/info/point-logs/page.tsx[13-18]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

4. Unbounded point logs fetch 🐞 Bug ➹ Performance ⭐ New
Description
GET /api/user/point-logs가 select('*')로 사용자의 전체 로그를 제한 없이 반환하고, 클라이언트는 이를 그대로 전체 렌더링합니다. 로그가 누적되면
응답/렌더링 성능 저하 및 타임아웃 위험이 커집니다.
Code

apps/web/src/app/api/user/point-logs/route.ts[R22-26]

+    const { data, error } = await supabase
+      .from('point_logs')
+      .select('*')
+      .eq('user_id', userId)
+      .order('created_at', { ascending: false });
Evidence
API는 user_id로 필터링은 하지만 limit/pagination 없이 모든 행을 반환합니다. 페이지는 logs.map(...)으로 전체를 렌더링하므로 데이터가 커질수록
네트워크/JS 렌더 비용이 선형으로 증가합니다.

apps/web/src/app/api/user/point-logs/route.ts[22-26]
apps/web/src/app/info/point-logs/page.tsx[41-53]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`/api/user/point-logs`가 전체 로그를 무제한 반환하고 UI도 전체를 즉시 렌더링해, 장기적으로 성능 문제가 발생합니다.

### Issue Context
현재는 created_at desc 정렬만 존재하며 페이지네이션 파라미터가 없습니다.

### Fix Focus Areas
- apps/web/src/app/api/user/point-logs/route.ts[22-26]
- apps/web/src/app/info/point-logs/page.tsx[41-53]

### Suggested fix
- API에 `limit`(예: 50) 및 `cursor`/`page` 파라미터를 추가하거나 `.range(from,to)` 적용.
- `select('*')` 대신 필요한 컬럼만 select하여 payload 축소.
- UI는 더보기/무한스크롤 또는 가상화(virtualization) 적용.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. point_logs creation only comment 📎 Requirement gap ⚙ Maintainability
Description
The PR only adds a SQL comment for point_logs creation and does not include any migration/DDL
automation, so the required table may be missing at deploy time. If the table/FK/defaults are not
created beforehand, point log insert/read will fail in production.
Code

apps/web/src/app/api/user/point-logs/route.ts[R1-8]

+// Supabase table required:
+// CREATE TABLE point_logs (
+//   id uuid DEFAULT gen_random_uuid() PRIMARY KEY,
+//   user_id uuid REFERENCES auth.users(id) ON DELETE CASCADE,
+//   description text NOT NULL,
+//   amount int NOT NULL,
+//   created_at timestamptz DEFAULT now()
+// );
Evidence
Compliance requires point_logs to exist in Supabase with required columns/constraints, but the PR
change only documents the schema in a comment and does not create/ensure the table exists.

Supabase에 point_logs 테이블이 생성되어 있어야 함
apps/web/src/app/api/user/point-logs/route.ts[1-8]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`point_logs` 테이블이 실제 Supabase에 생성되어 있다는 보장이 코드에 없습니다(주석만 존재).
## Issue Context
배포 환경에서 테이블/제약조건이 누락되면 포인트 사용 내역 기록/조회가 실패합니다.
## Fix Focus Areas
- apps/web/src/app/api/user/point-logs/route.ts[1-8]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Advisory comments

6. Wrong error messages returned 🐞 Bug ◔ Observability ⭐ New
Description
PATCH /api/user/spend-point의 catch 블록이 'like API'/'Failed to post like song' 메시지를 사용해 실제 장애 원인 파악을
방해합니다. point_logs insert 실패 등 새 로직에서 발생하는 에러도 잘못된 메시지로 노출됩니다.
Code

apps/web/src/app/api/user/spend-point/route.ts[R26-27]

  } catch (error) {
    console.error('Error in like API:', error);
Evidence
해당 endpoint는 spend-point인데도 catch에서 like 관련 로그/에러 메시지를 반환합니다. 이 PR로 추가된 point_logs insert 실패도 동일한
catch로 떨어져 잘못된 메시지가 찍히게 됩니다.

apps/web/src/app/api/user/spend-point/route.ts[26-31]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`/api/user/spend-point`의 에러 로그/응답 메시지가 like API로 되어 있어 디버깅을 혼동시킵니다.

### Issue Context
이 PR로 point_logs insert가 추가되면서 해당 경로에서 발생하는 오류도 같은 메시지로 처리됩니다.

### Fix Focus Areas
- apps/web/src/app/api/user/spend-point/route.ts[26-31]

### Suggested fix
- `console.error` 태그와 응답 error 문자열을 spend-point에 맞게 수정.
- 가능하면 auth 에러(`cause==='auth'`)도 401로 분기 처리하여 다른 user route들과 동작을 맞추기.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Previous review results

Review updated until commit aee79dc

Results up to commit aee79dc


🐞 Bugs (2) 📘 Rule violations (0) 📎 Requirement gaps (2)

Context used

Action required
1. point_logs insert not enforced 📎 Requirement gap ≡ Correctness
Description
/api/user/spend-point only inserts into point_logs when amount && description are truthy and
it ignores insert errors, so point 차감이 성공해도 로그가 누락될 수 있습니다. This violates the requirement to always
record point spend details on success.
Code

apps/web/src/app/api/user/spend-point/route.ts[R21-23]

+    if (amount && description) {
+      await supabase.from('point_logs').insert({ user_id: userId, amount, description });
+    }
Evidence
The checklist requires that each successful point spend writes a point_logs row with user_id,
amount, and description. The current implementation conditionally inserts and does not
check/throw on insert failure, allowing successful responses without a created log record.

포인트 차감 시 point_logs에 사용 내역이 기록되어야 함 (spend-point API)
apps/web/src/app/api/user/spend-point/route.ts[21-23]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`spend-point`에서 `point_logs` 적재가 조건부(`amount && description`)로 되어 있고, insert 결과의 `error`를 확인하지 않아 로그 누락이 발생할 수 있습니다.
## Issue Context
컴플라이언스 요구사항상 포인트 차감 성공 시마다 `user_id`, `amount`, `description`이 반드시 기록되어야 합니다.
## Fix Focus Areas
- apps/web/src/app/api/user/spend-point/route.ts[10-25]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Client-controlled point balance 🐞 Bug ⛨ Security
Description
PATCH /api/user/spend-point updates users.point using the request body’s point value without any
server-side computation/validation, so an authenticated user can set an arbitrary point balance
(including increasing it). This breaks the integrity of the points system and is inconsistent with
the server-side computation approach used in check-in.
Code

apps/web/src/app/api/user/spend-point/route.ts[1]

Evidence
The spend-point endpoint directly writes the client-provided point into the users table, enabling
point inflation. In contrast, the check-in endpoint fetches the current point from DB and computes
the updated value on the server, which is the safe pattern.

apps/web/src/app/api/user/spend-point/route.ts[9-19]
apps/web/src/app/api/user/check-in/route.ts[12-26]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`PATCH /api/user/spend-point` trusts a client-provided `point` and writes it to `users.point`, allowing any authenticated user to arbitrarily increase their points.
### Issue Context
The check-in route already demonstrates the safer pattern: load current point from DB, then compute the new value server-side.
### Fix (high-level)
- Change the API contract to accept only `amount` (required, positive int) and `description` (required, non-empty string). Do **not** accept an absolute `point` value from the client.
- In the route:
- Fetch the user’s current `point` from `users`.
- Validate `amount > 0` and `currentPoint - amount >= 0`.
- Update `users.point` to `currentPoint - amount`.
### Fix Focus Areas
- apps/web/src/app/api/user/spend-point/route.ts[7-23]
- apps/web/src/app/api/user/check-in/route.ts[12-26]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Point logs cache leak 🐞 Bug ⛨ Security
Description
usePointLogsQuery uses a static React Query key ['pointLogs'] and only gates fetching with
isAuthenticated, so cached logs can persist across logout/login and be shown to a different user on
the same device/session. This is a privacy leak of point usage history.
Code

apps/web/src/queries/userQuery.ts[R51-60]

+export const usePointLogsQuery = (isAuthenticated: boolean) => {
+  return useQuery({
+    queryKey: ['pointLogs'],
+    queryFn: async () => {
+      const response = await getUserPointLogs();
+      if (!response.success) return [];
+      return response.data ?? [];
+    },
+    enabled: isAuthenticated,
+  });
Evidence
React Query caches by queryKey; since the key does not include a user identifier and logout does
not clear the query cache, a subsequent user session can reuse the previous cached data. The
point-logs page renders data ?? [] regardless of authentication state, so stale cached data can be
displayed.

apps/web/src/queries/userQuery.ts[51-60]
apps/web/src/stores/useAuthStore.ts[124-134]
apps/web/src/app/info/point-logs/page.tsx[13-18]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Point logs are cached under a static key and are not cleared on logout, so another user can see the previous user’s cached point logs on shared browsers/devices.
### Fix (high-level)
- Include a stable user identifier in the query key, e.g. `['pointLogs', userId]`.
- That requires `usePointLogsQuery` to accept `userId` (or read it from the user/auth store).
- Additionally (recommended), clear user-scoped queries on logout:
- In the logout flow, call `queryClient.clear()` or `queryClient.removeQueries({ queryKey: ['pointLogs'] })` (and other user-scoped keys as needed).
### Fix Focus Areas
- apps/web/src/queries/userQuery.ts[51-60]
- apps/web/src/stores/useAuthStore.ts[124-134]
- apps/web/src/app/info/point-logs/page.tsx[13-18]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended
4. point_logs creation only comment 📎 Requirement gap ⚙ Maintainability
Description
The PR only adds a SQL comment for point_logs creation and does not include any migration/DDL
automation, so the required table may be missing at deploy time. If the table/FK/defaults are not
created beforehand, point log insert/read will fail in production.
Code

apps/web/src/app/api/user/point-logs/route.ts[R1-8]

+// Supabase table required:
+// CREATE TABLE point_logs (
+//   id uuid DEFAULT gen_random_uuid() PRIMARY KEY,
+//   user_id uuid REFERENCES auth.users(id) ON DELETE CASCADE,
+//   description text NOT NULL,
+//   amount int NOT NULL,
+//   created_at timestamptz DEFAULT now()
+// );
Evidence
Compliance requires point_logs to exist in Supabase with required columns/constraints, but the PR
change only documents the schema in a comment and does not create/ensure the table exists.

Supabase에 point_logs 테이블이 생성되어 있어야 함
apps/web/src/app/api/user/point-logs/route.ts[1-8]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`point_logs` 테이블이 실제 Supabase에 생성되어 있다는 보장이 코드에 없습니다(주석만 존재).
## Issue Context
배포 환경에서 테이블/제약조건이 누락되면 포인트 사용 내역 기록/조회가 실패합니다.
## Fix Focus Areas
- apps/web/src/app/api/user/point-logs/route.ts[1-8]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Results up to commit aee79dc


🐞 Bugs (2) 📘 Rule violations (0) 📎 Requirement gaps (2)

Context used

Action required
1. point_logs insert not enforced 📎 Requirement gap ≡ Correctness
Description
/api/user/spend-point only inserts into point_logs when amount && description are truthy and
it ignores insert errors, so point 차감이 성공해도 로그가 누락될 수 있습니다. This violates the requirement to always
record point spend details on success.
Code

apps/web/src/app/api/user/spend-point/route.ts[R21-23]

+    if (amount && description) {
+      await supabase.from('point_logs').insert({ user_id: userId, amount, description });
+    }
Evidence
The checklist requires that each successful point spend writes a point_logs row with user_id,
amount, and description. The current implementation conditionally inserts and does not
check/throw on insert failure, allowing successful responses without a created log record.

포인트 차감 시 point_logs에 사용 내역이 기록되어야 함 (spend-point API)
apps/web/src/app/api/user/spend-point/route.ts[21-23]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`spend-point`에서 `point_logs` 적재가 조건부(`amount && description`)로 되어 있고, insert 결과의 `error`를 확인하지 않아 로그 누락이 발생할 수 있습니다.

## Issue Context
컴플라이언스 요구사항상 포인트 차감 성공 시마다 `user_id`, `amount`, `description`이 반드시 기록되어야 합니다.

## Fix Focus Areas
- apps/web/src/app/api/user/spend-point/route.ts[10-25]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Client-controlled point balance 🐞 Bug ⛨ Security
Description
PATCH /api/user/spend-point updates users.point using the request body’s point value without any
server-side computation/validation, so an authenticated user can set an arbitrary point balance
(including increasing it). This breaks the integrity of the points system and is inconsistent with
the server-side computation approach used in check-in.
Code

↗ apps/web/src/app/api/user/spend-point/route.ts

Evidence
The spend-point endpoint directly writes the client-provided point into the users table, enabling
point inflation. In contrast, the check-in endpoint fetches the current point from DB and computes
the updated value on the server, which is the safe pattern.

apps/web/src/app/api/user/spend-point/route.ts[9-19]
apps/web/src/app/api/user/check-in/route.ts[12-26]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`PATCH /api/user/spend-point` trusts a client-provided `point` and writes it to `users.point`, allowing any authenticated user to arbitrarily increase their points.

### Issue Context
The check-in route already demonstrates the safer pattern: load current point from DB, then compute the new value server-side.

### Fix (high-level)
- Change the API contract to accept only `amount` (required, positive int) and `description` (required, non-empty string). Do **not** accept an absolute `point` value from the client.
- In the route:
 - Fetch the user’s current `point` from `users`.
 - Validate `amount > 0` and `currentPoint - amount >= 0`.
 - Update `users.point` to `currentPoint - amount`.

### Fix Focus Areas
- apps/web/src/app/api/user/spend-point/route.ts[7-23]
- apps/web/src/app/api/user/check-in/route.ts[12-26]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Point logs cache leak 🐞 Bug ⛨ Security
Description
usePointLogsQuery uses a static React Query key ['pointLogs'] and only gates fetching with
isAuthenticated, so cached logs can persist across logout/login and be shown to a different user on
the same device/session. This is a privacy leak of point usage history.
Code

apps/web/src/queries/userQuery.ts[R51-60]

+export const usePointLogsQuery = (isAuthenticated: boolean) => {
+  return useQuery({
+    queryKey: ['pointLogs'],
+    queryFn: async () => {
+      const response = await getUserPointLogs();
+      if (!response.success) return [];
+      return response.data ?? [];
+    },
+    enabled: isAuthenticated,
+  });
Evidence
React Query caches by queryKey; since the key does not include a user identifier and logout does
not clear the query cache, a subsequent user session can reuse the previous cached data. The
point-logs page renders data ?? [] regardless of authentication state, so stale cached data can be
displayed.

apps/web/src/queries/userQuery.ts[51-60]
apps/web/src/stores/useAuthStore.ts[124-134]
apps/web/src/app/info/point-logs/page.tsx[13-18]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
Point logs are cached under a static key and are not cleared on logout, so another user can see the previous user’s cached point logs on shared browsers/devices.

### Fix (high-level)
- Include a stable user identifier in the query key, e.g. `['pointLogs', userId]`.
 - That requires `usePointLogsQuery` to accept `userId` (or read it from the user/auth store).
- Additionally (recommended), clear user-scoped queries on logout:
 - In the logout flow, call `queryClient.clear()` or `queryClient.removeQueries({ queryKey: ['pointLogs'] })` (and other user-scoped keys as needed).

### Fix Focus Areas
- apps/web/src/queries/userQuery.ts[51-60]
- apps/web/src/stores/useAuthStore.ts[124-134]
- apps/web/src/app/info/point-logs/page.tsx[13-18]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended
4. point_logs creation only comment 📎 Requirement gap ⚙ Maintainability
Description
The PR only adds a SQL comment for point_logs creation and does not include any migration/DDL
automation, so the required table may be missing at deploy time. If the table/FK/defaults are not
created beforehand, point log insert/read will fail in production.
Code

apps/web/src/app/api/user/point-logs/route.ts[R1-8]

+// Supabase table required:
+// CREATE TABLE point_logs (
+//   id uuid DEFAULT gen_random_uuid() PRIMARY KEY,
+//   user_id uuid REFERENCES auth.users(id) ON DELETE CASCADE,
+//   description text NOT NULL,
+//   amount int NOT NULL,
+//   created_at timestamptz DEFAULT now()
+// );
Evidence
Compliance requires point_logs to exist in Supabase with required columns/constraints, but the PR
change only documents the schema in a comment and does not create/ensure the table exists.

Supabase에 point_logs 테이블이 생성되어 있어야 함
apps/web/src/app/api/user/point-logs/route.ts[1-8]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`point_logs` 테이블이 실제 Supabase에 생성되어 있다는 보장이 코드에 없습니다(주석만 존재).

## Issue Context
배포 환경에서 테이블/제약조건이 누락되면 포인트 사용 내역 기록/조회가 실패합니다.

## Fix Focus Areas
- apps/web/src/app/api/user/point-logs/route.ts[1-8]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Qodo Logo

Comment on lines +21 to +23
if (amount && description) {
await supabase.from('point_logs').insert({ user_id: userId, amount, description });
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

1. point_logs insert not enforced 📎 Requirement gap ≡ Correctness

/api/user/spend-point only inserts into point_logs when amount && description are truthy and
it ignores insert errors, so point 차감이 성공해도 로그가 누락될 수 있습니다. This violates the requirement to always
record point spend details on success.
Agent Prompt
## Issue description
`spend-point`에서 `point_logs` 적재가 조건부(`amount && description`)로 되어 있고, insert 결과의 `error`를 확인하지 않아 로그 누락이 발생할 수 있습니다.

## Issue Context
컴플라이언스 요구사항상 포인트 차감 성공 시마다 `user_id`, `amount`, `description`이 반드시 기록되어야 합니다.

## Fix Focus Areas
- apps/web/src/app/api/user/spend-point/route.ts[10-25]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +51 to +60
export const usePointLogsQuery = (isAuthenticated: boolean) => {
return useQuery({
queryKey: ['pointLogs'],
queryFn: async () => {
const response = await getUserPointLogs();
if (!response.success) return [];
return response.data ?? [];
},
enabled: isAuthenticated,
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

3. Point logs cache leak 🐞 Bug ⛨ Security

usePointLogsQuery uses a static React Query key ['pointLogs'] and only gates fetching with
isAuthenticated, so cached logs can persist across logout/login and be shown to a different user on
the same device/session. This is a privacy leak of point usage history.
Agent Prompt
### Issue description
Point logs are cached under a static key and are not cleared on logout, so another user can see the previous user’s cached point logs on shared browsers/devices.

### Fix (high-level)
- Include a stable user identifier in the query key, e.g. `['pointLogs', userId]`.
  - That requires `usePointLogsQuery` to accept `userId` (or read it from the user/auth store).
- Additionally (recommended), clear user-scoped queries on logout:
  - In the logout flow, call `queryClient.clear()` or `queryClient.removeQueries({ queryKey: ['pointLogs'] })` (and other user-scoped keys as needed).

### Fix Focus Areas
- apps/web/src/queries/userQuery.ts[51-60]
- apps/web/src/stores/useAuthStore.ts[124-134]
- apps/web/src/app/info/point-logs/page.tsx[13-18]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@qodo-code-review
Copy link
Copy Markdown

qodo-code-review Bot commented May 7, 2026

Persistent review updated to latest commit aee79dc

1 similar comment
@qodo-code-review
Copy link
Copy Markdown

qodo-code-review Bot commented May 7, 2026

Persistent review updated to latest commit aee79dc

@qodo-code-review
Copy link
Copy Markdown

qodo-code-review Bot commented May 7, 2026

PR Description updated to latest commit (aee79dc)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
GulSam00 and others added 4 commits May 11, 2026 01:15
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
GulSam00 and others added 5 commits May 11, 2026 01:43
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@GulSam00 GulSam00 changed the title [Feat] : 포인트 사용 내역 조회 기능 추가 (#226) [Feat] : 포인트 사용 내역 조회 + 포인트/홍보 시스템 통합 (#226) May 11, 2026
@GulSam00
Copy link
Copy Markdown
Owner Author

/describe

@GulSam00
Copy link
Copy Markdown
Owner Author

/review

@qodo-code-review
Copy link
Copy Markdown

ⓘ 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.

@GulSam00
Copy link
Copy Markdown
Owner Author

/improve

@qodo-code-review
Copy link
Copy Markdown

ⓘ 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.

1 similar comment
@qodo-code-review
Copy link
Copy Markdown

ⓘ 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.

@GulSam00 GulSam00 merged commit 2d257e4 into develop May 11, 2026
2 checks passed
@GulSam00 GulSam00 deleted the feat/226-pointLogs branch May 11, 2026 16:22
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.

포인트 사용 내역 조회 기능 추가

1 participant