Skip to content

feat : 구간 재생 준비 API 연동 - #136

Merged
kim3360 merged 9 commits into
developfrom
feat/135-playback-preparations-api
Aug 2, 2026
Merged

kim3360 merged 9 commits into
developfrom
feat/135-playback-preparations-api

Conversation

@kim3360

@kim3360 kim3360 commented Jul 31, 2026

Copy link
Copy Markdown
Member

변경 내용

  • POST /api/v1/tracks/playback-preparations 구간 재생 준비 API 연동
  • useGetPlaybackPreparations 훅 추가
  • SongDetailPage에서 mock 곡 정보를 API 응답(제목, 아티스트, 앨범 이미지, 재생 시간 등)으로 교체

관련 이슈

Closes #135

변경 사항

  • 새로운 기능 추가
  • 버그 수정
  • UI/UX 개선
  • 리팩토링
  • 문서 업데이트

테스트

  • 브라우저에서 정상 동작 확인
  • 기존 기능에 영향 없음 확인

스크린샷 (UI 변경시)

2026-07-31.10.37.33.mov

체크리스트

  • 코드가 정상적으로 동작합니다
  • 새로운 에러나 경고가 없습니다
  • 필요시 문서를 업데이트했습니다
  • 코드 포맷팅을 실행했습니다 (pnpm format)
  • ESLint 검사를 통과했습니다 (pnpm lint:fix)

코드 품질 확인
PR 제출 전에 다음 명령어를 실행하여 코드 품질을 확인해주세요:

pnpm lint:fix
pnpm format

Summary by CodeRabbit

  • 새로운 기능

    • 장소의 곡을 좋아요로 등록하거나 삭제할 수 있습니다.
    • 좋아요 상태와 개수가 즉시 반영되며, 오류 발생 시 이전 상태로 복구됩니다.
    • 핀에서 곡 상세 화면으로 이동할 수 있습니다.
    • 장소별 곡 상세 정보와 재생 정보를 서버에서 불러옵니다.
    • 곡의 앨범 이미지, 제목, 아티스트, 재생 시간이 실제 정보로 표시됩니다.
  • 개선

    • 상세 화면에서 좋아요 처리 중 중복 요청을 방지합니다.
    • 데이터가 없는 경우 안내 화면을 표시합니다.

@kim3360
kim3360 requested review from JeongGyul, L0521 and onebone July 31, 2026 13:39
@kim3360 kim3360 self-assigned this Jul 31, 2026
@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@kim3360, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 56 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: cf2e250d-2c93-4405-9003-d52b10d51a89

📥 Commits

Reviewing files that changed from the base of the PR and between 7c957e6 and 439ed3a.

📒 Files selected for processing (1)
  • src/features/pin/queries/likedTrackCache.ts
📝 Walkthrough

Walkthrough

트랙 좋아요 등록·삭제, 장소 트랙 상세 조회, 재생 준비 조회 API와 React Query 훅을 추가했습니다. 핀 카드와 상세 화면을 서버 데이터에 연결하고, 곡 상세 화면에 실제 재생 정보를 표시합니다.

Changes

트랙 API 및 핀 기능 연동

