Skip to content

TWA 세팅 및 적용#270

Merged
GulSam00 merged 15 commits into
mainfrom
develop
Jul 5, 2026
Merged

TWA 세팅 및 적용#270
GulSam00 merged 15 commits into
mainfrom
develop

Conversation

@GulSam00

@GulSam00 GulSam00 commented Jul 5, 2026

Copy link
Copy Markdown
Owner

📌 PR 제목

[Type] : 작업 내용 요약

📌 변경 사항

  • bubblewrap으로 웹 앱 안드로이드 빌드
  • 안드로이드 개발자 계정 만들고 업로드 후 테스트

💬 추가 참고 사항

GulSam00 and others added 15 commits June 12, 2026 01:58
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ector

[Refactor] : 크롤링 element selector 명확하게 지정 및 DB limit 상향 (#262)
…racy

[Fix] : TJ 번호 크롤링 제목/가수 셀렉터 정확도 개선 (#264)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
[Chore] : Google Play Store 등록 준비 및 앱 메타데이터 정비 (#268)
@vercel

vercel Bot commented Jul 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, Comment Jul 5, 2026 6:28am

@GulSam00 GulSam00 merged commit 1e302ae into main Jul 5, 2026
1 check passed
@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

TWA Google Play 등록 준비 및 TJ 크롤링 병렬화

✨ Enhancement ⚙️ Configuration changes 🕐 20-40 Minutes

Grey Divider

AI Description

• TWA(Trusted Web Activity) 매니페스트를 버전 3으로 업데이트하고, 다크테마 색상 통일·알림 활성화·불필요한 feature 제거 등 Google Play 등록
 준비를 완료함
• assetlinks.json에 Play 앱 서명 키 SHA-256 핑거프린트를 추가하여 TWA 검증 연결을 완성함
• TJ 전곡 번호 크롤링 워크플로우를 단일 순차 실행에서 10개 구간 병렬 matrix 실행으로 교체하여 GitHub Actions 6시간 제한 내 전체 범위(1~99999)
 처리 가능하게 함
• TJ 크롤링 셀렉터를 span 기준으로 수정하여 중첩 아이콘 요소로 인한 제목/가수 오추출 버그를 수정함
• Supabase DB 쿼리 limit을 50,000에서 100,000으로 상향하고, 일부 워크플로우 cron 스케줄을 조정함
• SEO 메타데이터 문구를 "노래방 메모장"에서 "노래방 번호 검색" 중심으로 개선함
Diagram

graph TD
    subgraph TWA["TWA / Play Store"]
        TM["twa-manifest.json"] --> AL["assetlinks.json"]
    end

    subgraph Web["Next.js Web App"]
        LY["layout.tsx\n(SEO metadata)"]
    end

    subgraph CI["GitHub Actions"]
        WF_NEW["crawl_tj_all_number.yml\n(matrix × 10)"] --> ENV["START/END env vars"]
        WF_TAG["tagging_song.yml\n(daily)"] 
        WF_TRN["translation_jpn.yml\n(daily)"]
        WF_VFY["verify_ky_youtube.yml\n(weekly)"]
    end

    subgraph Crawling["packages/crawling"]
        ENV --> CRON["crawlAllTJSongByNumber.ts"]
        CRON --> CRAWL["crawlTJSongByNumber.ts\n(span selector fix)"]
        CRON --> DB[("Supabase DB\nlimit 100k")]
    end

    WF_NEW --> CRON

    subgraph Legend
        direction LR
        _ci["CI Workflow"] ~~~ _ts["TypeScript Module"] ~~~ _db[("Database")]
    end
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Supabase Edge Function / 배치 upsert 활용
  • ➕ DB 왕복 횟수를 대폭 줄여 처리 속도 향상
  • ➕ Supabase rate limit 위험 감소
  • ➖ 크롤링 로직을 Edge Function으로 이전하거나 배치 버퍼링 코드 추가 필요
  • ➖ 구현 복잡도 증가
2. matrix 구간별 concurrency 제한 추가
  • ➕ 동시 실행 잡 수를 제한해 Supabase 부하 조절 가능
  • ➕ 기존 코드 변경 최소화
  • ➖ 전체 완료 시간이 늘어남

Recommendation: 현재 PR의 matrix 병렬화 접근은 GitHub Actions 6시간 제한 내에서 99,999개 번호를 처리하기 위한 실용적인 선택입니다. 다만 10개 잡이 동시에 Supabase에 쓰기 요청을 보내므로 DB 부하 및 rate limit 위험이 있습니다.

Files changed (11) +116 / -39

Enhancement (2) +10 / -11
layout.tsxSEO 메타데이터 문구를 '노래방 번호 검색' 중심으로 개선 +4/-5

SEO 메타데이터 문구를 '노래방 번호 검색' 중심으로 개선

• title과 description을 '노래방 메모장/저장' 중심에서 '노래방 번호 검색 + J-POP 지원' 중심으로 변경했습니다. OpenGraph title/description도 동일하게 통일했습니다.

apps/web/src/app/layout.tsx

getDB.tsSupabase DB 쿼리 limit을 50,000에서 100,000으로 상향 +6/-6

Supabase DB 쿼리 limit을 50,000에서 100,000으로 상향

• 6개 쿼리 함수('getSongsKyNullDB', 'getSongsKyNotNullDB', 'getSongsAllDB', 'getJpopSongsForTranslationDB', 'getArtistKoMapDB', 'getSongTagSongIdsDB')의 기본 limit을 50,000에서 100,000으로 두 배 상향했습니다.

packages/crawling/src/supabase/getDB.ts

Bug fix (1) +4 / -2
crawlTJSongByNumber.tsTJ 크롤링 제목/가수 셀렉터를 span 기준으로 수정하여 오추출 버그 수정 +4/-2

TJ 크롤링 제목/가수 셀렉터를 span 기준으로 수정하여 오추출 버그 수정

• '.grid-item.title3'과 '.grid-item.title4'에서 텍스트를 직접 추출하던 방식을 '.grid-item.title3 span'과 '.grid-item.title4 span'으로 변경했습니다. 기존 방식은 내부에 중첩된 아이콘용 '<p class="no-ico">' 요소의 텍스트까지 포함하여 제목/가수가 오추출되는 문제가 있었습니다.

packages/crawling/src/crawling/crawlTJSongByNumber.ts

Refactor (1) +14 / -3
crawlAllTJSongByNumber.ts크롤링 범위를 환경변수로 주입받도록 리팩터링 +14/-3

크롤링 범위를 환경변수로 주입받도록 리팩터링

• 하드코딩된 'START_NUMBER'/'END_NUMBER' 상수를 'process.env'에서 파싱하는 'parseRange' 함수로 교체했습니다. 잘못된 범위(start > end) 입력 시 즉시 에러를 던지는 유효성 검사도 추가했습니다.

packages/crawling/src/cron/crawlAllTJSongByNumber.ts

Other (7) +88 / -23
twa-manifest.jsonTWA 매니페스트 버전 3 업데이트 및 Play Store 등록 준비 +21/-19

TWA 매니페스트 버전 3 업데이트 및 Play Store 등록 준비

• 앱 이름을 '싱코드(singcode) - 노래방 번호 검색'으로 변경하고, 다크테마 색상('themeColorDark') 추가 및 모든 색상값을 '#1A1A2E'로 통일했습니다. 'enableNotifications'를 true로 활성화하고, 'locationDelegation'·'playBilling' 등 불필요한 feature를 제거했습니다. 버전을 1.0.0/1에서 3으로 올리고 'fingerprints', 'additionalTrustedOrigins' 등 bubblewrap 최신 필드를 추가했습니다.

apps/twa/twa-manifest.json

assetlinks.jsonPlay 앱 서명 키 SHA-256 핑거프린트 추가 +2/-1

Play 앱 서명 키 SHA-256 핑거프린트 추가

• Google Play 앱 서명(App Signing)에서 발급된 새 SHA-256 인증서 핑거프린트를 'sha256_cert_fingerprints' 배열에 추가했습니다. 이를 통해 TWA가 Play Store 배포 빌드에서도 정상적으로 검증됩니다.

apps/web/public/.well-known/assetlinks.json

crawl_tj_all_number.ymlTJ 전곡 크롤링 워크플로우를 10개 구간 병렬 matrix로 교체 +61/-0

TJ 전곡 크롤링 워크플로우를 10개 구간 병렬 matrix로 교체

• 기존 단일 순차 실행 워크플로우('crawl_tj_by_number.yml')를 삭제하고, 1~99999 범위를 1만 단위 10개 구간으로 나눠 병렬 실행하는 새 워크플로우를 추가했습니다. 'fail-fast: false'로 일부 구간 실패 시에도 나머지 구간이 계속 실행되며, 'START_NUMBER'/'END_NUMBER' 환경변수를 matrix에서 주입합니다.

.github/workflows/crawl_tj_all_number.yml

tagging_song.ymltagging_song 워크플로우 cron을 매주 월요일에서 매일 실행으로 변경 +1/-1

tagging_song 워크플로우 cron을 매주 월요일에서 매일 실행으로 변경

• cron 스케줄을 '0 10 * * 1'(매주 월요일 19:00 KST)에서 '0 7 * * *'(매일 16:00 KST)으로 변경했습니다.

.github/workflows/tagging_song.yml

translation_jpn.ymltranslation_jpn 워크플로우 cron을 매주 금요일에서 매일 실행으로 변경 +1/-1

translation_jpn 워크플로우 cron을 매주 금요일에서 매일 실행으로 변경

• cron 스케줄을 '0 10 * * 5'(매주 금요일)에서 '0 10 * * *'(매일 19:00 KST)으로 변경했습니다.

.github/workflows/translation_jpn.yml

verify_ky_youtube.ymlverify_ky_youtube 워크플로우 cron을 매일에서 매주 월요일로 변경 +1/-1

verify_ky_youtube 워크플로우 cron을 매일에서 매주 월요일로 변경

• cron 스케줄을 '0 14 * * *'(매일 23:00 KST)에서 '0 14 * * 1'(매주 월요일 23:00 KST)으로 변경했습니다.

.github/workflows/verify_ky_youtube.yml

package.jsontj-all-number 스크립트 추가 +1/-0

tj-all-number 스크립트 추가

• 'crawlAllTJSongByNumber.ts'를 실행하는 'tj-all-number' npm 스크립트를 추가했습니다.

packages/crawling/package.json

@qodo-code-review

Copy link
Copy Markdown

Code Review by Qodo

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

Context used
✅ Compliance rules (platform): 55 rules

Grey Divider


Action required

1. themeColor not #1a1a2e 📘 Rule violation ≡ Correctness
Description
apps/twa/twa-manifest.json sets themeColor to #1A1A2E instead of the required lowercase
#1a1a2e. This can break enforcement checks that expect the exact string and violates the mandated
theme color value.
Code

apps/twa/twa-manifest.json[7]

+  "themeColor": "#1A1A2E",
Evidence
PR Compliance ID 466906 requires themeColor to be exactly "#1a1a2e". The changed manifest sets
themeColor to "#1A1A2E", which does not match the required value.

Rule 466906: Enforce TWA manifest theme color
apps/twa/twa-manifest.json[7-7]

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

## Issue description
`twa-manifest.json` must enforce `themeColor` exactly as `"#1a1a2e"` (lowercase), but the PR sets it to `"#1A1A2E"`.

## Issue Context
Compliance rule requires an exact string match for the TWA manifest theme color.

## Fix Focus Areas
- apps/twa/twa-manifest.json[7-7]

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


2. DB queries truncate silently 🐞 Bug ≡ Correctness
Description
Several getDB() helpers use .limit(100000) without pagination, but callers treat the results as
complete (e.g., building num_tj maps or “already tagged” sets). Once tables exceed 100k rows, this
silently breaks dedupe/skip logic and can lead to duplicate inserts or redundant processing.
Code

packages/crawling/src/supabase/getDB.ts[R88-91]

+export async function getSongsAllDB(max: number = 100000) {
  const supabase = getClient();

  const { data, error } = await supabase
Evidence
The DB helpers cap result sets, while cron jobs use those results as authoritative sources for
whether a song already exists / is already tagged; truncation therefore directly breaks correctness
once table sizes exceed the cap.

packages/crawling/src/supabase/getDB.ts[88-115]
packages/crawling/src/supabase/getDB.ts[155-163]
packages/crawling/src/cron/taggingSongs.ts[11-28]
packages/crawling/src/cron/crawlAllTJSongByNumber.ts[27-65]

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

## Issue description
Supabase fetch helpers (e.g., `getSongsAllDB`, `getSongsAllWithTjDB`, `getSongTagSongIdsDB`) hard-cap results via `.limit(100000)` and return only the first page. Downstream jobs assume these are complete datasets for deduplication/skip decisions, so once any underlying table grows beyond the limit the jobs will silently behave incorrectly (re-tag already-tagged songs, miss existing TJ numbers and attempt inserts, etc.).

## Issue Context
- `taggingSongs.ts` loads *all songs* and *all tagged song IDs* to skip work.
- `crawlAllTJSongByNumber.ts` loads *all songs with num_tj* to decide whether to insert/update.
- Current fetch helpers do not implement pagination (`.range(...)`) or any loop until exhaustion.

## Fix Focus Areas
- packages/crawling/src/supabase/getDB.ts[88-115]
- packages/crawling/src/supabase/getDB.ts[155-163]
- packages/crawling/src/cron/taggingSongs.ts[11-28]
- packages/crawling/src/cron/crawlAllTJSongByNumber.ts[27-65]

## Suggested fix
1. Implement pagination utilities in `getDB.ts` (e.g., fetch in pages of 1000/5000 using `.range(offset, offset+pageSize-1)` until a page returns fewer than `pageSize`).
2. Update `getSongsAllWithTjDB()` and `getSongTagSongIdsDB()` to use pagination and return complete results (or, if “complete” is not required, rename functions to reflect partial reads and adjust callers accordingly).
3. Consider filtering server-side to reduce result size (e.g., `not('num_tj','is',null)` for the TJ map case).

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



Remediation recommended

3. Excessive Supabase overfetch 🐞 Bug ➹ Performance
Description
The default max for several DB fetch functions was increased to 100,000, but callers often process
only a small prefix (e.g., verify job stops at 5,000; tagging stops at 20,000). This creates
unnecessary data transfer and memory usage each run.
Code

packages/crawling/src/supabase/getDB.ts[R51-54]

+export async function getSongsKyNotNullDB(max: number = 100000) {
  const supabase = getClient();

  const { data, error } = await supabase
Evidence
The callers clearly stop early, while the DB functions default to fetching up to 100k rows, so the
added default increases unnecessary work each run.

packages/crawling/src/supabase/getDB.ts[36-64]
packages/crawling/src/supabase/getDB.ts[88-96]
packages/crawling/src/cron/crawlYoutubeVerify.ts[19-49]
packages/crawling/src/cron/taggingSongs.ts[11-24]

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

## Issue description
`getSongsKyNotNullDB()` (and other helpers) now default to `max=100000`, but some cron scripts intentionally stop after processing a much smaller number of rows. Fetching far more rows than needed increases bandwidth/memory and can slow down scheduled runs.

## Issue Context
- `crawlYoutubeVerify.ts` breaks after 5,000 items but currently calls `getSongsKyNotNullDB()` with default max.
- `taggingSongs.ts` breaks after 20,000 items but calls `getSongsAllDB()` with default max.

## Fix Focus Areas
- packages/crawling/src/supabase/getDB.ts[36-64]
- packages/crawling/src/supabase/getDB.ts[88-100]
- packages/crawling/src/cron/crawlYoutubeVerify.ts[19-49]
- packages/crawling/src/cron/taggingSongs.ts[11-24]

## Suggested fix
- Pass explicit caps from callers matching their processing limits (e.g., `getSongsKyNotNullDB(5000)` and `getSongsAllDB(20000)`).
- Alternatively, change defaults back to smaller values and require explicit `max` for “full table” use-cases (paired with pagination from the other finding).

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


4. Workflow has write permission 🐞 Bug ⛨ Security
Description
The new crawl workflow requests contents: write even though it only checks out code and runs
scripts. This unnecessarily expands the blast radius if the workflow is ever compromised.
Code

.github/workflows/crawl_tj_all_number.yml[R6-8]

+permissions:
+  contents: write
+
Evidence
The workflow’s steps do not perform any git write operation, so contents: write is not required
for its current behavior.

.github/workflows/crawl_tj_all_number.yml[6-61]

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 workflow declares `permissions: contents: write` but does not appear to push commits/tags/releases. Granting write access is unnecessary and increases risk.

## Issue Context
Steps: checkout, setup node/pnpm, install deps, write `.env`, run `pnpm run tj-all-number`.

## Fix Focus Areas
- .github/workflows/crawl_tj_all_number.yml[6-8]

## Suggested fix
- Change to `permissions: contents: read` (or remove the block entirely to use the default minimal permissions), unless a later step truly requires write access.

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



Informational

5. Misleading TJ selector comment 🐞 Bug ⚙ Maintainability
Description
The comment says to use a direct-child > p selector to avoid nested icon markup, but the
implementation selects span elements instead. This mismatch makes future maintenance risky because
the rationale and the actual selector no longer align.
Code

packages/crawling/src/crawling/crawlTJSongByNumber.ts[R25-28]

+  // title3 내부에는 아이콘용 <p class="no-ico">가 div.flex-box > ul 안에 중첩돼 있으므로
+  // 자손 셀렉터(' p') 대신 직계 자식(' > p')만 선택해 실제 제목만 추출한다.
+  const title = gridContainer.find('.grid-item.title3 span').text().trim();
+  const artist = gridContainer.find('.grid-item.title4 span').text().trim();
Evidence
The comment explicitly references a > p approach, but the code uses span; another crawler in
this repo demonstrates TJ markup can require careful element selection, so keeping the rationale
accurate matters.

packages/crawling/src/crawling/crawlTJSongByNumber.ts[23-33]
packages/crawling/src/cron/crawlRecentTJ.ts[39-44]

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

## Issue description
`crawlTJSongByNumber()` includes a comment describing a `> p` direct-child strategy, but the code uses `.find('... span')`. This discrepancy is confusing and can cause incorrect future edits.

## Issue Context
A separate TJ crawler parses title text from nested `<p>` elements, so the exact DOM structure is subtle and should be documented accurately.

## Fix Focus Areas
- packages/crawling/src/crawling/crawlTJSongByNumber.ts[25-28]

## Suggested fix
- Either update the comment to match the current `span`-based extraction (and explain why `span` is correct), or update the selector to match the documented `> p` approach.
- Consider adding a small unit/regression test with a saved HTML fixture to lock the intended extraction behavior.

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


Grey Divider

Qodo Logo

"navigationDividerColorDark": "#1a1a2e",
"backgroundColor": "#1a1a2e",
"enableNotifications": false,
"themeColor": "#1A1A2E",

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. themecolor not #1a1a2e 📘 Rule violation ≡ Correctness

apps/twa/twa-manifest.json sets themeColor to #1A1A2E instead of the required lowercase
#1a1a2e. This can break enforcement checks that expect the exact string and violates the mandated
theme color value.
Agent Prompt
## Issue description
`twa-manifest.json` must enforce `themeColor` exactly as `"#1a1a2e"` (lowercase), but the PR sets it to `"#1A1A2E"`.

## Issue Context
Compliance rule requires an exact string match for the TWA manifest theme color.

## Fix Focus Areas
- apps/twa/twa-manifest.json[7-7]

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

Comment on lines +88 to 91
export async function getSongsAllDB(max: number = 100000) {
const supabase = getClient();

const { data, error } = await supabase

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. Db queries truncate silently 🐞 Bug ≡ Correctness

Several getDB() helpers use .limit(100000) without pagination, but callers treat the results as
complete (e.g., building num_tj maps or “already tagged” sets). Once tables exceed 100k rows, this
silently breaks dedupe/skip logic and can lead to duplicate inserts or redundant processing.
Agent Prompt
## Issue description
Supabase fetch helpers (e.g., `getSongsAllDB`, `getSongsAllWithTjDB`, `getSongTagSongIdsDB`) hard-cap results via `.limit(100000)` and return only the first page. Downstream jobs assume these are complete datasets for deduplication/skip decisions, so once any underlying table grows beyond the limit the jobs will silently behave incorrectly (re-tag already-tagged songs, miss existing TJ numbers and attempt inserts, etc.).

## Issue Context
- `taggingSongs.ts` loads *all songs* and *all tagged song IDs* to skip work.
- `crawlAllTJSongByNumber.ts` loads *all songs with num_tj* to decide whether to insert/update.
- Current fetch helpers do not implement pagination (`.range(...)`) or any loop until exhaustion.

## Fix Focus Areas
- packages/crawling/src/supabase/getDB.ts[88-115]
- packages/crawling/src/supabase/getDB.ts[155-163]
- packages/crawling/src/cron/taggingSongs.ts[11-28]
- packages/crawling/src/cron/crawlAllTJSongByNumber.ts[27-65]

## Suggested fix
1. Implement pagination utilities in `getDB.ts` (e.g., fetch in pages of 1000/5000 using `.range(offset, offset+pageSize-1)` until a page returns fewer than `pageSize`).
2. Update `getSongsAllWithTjDB()` and `getSongTagSongIdsDB()` to use pagination and return complete results (or, if “complete” is not required, rename functions to reflect partial reads and adjust callers accordingly).
3. Consider filtering server-side to reduce result size (e.g., `not('num_tj','is',null)` for the TJ map case).

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

Comment on lines +51 to 54
export async function getSongsKyNotNullDB(max: number = 100000) {
const supabase = getClient();

const { data, error } = await supabase

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. Excessive supabase overfetch 🐞 Bug ➹ Performance

The default max for several DB fetch functions was increased to 100,000, but callers often process
only a small prefix (e.g., verify job stops at 5,000; tagging stops at 20,000). This creates
unnecessary data transfer and memory usage each run.
Agent Prompt
## Issue description
`getSongsKyNotNullDB()` (and other helpers) now default to `max=100000`, but some cron scripts intentionally stop after processing a much smaller number of rows. Fetching far more rows than needed increases bandwidth/memory and can slow down scheduled runs.

## Issue Context
- `crawlYoutubeVerify.ts` breaks after 5,000 items but currently calls `getSongsKyNotNullDB()` with default max.
- `taggingSongs.ts` breaks after 20,000 items but calls `getSongsAllDB()` with default max.

## Fix Focus Areas
- packages/crawling/src/supabase/getDB.ts[36-64]
- packages/crawling/src/supabase/getDB.ts[88-100]
- packages/crawling/src/cron/crawlYoutubeVerify.ts[19-49]
- packages/crawling/src/cron/taggingSongs.ts[11-24]

## Suggested fix
- Pass explicit caps from callers matching their processing limits (e.g., `getSongsKyNotNullDB(5000)` and `getSongsAllDB(20000)`).
- Alternatively, change defaults back to smaller values and require explicit `max` for “full table” use-cases (paired with pagination from the other finding).

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

Comment on lines +6 to +8
permissions:
contents: write

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. Workflow has write permission 🐞 Bug ⛨ Security

The new crawl workflow requests contents: write even though it only checks out code and runs
scripts. This unnecessarily expands the blast radius if the workflow is ever compromised.
Agent Prompt
## Issue description
The workflow declares `permissions: contents: write` but does not appear to push commits/tags/releases. Granting write access is unnecessary and increases risk.

## Issue Context
Steps: checkout, setup node/pnpm, install deps, write `.env`, run `pnpm run tj-all-number`.

## Fix Focus Areas
- .github/workflows/crawl_tj_all_number.yml[6-8]

## Suggested fix
- Change to `permissions: contents: read` (or remove the block entirely to use the default minimal permissions), unless a later step truly requires write access.

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

Comment on lines +25 to +28
// title3 내부에는 아이콘용 <p class="no-ico">가 div.flex-box > ul 안에 중첩돼 있으므로
// 자손 셀렉터(' p') 대신 직계 자식(' > p')만 선택해 실제 제목만 추출한다.
const title = gridContainer.find('.grid-item.title3 span').text().trim();
const artist = gridContainer.find('.grid-item.title4 span').text().trim();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Informational

5. Misleading tj selector comment 🐞 Bug ⚙ Maintainability

The comment says to use a direct-child > p selector to avoid nested icon markup, but the
implementation selects span elements instead. This mismatch makes future maintenance risky because
the rationale and the actual selector no longer align.
Agent Prompt
## Issue description
`crawlTJSongByNumber()` includes a comment describing a `> p` direct-child strategy, but the code uses `.find('... span')`. This discrepancy is confusing and can cause incorrect future edits.

## Issue Context
A separate TJ crawler parses title text from nested `<p>` elements, so the exact DOM structure is subtle and should be documented accurately.

## Fix Focus Areas
- packages/crawling/src/crawling/crawlTJSongByNumber.ts[25-28]

## Suggested fix
- Either update the comment to match the current `span`-based extraction (and explain why `span` is correct), or update the selector to match the documented `> p` approach.
- Consider adding a small unit/regression test with a saved HTML fixture to lock the intended extraction behavior.

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

1 participant