Feat : TJ 공식 차트 API 연동으로 popular 페이지 개편 (#295) - #296
Conversation
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WGv6Vf3GKCCogvBmEgZb2g
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
/describe |
|
/review |
|
/improve |
PR Summary by QodoIntegrate TJ official chart pipeline and revamp /popular with monthly/genre rankings
AI Description
Diagram
High-Level Assessment
Files changed (13)
|
Code Review by Qodo
1. Incomplete month list
|
| for (const targetMonth of targetMonths) { | ||
| const searchStartDate = format(startOfMonth(targetMonth), 'yyyy-MM-dd'); | ||
| const searchEndDate = format(endOfMonth(targetMonth), 'yyyy-MM-dd'); | ||
| const chartMonth = format(startOfMonth(targetMonth), 'yyyy-MM-dd'); |
There was a problem hiding this comment.
1. crawltjchartbackfill.ts missing checkpoint 📘 Rule violation ☼ Reliability
The new TJ 차트 백필 스크립트는 여러 개월/장르를 순회하는 장시간 작업인데, 중단 시 재개할 수 있는 체크포인트를 src/assets/에 저장/로드하지 않습니다. 실행 중단 시 전체 재처리 또는 누락 가능성이 있어 요구사항을 충족하지 못합니다.
Agent Prompt
## Issue description
`packages/crawling/src/cron/crawlTjChartBackfill.ts`는 월/장르를 대량 순회하는 장시간 스크립트인데, 중단 시 재개(resume)할 체크포인트를 `src/assets/` 하위 텍스트 파일로 저장/로드하지 않습니다.
## Issue Context
컴플라이언스 규칙은 장시간 스크립트가 (1) 시작 시 체크포인트를 읽고, (2) 처리 진행에 따라 주기적으로 체크포인트를 갱신하여, (3) 다음 실행 시 이미 처리한 구간을 건너뛰도록 요구합니다.
## Fix Focus Areas
- packages/crawling/src/cron/crawlTjChartBackfill.ts[18-77]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| // 1) 데이터가 존재하는 월 목록 조회 | ||
| const { data: monthRows, error: monthError } = await supabase | ||
| .from('chart_rankings') | ||
| .select('chart_month') | ||
| .order('chart_month', { ascending: false }); |
There was a problem hiding this comment.
2. Incomplete month list 🐞 Bug ≡ Correctness
GET /api/tj-chart가 chart_rankings의 모든 row에서 chart_month를 가져와 availableMonths를 만들기 때문에, Supabase 응답 row 제한/트렁케이션으로 오래된 월이 누락될 수 있습니다. 그 결과 월 선택 UI가 실제 DB에 있는 과거 월 데이터를 숨길 수 있습니다.
Agent Prompt
### Issue description
`/api/tj-chart`에서 `availableMonths`를 만들기 위해 `chart_rankings` 전체에서 `chart_month`를 조회하고 `Set`으로 중복 제거하고 있습니다. `chart_rankings`는 월/장르/순위 단위로 row 수가 많아지기 때문에, Supabase가 한 번의 select에서 반환하는 row 수 제한에 걸려 과거 월이 응답에 포함되지 않을 수 있고, 그 상태로 `availableMonths`를 계산하면 월 목록이 잘못됩니다.
### Issue Context
- 크롤러는 `StrType` 전체에 대해 TOP 차트를 수집/저장하므로 월 단위로 다수의 row가 생성됩니다.
- 레포 내 Supabase 조회 코드에서도 row 제한 존재를 인지하고 `.limit(...)`를 사용하는 패턴이 이미 있습니다.
### Fix Focus Areas
- apps/web/src/app/api/tj-chart/route.ts[25-45]
### Suggested fix
- 월 목록 조회 쿼리를 **중복이 구조적으로 발생하지 않도록** 바꾸세요. 예를 들어 월당 1개 row만 나오도록 고정 조건을 추가하면 됩니다.
- 예: `type = StrType.All` AND `rank = 1`만 조회
- 또는 DB view/RPC로 `select distinct chart_month ...`를 제공
예시(개념):
```ts
const { data: monthRows, error: monthError } = await supabase
.from('chart_rankings')
.select('chart_month')
.eq('type', StrType.All)
.eq('rank', 1)
.order('chart_month', { ascending: false });
const availableMonths = (monthRows ?? []).map(r => r.chart_month as string);
```
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| const { data } = await axios.get<TjChartApiResponse>( | ||
| 'https://www.tjmedia.com/legacy/api/topAndHot100', | ||
| { | ||
| params: { |
There was a problem hiding this comment.
3. No crawl request timeout 🐞 Bug ☼ Reliability
fetchTjChart의 axios.get에 timeout이 없어 네트워크 지연/서버 응답 정지 시 크롤링이 외부 러너 타임아웃까지 장시간 블록될 수 있습니다. 이 경우 월간 크롤링이 완료되지 않아 차트 데이터가 갱신되지 않을 수 있습니다.
Agent Prompt
### Issue description
`fetchTjChart()`가 `axios.get(...)`을 timeout 없이 호출합니다. axios 기본은 애플리케이션 레벨 타임아웃이 없기 때문에, 요청이 지연되면 해당 genre 이후 로직이 모두 멈춘 상태로 오래 지속될 수 있습니다.
### Issue Context
웹앱 axios 클라이언트는 이미 timeout을 명시하고 있어(10초) 레포의 표준 패턴과도 불일치합니다.
### Fix Focus Areas
- packages/crawling/src/utils/tjChart.ts[13-35]
### Suggested fix
- `axios.get` 옵션에 `timeout`을 추가하세요(예: 10~30초).
- (선택) 특정 genre 실패 시 전체를 즉시 종료할지/해당 genre만 스킵할지 정책을 정하고, 재시도(최대 N회, 백오프)와 함께 로그를 남기세요.
예시(개념):
```ts
const { data } = await axios.get<TjChartApiResponse>(URL, {
params: {...},
timeout: 30_000,
});
```
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| if (unmatched.length > 0) { | ||
| fs.appendFileSync(UNMATCHED_LOG_FILE, unmatched.join('\n') + '\n', 'utf-8'); | ||
| console.log(`📝 미매칭 목록 기록: ${UNMATCHED_LOG_FILE}`); |
There was a problem hiding this comment.
4. Unmatched log not retained 🐞 Bug ◔ Observability
crawlTjChart가 미매칭 곡 목록을 로컬 txt 파일로 기록하지만, GitHub Actions 워크플로우가 해당 파일을 업로드/커밋하지 않아 실행 종료 후 데이터가 사라집니다. 이로 인해 정기 크롤링에서 매칭 실패 원인을 추적하기 어렵습니다.
Agent Prompt
### Issue description
정기 크롤링에서 `tjChartUnmatched.txt`에 미매칭 목록을 append 하지만, Actions 러너는 ephemeral이므로 워크플로우에서 아티팩트 업로드나 커밋을 하지 않으면 파일이 보존되지 않습니다.
### Issue Context
현재 워크플로우는 의존성 설치 후 크롤 스크립트만 실행하고 종료합니다.
### Fix Focus Areas
- packages/crawling/src/cron/crawlTjChart.ts[18-19]
- packages/crawling/src/cron/crawlTjChart.ts[58-60]
- .github/workflows/crawl_tj_chart.yml[26-38]
### Suggested fix
- 워크플로우에 `actions/upload-artifact@v4` 스텝을 추가하여 `packages/crawling/src/assets/tjChartUnmatched.txt`가 존재할 때 업로드하세요.
- 또는 파일 대신 콘솔에 미매칭 목록을 요약/샘플링 출력하고, 전체 목록은 Supabase 테이블/스토리지(S3 등)에 적재하는 방식으로 영구 보관하세요.
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
📌 PR 제목
Feat : TJ 공식 차트 API 연동으로 popular 페이지 개편
📌 변경 사항
topAndHot100API를 장르별로 크롤링하는crawlTjChart.ts추가 (매달 지난달 기준, GitHub Actions로 매달 1일 KST 10시 자동 실행)crawlTjChartBackfill.ts추가, 조회 시마다 순위 표(console.table)와 저장 결과를 즉시 로그로 확인 가능packages/crawling/src/utils/tjChart.ts로 추출해 두 크론 스크립트에서 재사용chart_rankings테이블 upsert용postTjChartRankingsDB추가,StrTypeenum 및 TJ API 응답 타입 정의GET /api/tj-chart라우트(월/장르 파라미터로chart_rankings+songs조인 조회) 및lib/api/tjChart.ts,queries/tjChartQuery.ts,types/tjChart.ts추가/popular페이지의 기존PopularRankingList(포인트 기반 추천)를 월/장르 선택 가능한TjChartRankingList로 교체 (기존 엄지척/thumb 시스템 코드는 그대로 유지)💬 추가 참고 사항
num_tj매칭 실패 곡은 저장하지 않고src/assets/tjChartUnmatched.txt(정기 크롤링) /tjChartBackfillUnmatched.txt(백필)에만 기록