Skip to content

Feat : TJ 공식 차트 API 연동으로 popular 페이지 개편 (#295) - #296

Open
GulSam00 wants to merge 2 commits into
developfrom
feat/295-tjChartApi
Open

Feat : TJ 공식 차트 API 연동으로 popular 페이지 개편 (#295)#296
GulSam00 wants to merge 2 commits into
developfrom
feat/295-tjChartApi

Conversation

@GulSam00

@GulSam00 GulSam00 commented Aug 5, 2026

Copy link
Copy Markdown
Owner

📌 PR 제목

Feat : TJ 공식 차트 API 연동으로 popular 페이지 개편

📌 변경 사항

  • TJ미디어 공식 topAndHot100 API를 장르별로 크롤링하는 crawlTjChart.ts 추가 (매달 지난달 기준, GitHub Actions로 매달 1일 KST 10시 자동 실행)
  • 특정 기간(월 단위 반복)을 일괄 등록하는 crawlTjChartBackfill.ts 추가, 조회 시마다 순위 표(console.table)와 저장 결과를 즉시 로그로 확인 가능
  • 크롤링 공통 로직(API 호출/곡 매칭/순위 로깅)을 packages/crawling/src/utils/tjChart.ts로 추출해 두 크론 스크립트에서 재사용
  • chart_rankings 테이블 upsert용 postTjChartRankingsDB 추가, StrType enum 및 TJ API 응답 타입 정의
  • 웹앱: GET /api/tj-chart 라우트(월/장르 파라미터로 chart_rankings + songs 조인 조회) 및 lib/api/tjChart.ts, queries/tjChartQuery.ts, types/tjChart.ts 추가
  • /popular 페이지의 기존 PopularRankingList(포인트 기반 추천)를 월/장르 선택 가능한 TjChartRankingList로 교체 (기존 엄지척/thumb 시스템 코드는 그대로 유지)

💬 추가 참고 사항

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WGv6Vf3GKCCogvBmEgZb2g
@vercel

vercel Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

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

Project Deployment Actions Updated (UTC)
singcode Ready Ready Preview Aug 5, 2026 5:10am

@GulSam00

GulSam00 commented Aug 5, 2026

Copy link
Copy Markdown
Owner Author

/describe

@GulSam00

GulSam00 commented Aug 5, 2026

Copy link
Copy Markdown
Owner Author

/review

@GulSam00

GulSam00 commented Aug 5, 2026

Copy link
Copy Markdown
Owner Author

/improve

@qodo-code-review

qodo-code-review Bot commented Aug 5, 2026

Copy link
Copy Markdown

PR Summary by Qodo

Integrate TJ official chart pipeline and revamp /popular with monthly/genre rankings

✨ Enhancement ⚙️ Configuration changes 🕐 40+ Minutes

Grey Divider

AI Description

• Add monthly TJ TOP100 crawling + Supabase upsert for chart_rankings
• Expose /api/tj-chart (month/genre) and client query/types to fetch joined chart+songs
• Replace /popular rankings UI with selectable TJ chart list (month + genre)
Diagram

graph TD
  ga["GitHub Actions: crawl_tj_chart.yml"] --> crawler["Crawler: crawlTjChart.ts"] --> db[("Supabase: chart_rankings")]
  db --> api["Next.js API: GET /api/tj-chart"] --> ui["Web UI: /popular (TjChartRankingList)"]
  crawler --> tj{{"TJ topAndHot100 API (TOP)"}}
  subgraph Legend
    direction LR
    _proc["Process/Service"] ~~~ _db[("Database")] ~~~ _ext{{"External API"}}
  end
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Move the scheduled crawl into Supabase (Edge Function + Scheduler)
  • ➕ Keeps secrets/runtime fully within the data platform (no .env creation in CI)
  • ➕ Easier operational visibility near the database (logs/metrics in one place)
  • ➕ Avoids CI dependency install cost on every schedule
  • ➖ Requires Supabase runtime constraints review (timeouts, networking, dependencies)
  • ➖ More platform-specific; harder to run identically locally without adapters
2. Create a shared types package for StrType and chart response shapes
  • ➕ Prevents drift between crawling StrType and web StrType definitions
  • ➕ Single source of truth for labels/allowed values
  • ➖ Introduces/strengthens monorepo coupling and build graph between packages
  • ➖ May require tsconfig/package exports adjustments
3. Optimize availableMonths query via distinct/grouping at the DB layer
  • ➕ Avoids scanning and de-duplicating potentially large chart_rankings result sets in the API
  • ➕ Clearer intent and likely lower latency
  • ➖ May require SQL view/RPC or different Supabase query patterns
  • ➖ Small win until table grows significantly

Recommendation: The PR’s approach (GitHub Actions → crawler → upsert → Next API → UI) is pragmatic and easy to operate in a repo-centric workflow. The most valuable follow-up would be extracting shared StrType/types to a common package to avoid future enum/label drift, and tightening the availableMonths query if/when chart_rankings grows.

Files changed (13) +662 / -4

Enhancement (10) +523 / -4
route.tsAdd GET /api/tj-chart to serve month/genre chart rankings +69/-0

Add GET /api/tj-chart to serve month/genre chart rankings

• Implements a Next.js route that validates the genre parameter, discovers available months from chart_rankings, and returns ranked songs by joining chart_rankings with songs. Filters out null joined rows and returns a structured response including availableMonths.

apps/web/src/app/api/tj-chart/route.ts

TjChartRankingList.tsxNew /popular ranking UI with month + genre selectors +148/-0

New /popular ranking UI with month + genre selectors

• Adds a client component that fetches TJ chart data via react-query, manages month/genre selection, and renders ranked song rows with special styling for top 3. Shows a loading state and an empty/error placeholder when data is unavailable.

apps/web/src/app/popular/TjChartRankingList.tsx

page.tsxSwap popular page ranking source to TJ chart list +3/-3

Swap popular page ranking source to TJ chart list

• Replaces the previous PopularRankingList with TjChartRankingList and updates the section comment to reflect the TJ official chart basis.

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

tjChart.tsClient API wrapper for /tj-chart endpoint +12/-0

Client API wrapper for /tj-chart endpoint

• Adds a typed API helper that calls GET /tj-chart with optional month and genre query parameters and returns the ApiResponse payload.

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

tjChartQuery.tsAdd react-query hook for TJ chart data +18/-0

Add react-query hook for TJ chart data

• Introduces useTjChartQuery with a stable queryKey and a queryFn that returns null on unsuccessful API responses.

apps/web/src/queries/tjChartQuery.ts

tjChart.tsDefine web-side TJ chart enums and response types +44/-0

Define web-side TJ chart enums and response types

• Adds StrType enum and labels for rendering, plus the response and item types used by the /popular UI and API client.

apps/web/src/types/tjChart.ts

crawlTjChart.tsMonthly TJ chart crawler (previous month) with unmatched logging +61/-0

Monthly TJ chart crawler (previous month) with unmatched logging

• Implements a cron script that computes the prior month interval, loads all songs with num_tj, fetches TJ TOP chart items for each genre, matches to song_id, and upserts rows. Unmatched items are appended to a local assets log file for later review.

packages/crawling/src/cron/crawlTjChart.ts

crawlTjChartBackfill.tsBackfill crawler for a fixed month interval with per-batch upserts +77/-0

Backfill crawler for a fixed month interval with per-batch upserts

• Adds a script to iterate month-by-month over a configured interval, fetch charts per genre, log a truncated console.table preview, and upsert month/genre batches immediately. Appends unmatched items to a separate backfill log file.

packages/crawling/src/cron/crawlTjChartBackfill.ts

postDB.tsAdd chart_rankings upsert helper +15/-1

Add chart_rankings upsert helper

• Introduces postTjChartRankingsDB which upserts ranking rows into chart_rankings using the (chart_month,type,rank) conflict key and returns a boolean success flag with error logging.

packages/crawling/src/supabase/postDB.ts

types.tsAdd TJ chart enums, API response types, and DB insert shape +76/-0

Add TJ chart enums, API response types, and DB insert shape

• Defines StrType, human labels, mapping to TJ API strType parameters, the TJ chart API response/item shapes, and the insert type used for chart_rankings upserts.

packages/crawling/src/types.ts

Refactor (1) +99 / -0
tjChart.tsExtract shared TJ chart fetch/match/log utilities +99/-0

Extract shared TJ chart fetch/match/log utilities

• Adds reusable helpers to call TJ’s legacy topAndHot100 endpoint, build a num_tj→song_id map, print chart previews via console.table, and convert chart items into DB upsert rows while collecting unmatched entries.

packages/crawling/src/utils/tjChart.ts

Other (2) +40 / -0
crawl_tj_chart.ymlAdd monthly GitHub Actions workflow to run TJ chart crawler +38/-0

Add monthly GitHub Actions workflow to run TJ chart crawler

• Introduces a scheduled (monthly) and manually-dispatchable workflow that installs pnpm deps, writes Supabase secrets into a crawling .env, and runs the tj-chart script.

.github/workflows/crawl_tj_chart.yml

package.jsonAdd crawling scripts for TJ chart and backfill +2/-0

Add crawling scripts for TJ chart and backfill

• Registers pnpm scripts to run crawlTjChart.ts for monthly ingestion and crawlTjChartBackfill.ts for historical backfill runs.

packages/crawling/package.json

@qodo-code-review

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (3) 📘 Rule violations (1) 📜 Skill insights (0)

Grey Divider


Action required

1. Incomplete month list 🐞 Bug ≡ Correctness
Description
GET /api/tj-chart가 chart_rankings의 모든 row에서 chart_month를 가져와 availableMonths를 만들기 때문에, Supabase 응답
row 제한/트렁케이션으로 오래된 월이 누락될 수 있습니다. 그 결과 월 선택 UI가 실제 DB에 있는 과거 월 데이터를 숨길 수 있습니다.
Code

apps/web/src/app/api/tj-chart/route.ts[R25-29]

+    // 1) 데이터가 존재하는 월 목록 조회
+    const { data: monthRows, error: monthError } = await supabase
+      .from('chart_rankings')
+      .select('chart_month')
+      .order('chart_month', { ascending: false });
Relevance

●●● Strong

API robustness fixes are typically accepted; query distinct months/paginate to avoid truncated month
list.

PR-#255
PR-#278

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
API는 chart_rankings의 모든 row에서 chart_month를 가져와 Set으로 dedup 하는데, 크롤러가 매월/장르/순위로 대량 row를 생성하므로 이 조회는
응답 제한에 걸려 일부 월이 누락될 수 있습니다. 레포의 다른 Supabase 조회 코드에서도 row 제한을 전제로 limit을 두고 있어(주석 포함) 같은 문제가 재현될 근거가
있습니다.

apps/web/src/app/api/tj-chart/route.ts[25-34]
packages/crawling/src/cron/crawlTjChart.ts[35-49]
packages/crawling/src/supabase/getDB.ts[36-45]

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/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



Remediation recommended

2. No crawl request timeout 🐞 Bug ☼ Reliability
Description
fetchTjChart의 axios.get에 timeout이 없어 네트워크 지연/서버 응답 정지 시 크롤링이 외부 러너 타임아웃까지 장시간 블록될 수 있습니다. 이 경우 월간
크롤링이 완료되지 않아 차트 데이터가 갱신되지 않을 수 있습니다.
Code

packages/crawling/src/utils/tjChart.ts[R18-21]

+  const { data } = await axios.get<TjChartApiResponse>(
+    'https://www.tjmedia.com/legacy/api/topAndHot100',
+    {
+      params: {
Relevance

●●● Strong

Adding axios timeout is a low-risk reliability hardening for cron scripts; likely accepted.

PR-#187

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
크롤링 유틸은 axios timeout을 설정하지 않고 있으며, 레포 내 다른 axios 사용처(웹 API 클라이언트)는 timeout을 명시적으로 두고 있어 크롤러만 예외적으로
무제한 대기 상태가 될 수 있음을 뒷받침합니다.

packages/crawling/src/utils/tjChart.ts[13-28]
apps/web/src/lib/api/client.ts[3-10]

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

### 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


3. crawlTjChartBackfill.ts missing checkpoint 📘 Rule violation ☼ Reliability
Description
The new TJ 차트 백필 스크립트는 여러 개월/장르를 순회하는 장시간 작업인데, 중단 시 재개할 수 있는 체크포인트를 src/assets/에 저장/로드하지 않습니다. 실행
중단 시 전체 재처리 또는 누락 가능성이 있어 요구사항을 충족하지 못합니다.
Code

packages/crawling/src/cron/crawlTjChartBackfill.ts[R41-44]

+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');
Relevance

●● Moderate

Checkpointing backfill is nontrivial and process-specific; no strong repository precedent confirming
requirement enforcement.

PR-#187

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
규칙 105302는 장시간 스크립트가 src/assets/ 하위 체크포인트 파일을 통해 재개 가능해야 함을 요구합니다. 현재 백필 스크립트는 여러 달/장르를 중첩 루프로
처리하지만(41-49행) 시작 시 체크포인트를 읽어 재개하는 로직이 없고, 종료 시점에 미매칭 로그만 기록(74-76행)하여 중단 시 재개가 불가능합니다.

Rule 105302: Checkpoint long-running scripts to resumable text files under src/assets
packages/crawling/src/cron/crawlTjChartBackfill.ts[41-49]
packages/crawling/src/cron/crawlTjChartBackfill.ts[74-76]

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

## 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


4. Unmatched log not retained 🐞 Bug ◔ Observability
Description
crawlTjChart가 미매칭 곡 목록을 로컬 txt 파일로 기록하지만, GitHub Actions 워크플로우가 해당 파일을 업로드/커밋하지 않아 실행 종료 후 데이터가
사라집니다. 이로 인해 정기 크롤링에서 매칭 실패 원인을 추적하기 어렵습니다.
Code

packages/crawling/src/cron/crawlTjChart.ts[R58-60]

+if (unmatched.length > 0) {
+  fs.appendFileSync(UNMATCHED_LOG_FILE, unmatched.join('\n') + '\n', 'utf-8');
+  console.log(`📝 미매칭 목록 기록: ${UNMATCHED_LOG_FILE}`);
Relevance

●● Moderate

Keeping logs via artifact/commit is useful but adds workflow complexity; no clear accept/reject
precedent.

PR-#187

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
크롤러는 미매칭을 파일에 append하지만, 워크플로우에는 실행 후 파일을 보존하는 단계가 없어 러너 종료와 함께 사라집니다.

packages/crawling/src/cron/crawlTjChart.ts[18-19]
packages/crawling/src/cron/crawlTjChart.ts[58-60]
.github/workflows/crawl_tj_chart.yml[26-38]

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

### 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


Grey Divider

Context used
✅ Compliance rules (platform): 45 rules

To customize comments, go to the Qodo configuration screen, or learn more in the docs.

Qodo Logo

Comment on lines +41 to +44
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');

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Remediation recommended

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

Comment on lines +25 to +29
// 1) 데이터가 존재하는 월 목록 조회
const { data: monthRows, error: monthError } = await supabase
.from('chart_rankings')
.select('chart_month')
.order('chart_month', { ascending: false });

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

Comment on lines +18 to +21
const { data } = await axios.get<TjChartApiResponse>(
'https://www.tjmedia.com/legacy/api/topAndHot100',
{
params: {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Remediation recommended

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

Comment on lines +58 to +60
if (unmatched.length > 0) {
fs.appendFileSync(UNMATCHED_LOG_FILE, unmatched.join('\n') + '\n', 'utf-8');
console.log(`📝 미매칭 목록 기록: ${UNMATCHED_LOG_FILE}`);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Remediation recommended

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

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.

TJ 노래방 공식 차트 API 연동으로 popular 페이지 개편

1 participant