Layer / File(s) Summary
트랙 API 계약과 타입
src/features/pin/types.ts, src/api/track.ts
좋아요 변경, 장소 트랙 상세, 재생 준비 응답 타입과 API 함수를 추가했습니다. 재생 준비 요청은 itunesTrackId를 숫자로 변환합니다.
조회 훅과 좋아요 캐시 흐름
src/features/pin/queries/*
상세·재생 준비 조회 훅을 추가했습니다. 좋아요 등록·삭제 mutation은 관련 캐시를 낙관적으로 갱신하고 실패 시 롤백합니다.
장소 트랙 목록과 카드 연동
src/features/pin/components/PinCard.tsx, src/pages/MapPage.tsx
PinCard가 좋아요 등록·삭제와 pending 상태를 처리합니다. 카드 클릭과 키보드 상호작용을 지원하며, 핀 선택 시 상세 경로로 이동합니다.
장소 트랙 상세 화면 연동
src/pages/PinDetailPage.tsx
목업 데이터와 로컬 좋아요 상태를 제거했습니다. 상세 API 데이터와 좋아요 mutation을 사용하고 빈 피드 상태를 표시합니다.
재생 준비와 곡 상세 화면 연동
src/pages/SongDetailPage.tsx
재생 준비 API 결과로 곡 정보를 표시합니다. 밀리초 재생 시간을 초 단위로 변환하고 파형 트림 범위에 전달합니다.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant PinDetailPage
  participant usePutLikedTrack
  participant likedTrackCache
  participant trackApi
  User->>PinDetailPage: 좋아요 버튼 클릭
  PinDetailPage->>usePutLikedTrack: placeTrackId 전달
  usePutLikedTrack->>likedTrackCache: 좋아요 상태와 개수 낙관적 갱신
  usePutLikedTrack->>trackApi: 좋아요 등록 요청
  trackApi-->>usePutLikedTrack: 응답 반환
  usePutLikedTrack->>likedTrackCache: 관련 쿼리 무효화
Loading

Possibly related PRs

Suggested reviewers: onebone, jeonggyul

🚥 Pre-merge checks | ✅ 3 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning 좋아요 mutation, 핀 상세·목록 변경, 지도 이동 변경은 이슈 #135의 범위를 벗어납니다. 좋아요와 핀 관련 변경을 별도 PR로 분리하거나 해당 변경을 명시하는 관련 이슈를 연결하세요.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목은 구간 재생 준비 API 연동이라는 PR의 핵심 변경을 직접 설명합니다.
Linked Issues check ✅ Passed API 함수, 쿼리 훅, SongDetailPage 연동으로 이슈 #135의 핵심 개발 요구사항을 충족합니다.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/135-playback-preparations-api

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (5)
src/api/track.ts (2)

49-65: 🗄️ Data Integrity & Integration | 🔵 Trivial

장소 ID와 좌표가 하드코드되어 있습니다.

주석은 이미 이 상태를 인지하고 "추후에 수정 필요"라고 명시합니다. placeId는 URL 경로에 2로 고정되어 있습니다. 실제 사용자 위치나 선택된 장소를 반영하도록 나중에 교체해야 합니다.

주석에 적힌 기본 좌표값(latitude: 37.5665, longitude: 126.978)도 usePlaceTrack.ts의 실제 기본값(37.5350918, 127.0531533)과 다릅니다. 자세한 내용은 통합 코멘트를 참고하십시오.

이 작업을 진행할 해결책을 생성해 드릴까요? 아니면 별도 이슈로 등록해 드릴까요?

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/api/track.ts` around lines 49 - 65, Update getPlaceTracks so the URL uses
the caller’s selected placeId instead of the hardcoded 2, adding placeId to the
function input and passing it into the path. Replace any hardcoded coordinate
defaults associated with this request using the established defaults from
usePlaceTrack.ts, while preserving the existing query parameters and response
handling.

51-61: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

sort 매개변수 타입을 PinSort로 좁히십시오.

getPlaceTrackssort 매개변수는 string으로 선언되어 있습니다. 호출부는 항상 PinSort 값을 전달합니다. 타입을 PinSort로 지정하면 잘못된 문자열 전달을 컴파일 시점에 막을 수 있습니다.

♻️ 제안하는 타입 변경
 import type {
   searchTracksResponse,
   GetLikedTracksResponse,
   GetPlaceTracksResponse,
   PutLikedTracksResponse,
   GetPlaceTrackDetailResponse,
   GetPlaybackPreparationsResponse,
 } from '`@/features/pin/types`';
+import type { PinSort } from '`@/features/pin/types`';

 export async function getPlaceTracks(
   page: string,
   size: number,
   latitude: number,
   longitude: number,
-  sort: string,
+  sort: PinSort,
 ): Promise<GetPlaceTracksResponse> {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/api/track.ts` around lines 51 - 61, Change the sort parameter type in the
getPlaceTracks function signature from string to PinSort to enforce type safety
at compile time and prevent invalid values from being passed, ensuring the
function only accepts the valid PinSort enum values that callers actually use.
src/features/pin/queries/usePlaceTrack.ts (1)

14-21: 🗄️ Data Integrity & Integration | 🔵 Trivial

기본 좌표가 하드코드되어 있고, src/api/track.ts의 주석과 값이 다릅니다.

latitudelongitude의 기본값이 37.5350918, 127.0531533으로 고정되어 있습니다. src/api/track.ts의 주석은 37.5665, 126.978을 예시로 듭니다. 두 값이 일치하지 않습니다.

실제 사용자 위치를 사용할 계획이라면 이 기본값은 임시 상태입니다. 자세한 내용은 통합 코멘트를 참고하십시오.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/pin/queries/usePlaceTrack.ts` around lines 14 - 21, The default
latitude and longitude values in the usePlaceTrack function parameters are
hardcoded and do not match the example coordinates documented in
src/api/track.ts, creating inconsistency between the function defaults and the
API documentation. Update the default values for the latitude parameter
(currently 37.5350918) and longitude parameter (currently 127.0531533) in the
UsePlaceTrackParams destructuring to align with the documented example values
from src/api/track.ts (37.5665 and 126.978 respectively).
src/features/pin/queries/likedTrackCache.ts (1)

1-98: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

낙관적 업데이트/롤백 로직에 테스트가 없습니다.

prepareLikedTrackMutation, rollbackLikedTrackMutation, setPlaceTrackLiked, removeLikedTrackFromList는 순수 함수에 가깝고 QueryClient만 모킹하면 테스트하기 쉽습니다. 이 로직은 좋아요 상태와 카운트를 낙관적으로 변경하고 실패 시 되돌리는 핵심 경로입니다. 회귀가 발생하면 캐시 상태가 실제 서버 상태와 어긋나 사용자에게 잘못된 좋아요 상태를 보여줄 수 있습니다.

단위 테스트 작성을 도와드릴까요?

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/pin/queries/likedTrackCache.ts` around lines 1 - 98, Add unit
tests for the cache mutation functions prepareLikedTrackMutation,
rollbackLikedTrackMutation, setPlaceTrackLiked, and removeLikedTrackFromList.
Mock the QueryClient and verify each function correctly updates or reverts the
cache state. Cover the core optimistic update paths: preparing and storing
snapshot data, restoring data during rollback, updating like status and counts
in place track queries, and removing tracks from liked track queries. Include
tests for edge cases such as undefined or missing data to ensure cache
consistency is maintained.
src/features/pin/types.ts (1)

104-108: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Pin 타입 정의와 pinCount 설명이 실제 사용과 다릅니다.

주석은 pinCount를 "UI 전용 옵션"이라고 설명합니다. PinListSheetusePlaceTrackPlaceTrack 데이터로 Pin을 생성합니다(src/features/pin/components/PinListSheet.tsx:120-145 참고). PlaceTrackpinCount를 실제 API 필드로 포함합니다. 이 경우 pinCount는 UI 전용 값이 아니라 서버 응답값입니다.

PinLikedTrack을 기반으로 정의된 것도 오해를 일으킵니다. Pin은 실제로 LikedTrack 출처와 PlaceTrack 출처를 모두 표현합니다. 타입을 두 출처의 공통 필드로 직접 선언하면 의도가 더 명확해집니다.

♻️ 제안하는 타입 정의
-/** PinCard — 찜한 곡 API와 동일 shape (+ UI 전용 옵션) */
-export type Pin = LikedTrack & {
-  pinCount?: number;
-  liked?: boolean;
-  pinId?: string;
-};
+/**
+ * PinCard — 찜한 곡(LikedTrack) 또는 장소별 곡(PlaceTrack) 데이터를 함께 표현합니다.
+ * pinCount는 PlaceTrack 출처일 때만 존재하는 실제 API 필드입니다.
+ */
+export type Pin = TrackBase & {
+  placeTrackId: number;
+  likeCount: number;
+  pinCount?: number;
+  liked?: boolean;
+  pinId?: string;
+};
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/pin/types.ts` around lines 104 - 108, The JSDoc comment for the
Pin type incorrectly describes pinCount as a UI-only option, but pinCount is
actually an API field from PlaceTrack data when Pin is created in PinListSheet.
Additionally, extending LikedTrack is misleading since Pin represents data from
both LikedTrack and PlaceTrack sources. Update the JSDoc comment to clarify that
Pin combines fields from both API sources, and consider restructuring the Pin
type definition to directly declare the common fields from both LikedTrack and
PlaceTrack rather than extending only LikedTrack, making the dual-source nature
of the type explicit.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/features/pin/components/PinListSheet.tsx`:
- Around line 120-138: Update the PlaceInfo model and toPlaceInfo conversion to
include latitude and longitude from selectedMapPlace.coordinates, then pass
those coordinates from PinListSheet to usePlaceTrack so its query key and
results react to the selected place instead of using fixed defaults.

