Skip to content

[Feat] : 검색 로그 기능 추가 및 UI 개선 (#174)#177

Merged
GulSam00 merged 4 commits intodevelopfrom
feat/174-searchLogAndUiImprove
Apr 4, 2026
Merged

[Feat] : 검색 로그 기능 추가 및 UI 개선 (#174)#177
GulSam00 merged 4 commits intodevelopfrom
feat/174-searchLogAndUiImprove

Conversation

@GulSam00
Copy link
Copy Markdown
Owner

@GulSam00 GulSam00 commented Apr 2, 2026

User description

📌 PR 제목

[Feat] : 검색 로그 기능 추가 및 UI 개선

📌 변경 사항

  • search_logs 테이블 기반 검색 로그 API Route (GET/POST) 추가
  • 인기 검색어 컴포넌트 (PopularSearchHistory) 추가
  • 좋아요 → 즐겨찾기 용어 및 아이콘 변경 (Heart → Star)
  • 검색 기록 UI를 칩 형태로 개선 (제목 + flex-wrap 레이아웃)
  • 불필요한 크롤링 asset 파일 삭제 (약 50,000줄 제거)
  • README 업데이트

💬 추가 참고 사항


PR Type

Enhancement, Tests


Description

  • Add search log API (GET/POST) with popular search tracking

  • Implement PopularSearchHistory component displaying top 10 searches

  • Replace "Like" terminology with "Favorites" (Heart → Star icon)

  • Refactor search history UI to chip-based flex-wrap layout

  • Update README formatting and terminology consistency


Diagram Walkthrough

flowchart LR
  A["Search Input"] -- "POST search term" --> B["Search Log API"]
  B -- "Store in DB" --> C["search_logs Table"]
  C -- "GET aggregated logs" --> D["Popular Search Component"]
  D -- "Display top 10" --> E["Search Page UI"]
  F["Search History"] -- "Display recent 10" --> E
  G["Like Button"] -- "Refactor to" --> H["Favorites Button"]
  H -- "Star Icon" --> E
Loading

File Walkthrough

Relevant files
Enhancement
9 files
route.ts
New search log API endpoints GET and POST                               
+69/-0   
searchLogQuery.ts
React Query hooks for search log operations                           
+27/-0   
searchLog.ts
API client functions for search log requests                         
+18/-0   
PopularSearchHistory.tsx
New component displaying popular searches ranking               
+41/-0   
SearchHistory.tsx
Refactor to chip layout with title and icon                           
+27/-21 
useSearchSong.ts
Integrate search log mutation on search execution               
+9/-0     
HomePage.tsx
Reorganize layout to show history and popular searches     
+11/-10 
SearchResultCard.tsx
Replace Heart icon with Star for favorites button               
+4/-4     
page.tsx
Replace Heart icon with Star and update labels                     
+3/-3     
Documentation
6 files
likeSongQuery.ts
Update comments from like to favorites terminology             
+2/-2     
song.ts
Update comment terminology to favorites                                   
+1/-1     
page.tsx
Update page title to favorites management                               
+1/-1     
AddListModal.tsx
Update tab label from like to favorites                                   
+1/-1     
changelog.json
Update changelog terminology to favorites                               
+2/-2     
README.md
Clean up formatting and update terminology                             
+35/-53 
Formatting
1 files
route.ts
Format code style improvements for readability                     
+5/-3     
Miscellaneous
1 files
sitemap-0.xml
Update sitemap timestamp                                                                 
+1/-1     
Additional files
3 files
route.ts +1/-3     
crawlKYValidList.txt +0/-23527
crawlKYYoutubeFailedList.txt +0/-26417

GulSam00 and others added 3 commits March 31, 2026 01:48
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown
Contributor

vercel bot commented Apr 2, 2026

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

Project Deployment Actions Updated (UTC)
singcode Ready Ready Preview, Comment Apr 4, 2026 2:32pm

@GulSam00
Copy link
Copy Markdown
Owner Author

GulSam00 commented Apr 2, 2026

/describe

@GulSam00
Copy link
Copy Markdown
Owner Author

GulSam00 commented Apr 2, 2026

/review

@GulSam00
Copy link
Copy Markdown
Owner Author

GulSam00 commented Apr 2, 2026

/improve

@qodo-code-review
Copy link
Copy Markdown

Review Summary by Qodo

Add search log tracking and UI improvements with terminology updates

✨ Enhancement 🧪 Tests

Grey Divider

Walkthroughs

Description
• Add search log API with GET/POST routes to track popular searches
• Create PopularSearchHistory component displaying top 10 searches
• Replace "좋아요" (Like) terminology with "즐겨찾기" (Favorite) and Heart icon with Star
• Refactor search history UI to chip layout with flex-wrap and add section titles
• Update README formatting and changelog references
Diagram
flowchart LR
  A["Search Input"] -->|POST| B["Search Log API"]
  B -->|Store| C["search_logs Table"]
  C -->|GET| D["Popular Search History"]
  D -->|Display| E["PopularSearchHistory Component"]
  F["Search History"] -->|Display| G["Chip Layout UI"]
  H["Like Icon"] -->|Replace| I["Star Icon"]
Loading

Grey Divider

File Changes

1. apps/web/src/app/api/search/log/route.ts ✨ Enhancement +69/-0

Search log API endpoints for GET and POST

apps/web/src/app/api/search/log/route.ts


2. apps/web/src/queries/searchLogQuery.ts ✨ Enhancement +27/-0

React Query hooks for search log operations

apps/web/src/queries/searchLogQuery.ts


3. apps/web/src/lib/api/searchLog.ts ✨ Enhancement +18/-0

API client functions for search log requests

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


View more (17)
4. apps/web/src/app/search/PopularSearchHistory.tsx ✨ Enhancement +41/-0

New component displaying top 10 popular searches

apps/web/src/app/search/PopularSearchHistory.tsx


5. apps/web/src/app/search/SearchHistory.tsx ✨ Enhancement +27/-21

Refactor to chip layout with flex-wrap and section title

apps/web/src/app/search/SearchHistory.tsx


6. apps/web/src/hooks/useSearchSong.ts ✨ Enhancement +9/-0

Integrate search log mutation and validation logic

apps/web/src/hooks/useSearchSong.ts


7. apps/web/src/app/search/HomePage.tsx ✨ Enhancement +11/-10

Reorganize search page layout with popular searches

apps/web/src/app/search/HomePage.tsx


8. apps/web/src/app/search/SearchResultCard.tsx ✨ Enhancement +4/-4

Replace Heart icon with Star and update terminology

apps/web/src/app/search/SearchResultCard.tsx


9. apps/web/src/queries/likeSongQuery.ts 📝 Documentation +2/-2

Update comments from like to favorite terminology

apps/web/src/queries/likeSongQuery.ts


10. apps/web/src/types/song.ts 📝 Documentation +1/-1

Update comment terminology from like to favorite

apps/web/src/types/song.ts


11. apps/web/src/app/info/like/page.tsx ✨ Enhancement +1/-1

Update page title to favorite song management

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


12. apps/web/src/app/info/page.tsx ✨ Enhancement +3/-3

Replace Heart icon with Star and update menu title

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


13. apps/web/src/app/tosing/AddListModal.tsx ✨ Enhancement +1/-1

Update tab label from like to favorite

apps/web/src/app/tosing/AddListModal.tsx


14. apps/web/src/app/api/search/route.ts Formatting +5/-3

Format type definition for improved readability

apps/web/src/app/api/search/route.ts


15. apps/web/public/changelog.json 📝 Documentation +2/-2

Update changelog with favorite terminology

apps/web/public/changelog.json


16. README.md 📝 Documentation +35/-53

Clean up formatting and update terminology references

README.md


17. apps/web/public/sitemap-0.xml Miscellaneous +1/-1

Update sitemap timestamp for deployment

apps/web/public/sitemap-0.xml


18. apps/web/src/app/api/songs/thumb-up/route.ts Additional files +1/-3

...

apps/web/src/app/api/songs/thumb-up/route.ts


19. packages/crawling/src/assets/crawlKYValidList.txt Additional files +0/-23527

...

packages/crawling/src/assets/crawlKYValidList.txt


20. packages/crawling/src/assets/crawlKYYoutubeFailedList.txt Additional files +0/-26417

...

packages/crawling/src/assets/crawlKYYoutubeFailedList.txt


Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Copy Markdown

qodo-code-review bot commented Apr 2, 2026

Code Review by Qodo

Grey Divider

New Review Started

This review has been superseded by a new analysis

Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

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

qodo-code-review bot commented Apr 2, 2026

Code Review by Qodo

Grey Divider

New Review Started

This review has been superseded by a new analysis

Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Copy Markdown

qodo-code-review bot commented Apr 2, 2026

Code Review by Qodo

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

Grey Divider


Action required

1. Empty results omit history UI 📎 Requirement gap ≡ Correctness
Description
In the empty-results state after a search (searchSongs.length === 0 && query), the page only shows
the "검색 결과가 없습니다" message and does not render search history/popular searches. This does not meet
the requirement to show search history and/or popular searches when search results are empty.
Code

apps/web/src/app/search/HomePage.tsx[R240-255]

            <p className="m-2">검색 결과가 없습니다.</p>
          </div>
        )}