In `@src/pages/PinDetailPage.tsx`:
- Line 87: Update the registration-count text in PinDetailPage so it is a
complete standalone sentence when no count is displayed; replace the incomplete
“명이 등록” wording with the appropriate full Korean message while preserving the
surrounding layout and styling.

---

Nitpick comments:
In `@src/api/track.ts`:
- Around line 49-65: Update getPlaceTracks so the URL uses the caller’s selected
placeId instead of the hardcoded 2, adding placeId to the function input and
passing it into the path. Replace any hardcoded coordinate defaults associated
with this request using the established defaults from usePlaceTrack.ts, while
preserving the existing query parameters and response handling.
- Around line 51-61: Change the sort parameter type in the getPlaceTracks
function signature from string to PinSort to enforce type safety at compile time
and prevent invalid values from being passed, ensuring the function only accepts
the valid PinSort enum values that callers actually use.

In `@src/features/pin/queries/likedTrackCache.ts`:
- Around line 1-98: Add unit tests for the cache mutation functions
prepareLikedTrackMutation, rollbackLikedTrackMutation, setPlaceTrackLiked, and
removeLikedTrackFromList. Mock the QueryClient and verify each function
correctly updates or reverts the cache state. Cover the core optimistic update
paths: preparing and storing snapshot data, restoring data during rollback,
updating like status and counts in place track queries, and removing tracks from
liked track queries. Include tests for edge cases such as undefined or missing
data to ensure cache consistency is maintained.

In `@src/features/pin/queries/usePlaceTrack.ts`:
- Around line 14-21: The default latitude and longitude values in the
usePlaceTrack function parameters are hardcoded and do not match the example
coordinates documented in src/api/track.ts, creating inconsistency between the
function defaults and the API documentation. Update the default values for the
latitude parameter (currently 37.5350918) and longitude parameter (currently
127.0531533) in the UsePlaceTrackParams destructuring to align with the
documented example values from src/api/track.ts (37.5665 and 126.978
respectively).

In `@src/features/pin/types.ts`:
- Around line 104-108: The JSDoc comment for the Pin type incorrectly describes
pinCount as a UI-only option, but pinCount is actually an API field from
PlaceTrack data when Pin is created in PinListSheet. Additionally, extending
LikedTrack is misleading since Pin represents data from both LikedTrack and
PlaceTrack sources. Update the JSDoc comment to clarify that Pin combines fields
from both API sources, and consider restructuring the Pin type definition to
directly declare the common fields from both LikedTrack and PlaceTrack rather
than extending only LikedTrack, making the dual-source nature of the type
explicit.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: d5f41076-1d6a-4de1-8215-89423490c5a9

📥 Commits

Reviewing files that changed from the base of the PR and between 3d58069 and 09a0a14.

📒 Files selected for processing (17)
  • src/api/track.ts
  • src/features/pin/components/PinCard.tsx
  • src/features/pin/components/PinListSheet.tsx
  • src/features/pin/components/SortTabs.tsx
  • src/features/pin/data/mockPinSearchPlaces.ts
  • src/features/pin/queries/likedTrackCache.ts
  • src/features/pin/queries/useDeleteLikedTrack.ts
  • src/features/pin/queries/useGetPlaybackPreparations.ts
  • src/features/pin/queries/useLikeTrack.ts
  • src/features/pin/queries/usePlaceTrack.ts
  • src/features/pin/queries/usePlaceTrackDetail.ts
  • src/features/pin/queries/usePutLikedTrack.ts
  • src/features/pin/types.ts
  • src/pages/MapPage.tsx
  • src/pages/MyPlimapPage.tsx
  • src/pages/PinDetailPage.tsx
  • src/pages/SongDetailPage.tsx