-        {searchSongs.length === 0 && !query && (
+
+        {/* {searchSongs.length === 0 && !query && (
          <div className="text-muted-foreground flex h-40 flex-col items-center justify-center">
            <Search className="h-8 w-8 opacity-50" />
            <p className="m-2">노래 제목이나 가수를 검색해보세요</p>
          </div>
+        )} */}
+
+        {searchSongs.length === 0 && !query && (
+          <div className="flex h-full flex-col justify-center gap-2">
+            <SearchHistory onHistoryClick={handleHistoryClick} />
+            <PopularSearchHistory onHistoryClick={handleHistoryClick} />
+          </div>
Evidence
PR Compliance ID 4 requires showing search history/popular searches specifically when a search
yields no results, but the code renders SearchHistory/PopularSearchHistory only when !query
(initial state), not when results are empty after a search (query is truthy).

Update HomePage layout to show search history/popular searches when there are no search results
apps/web/src/app/search/HomePage.tsx[237-255]

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

## Issue description
The HomePage currently renders `SearchHistory`/`PopularSearchHistory` only when `searchSongs.length === 0 && !query`, but the compliance requirement is to show these in the empty-results state (when a search is performed and yields no results).

## Issue Context
The current empty-results UI path is `!isPendingSearch && searchSongs.length === 0 && query`, which only renders the "검색 결과가 없습니다" message.

## Fix Focus Areas
- apps/web/src/app/search/HomePage.tsx[237-255]

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


2. searchHistory.slice(10) hides chips 📎 Requirement gap ≡ Correctness
Description
SearchHistory maps over searchHistory.slice(10), which skips the first 10 entries and often
results in no chips being rendered for typical histories (<=10 items). This can prevent the
chip-style search history UI from being displayed as required.
Code

apps/web/src/app/search/SearchHistory.tsx[R20-22]

+      <div className="flex flex-wrap gap-2 pb-4">
+        {searchHistory.slice(10).map((term, index) => (
+          <div
Evidence
PR Compliance ID 6 requires search history to be rendered chip-style; however, slice(10) commonly
produces an empty list, so the chip list may not render even when history exists.

Improve search history UI to chip-style with title and flex-wrap layout
apps/web/src/app/search/SearchHistory.tsx[20-22]

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

## Issue description
`SearchHistory` uses `searchHistory.slice(10)`, which skips the first 10 items. This often results in rendering no chip items, undermining the required chip-style search history UI.

## Issue Context
The component already has the required title and `flex-wrap` chip container, but the slicing logic likely should show the most recent items (e.g., first 10, or last 10).

## Fix Focus Areas
- apps/web/src/app/search/SearchHistory.tsx[20-22]

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



Remediation recommended

3. README missing search log docs 📎 Requirement gap ⚙ Maintainability
Description
The README does not mention the new search log feature (logging searches) or the popular search
terms UI, so documentation is missing updates for this change. This fails the requirement to update
README to reflect the new search log functionality and related UI/behavior changes.
Code

README.md[R63-92]

## ✨ 주요 기능

### 검색 페이지

-* 제목, 가수 이름으로 곡을 검색할 수 있습니다.
+- 제목, 가수 이름으로 곡을 검색할 수 있습니다.

<div style="display: flex; justify-content: center; gap: 10px; flex-wrap: wrap;">
-  
+

</div>

- ### 검색 페이지 - 재생목록으로 저장
- 
-* 기존 재생목록이나 새로운 재생목록에 곡을 저장할 수 있습니다.
+### 검색 페이지 - 재생목록으로 저장

-<div style="display: flex; justify-content: center; gap: 10px; flex-wrap: wrap;">
+- 기존 재생목록이나 새로운 재생목록에 곡을 저장할 수 있습니다.

+<div style="display: flex; justify-content: center; gap: 10px; flex-wrap: wrap;">

</div>

### 부를 곡 페이지

-* 자신이 저장한 부를 곡을 조회합니다.
-* 부를 곡의 순서를 바꿀 수 있습니다.
-* 곡을 부르거나, 부르지 않고 삭제할 수 있습니다.
-  
-<div style="display: flex; justify-content: center; gap: 10px; flex-wrap: wrap;">
+- 자신이 저장한 부를 곡을 조회합니다.
+- 부를 곡의 순서를 바꿀 수 있습니다.
+- 곡을 부르거나, 부르지 않고 삭제할 수 있습니다.

+<div style="display: flex; justify-content: center; gap: 10px; flex-wrap: wrap;">

</div>

-* 좋아요 표시한 곡이나 재생목록에 저장한 곡에서 빠르게 부를곡을 추가할 수 있습니다.
-
+- 즐겨찾기 표시한 곡이나 재생목록에 저장한 곡에서 빠르게 부를곡을 추가할 수 있습니다.
Evidence
PR Compliance ID 9 requires README updates for the search log feature and UI/behavior changes, but
the feature documentation section contains no reference to search logging or popular searches.

Update README to reflect new search log feature and UI changes
README.md[63-92]

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

## Issue description
The README lacks documentation for the new search log feature (recording searches) and the popular search terms UI/behavior.

## Issue Context
The PR introduces `/api/search/log` (GET/POST), logging on search, and a `PopularSearchHistory` component, but the README feature list does not describe these additions.

## Fix Focus Areas
- README.md[63-92]

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


4. Unbounded log scan/aggregate 🐞 Bug ➹ Performance
Description
GET /api/search/log이 search_logs의 모든 row를 select 후 서버 메모리에서 카운팅/정렬해 전체 결과를 반환하여, 검색이 누적될수록 불필요한
DB/서버 부하와 응답 페이로드가 커집니다. UI는 상위 10개만 쓰므로 서버에서 집계/정렬/limit을 적용해야 합니다.
Code

apps/web/src/app/api/search/log/route.ts[R14-28]

+    const { data, error } = await supabase.from('search_logs').select('text');
+
+    if (error) throw error;
+
+    const countMap = new Map<string, number>();
+    for (const row of data) {
+      countMap.set(row.text, (countMap.get(row.text) ?? 0) + 1);
+    }
+
+    const result: SearchLogCount[] = Array.from(countMap, ([text, count]) => ({
+      text,
+      count,
+    })).sort((a, b) => b.count - a.count);
+
+    return NextResponse.json({ success: true, data: result });
Evidence
API는 supabase.from('search_logs').select('text')로 전체 로그 row를 가져와 Map으로 집계한 뒤 전체를 정렬해 반환합니다. 동시에
클라이언트는 검색 성공 시마다 postSearchLog(parsedSearch)로 row를 계속 추가하며, 인기 검색어 컴포넌트는 slice(0, 10)으로 상위 10개만
표시하므로(=나머지 데이터는 전송/계산 낭비) 서버에서 top N만 산출해 내려주는 것이 맞습니다.

apps/web/src/app/api/search/log/route.ts[11-28]
apps/web/src/hooks/useSearchSong.ts[59-89]
apps/web/src/app/search/PopularSearchHistory.tsx[11-37]

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

### Issue description
`GET /api/search/log`이 `search_logs` 전체 row를 읽어 애플리케이션 레벨에서 집계/정렬합니다. 검색 로그는 검색 시마다 계속 insert 되므로(클라이언트에서 매 검색마다 POST), 이 방식은 누적 데이터에 비례해 느려집니다.

### Issue Context
UI(`PopularSearchHistory`)는 상위 10개만 사용합니다. 따라서 서버는 DB에서 group by + count + order + limit(10)을 적용해 결과만 반환해야 합니다.

### Fix Focus Areas
- apps/web/src/app/api/search/log/route.ts[13-28]
- apps/web/src/app/search/PopularSearchHistory.tsx[22-37]
- apps/web/src/hooks/useSearchSong.ts[83-89]

### Suggested fix options
- (권장) Postgres view/RPC를 만들고 `supabase.rpc(...)`로 `text, count` 상위 10개만 가져오기
- 또는 Supabase 쿼리로 `group by text` + `count(*)` + `order by count desc` + `limit 10`이 되도록 서버 쿼리를 변경
- 응답은 top N만 내려주고 클라이언트의 `slice(0,10)`은 제거하거나 방어용으로만 유지

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


5. Search log POST unvalidated 🐞 Bug ☼ Reliability
Description
POST /api/search/log이 요청 body의 text를 타입/공백/길이 검증 없이 그대로 insert하여 빈 문자열/비정상 값이 로그에 저장되거나 DB 에러로 500이
발생할 수 있습니다. 서버에서 최소한 string 여부 및 trim 후 비어있음 체크를 하고, 잘못된 입력은 400으로 응답해야 합니다.
Code

apps/web/src/app/api/search/log/route.ts[R45-52]

+export async function POST(request: Request): Promise<NextResponse<ApiResponse<void>>> {
+  try {
+    const { text } = await request.json();
+
+    const supabase = await createClient();
+    const { error } = await supabase.from('search_logs').insert({ text });
+
+    if (error) throw error;
Evidence
현재 route는 const { text } = await request.json(); 이후 바로 insert({ text })를 수행하며, 서버 측에서 입력 검증/정규화가
없습니다. 클라이언트 훅은 trim 공백만 방어하지만 API는 외부 호출도 가능하므로 서버에서 유효성 검증이 필요합니다.

apps/web/src/app/api/search/log/route.ts[45-52]
apps/web/src/hooks/useSearchSong.ts[59-66]

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

### Issue description
`POST /api/search/log`이 `text`를 검증 없이 DB에 저장합니다. 빈 값/비문자열/과도한 길이 등이 들어오면 로그 데이터가 오염되거나 DB 에러로 500이 발생할 수 있습니다.

### Issue Context
클라이언트에서 일부 trim 체크가 있어도, API는 서버가 최종 방어선이므로 동일한 검증을 서버에 두어야 합니다.

### Fix Focus Areas
- apps/web/src/app/api/search/log/route.ts[45-55]
- apps/web/src/hooks/useSearchSong.ts[59-66]

### Suggested change
- `text`가 `typeof text === 'string'`인지 확인
- `const normalized = text.trim()` 후 빈 문자열이면 400 반환
- (선택) 최대 길이 제한(예: 100~255자) 및 초과 시 400
- insert에는 `normalized`를 사용

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


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Copy Markdown

PR Description updated to latest commit (c01c0f0)

Comment on lines 240 to +255
<p className="m-2">검색 결과가 없습니다.</p>
</div>
)}
{searchSongs.length === 0 && !query && (

{/* {searchSongs.length === 0 && !query && (
<div className="text-muted-foreground flex h-40 flex-col items-center justify-center">
<Search className="h-8 w-8 opacity-50" />
<p className="m-2">노래 제목이나 가수를 검색해보세요</p>
</div>
)} */}

{searchSongs.length === 0 && !query && (
<div className="flex h-full flex-col justify-center gap-2">
<SearchHistory onHistoryClick={handleHistoryClick} />
<PopularSearchHistory onHistoryClick={handleHistoryClick} />
</div>
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. Empty results omit history ui 📎 Requirement gap ≡ Correctness

In the empty-results state after a search (searchSongs.length === 0 && query), the page only shows
the "검색 결과가 없습니다" message and does not render search history/popular searches. This does not meet
the requirement to show search history and/or popular searches when search results are empty.
Agent Prompt
## Issue description
The HomePage currently renders `SearchHistory`/`PopularSearchHistory` only when `searchSongs.length === 0 && !query`, but the compliance requirement is to show these in the empty-results state (when a search is performed and yields no results).

## Issue Context
The current empty-results UI path is `!isPendingSearch && searchSongs.length === 0 && query`, which only renders the "검색 결과가 없습니다" message.

## Fix Focus Areas
- apps/web/src/app/search/HomePage.tsx[237-255]

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

Comment on lines +20 to +22
<div className="flex flex-wrap gap-2 pb-4">
{searchHistory.slice(10).map((term, index) => (
<div
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

2. searchhistory.slice(10) hides chips 📎 Requirement gap ≡ Correctness

SearchHistory maps over searchHistory.slice(10), which skips the first 10 entries and often
results in no chips being rendered for typical histories (<=10 items). This can prevent the
chip-style search history UI from being displayed as required.
Agent Prompt
## Issue description
`SearchHistory` uses `searchHistory.slice(10)`, which skips the first 10 items. This often results in rendering no chip items, undermining the required chip-style search history UI.

## Issue Context
The component already has the required title and `flex-wrap` chip container, but the slicing logic likely should show the most recent items (e.g., first 10, or last 10).

## Fix Focus Areas
- apps/web/src/app/search/SearchHistory.tsx[20-22]

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

Base automatically changed from feat/173-extractSongTags to develop April 4, 2026 14:30
@GulSam00 GulSam00 merged commit 1098450 into develop Apr 4, 2026
1 of 2 checks passed
@GulSam00 GulSam00 deleted the feat/174-searchLogAndUiImprove branch April 4, 2026 14:32
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.

검색 로그 기능 추가 및 UI 개선

1 participant