Comment thread src/features/pin/components/PinListSheet.tsx
Comment thread src/pages/PinDetailPage.tsx
@onebone onebone added the feature Feature implementation label Jul 31, 2026
@onebone
onebone requested review from onebone and removed request for JeongGyul, L0521 and onebone July 31, 2026 16:22
@github-actions

Copy link
Copy Markdown

https://pr-136.plimap.kr

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/pages/SongDetailPage.tsx (2)

150-152: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

songId를 숫자로 검증한 후 조회를 시작하세요.

현재 호출은 라우트 문자열을 그대로 훅에 전달합니다. songIdabc이면 Number(songId)가 유효하지 않은 값이 됩니다. 양의 정수인 경우에만 훅을 활성화하거나, 잘못된 경로에 대한 오류 화면을 표시하세요.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/pages/SongDetailPage.tsx` around lines 150 - 152, Validate songId in
SongDetailPage before invoking useGetPlaybackPreparations, converting it to a
positive integer and only enabling the hook for valid values. Prevent invalid
route strings such as “abc” from reaching the query, and show the existing
invalid-route error state when validation fails.

150-160: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

로딩 및 오류 상태에서 30초 대체값을 노출하지 마세요.

song이 없을 때 로딩과 오류를 구분하지 않고 durationSec에 30초를 사용합니다. 이 상태에서는 제목, 아티스트, 앨범 이미지도 비어 있을 수 있습니다. API 오류 시 사용자는 잘못된 재생 시간과 불완전한 화면을 봅니다. 성공한 song이 있을 때만 durationSec을 계산하고, 로딩 및 오류 화면을 별도로 렌더링하세요.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/pages/SongDetailPage.tsx` around lines 150 - 160, Update SongDetailPage
around useGetPlaybackPreparations and durationSec so the 30-second fallback is
not used when song is unavailable. Render distinct loading and API-error states
before the main detail UI, and calculate durationSec only after a successful
song response using its durationMs.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/pages/SongDetailPage.tsx`:
- Around line 150-152: Validate songId in SongDetailPage before invoking
useGetPlaybackPreparations, converting it to a positive integer and only
enabling the hook for valid values. Prevent invalid route strings such as “abc”
from reaching the query, and show the existing invalid-route error state when
validation fails.
- Around line 150-160: Update SongDetailPage around useGetPlaybackPreparations
and durationSec so the 30-second fallback is not used when song is unavailable.
Render distinct loading and API-error states before the main detail UI, and
calculate durationSec only after a successful song response using its
durationMs.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 654dd5cc-cb07-464a-9a64-4f66da913adf

📥 Commits

Reviewing files that changed from the base of the PR and between 09a0a14 and 70edae5.

📒 Files selected for processing (1)
  • src/pages/SongDetailPage.tsx

Comment thread src/features/pin/queries/likedTrackCache.ts
Comment thread src/pages/PinDetailPage.tsx
Comment thread src/pages/PinDetailPage.tsx
@kim3360
kim3360 merged commit ef61a64 into develop Aug 2, 2026
4 checks passed

This branch was successfully deployed

1 active and 1 inactive deployments
preview-maintenance 439ed3a2 Deployed Aug 2, 2026 by kim3360 via cleanup #235
preview 439ed3a2 Deployed Aug 2, 2026 by kim3360 via deploy #234
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature Feature implementation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

구간 재생 준비 API 연동

2 participants