From 30d03fda68b7371828f87f1f6727243fd57c6009 Mon Sep 17 00:00:00 2001 From: moony01 Date: Wed, 3 Jun 2026 16:57:20 +0900 Subject: [PATCH 1/8] chore(kcl): run one-time THE MUZE data patch --- .github/workflows/kcl-data-patch-the-muze.yml | 95 +++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 .github/workflows/kcl-data-patch-the-muze.yml diff --git a/.github/workflows/kcl-data-patch-the-muze.yml b/.github/workflows/kcl-data-patch-the-muze.yml new file mode 100644 index 0000000..f1b1a83 --- /dev/null +++ b/.github/workflows/kcl-data-patch-the-muze.yml @@ -0,0 +1,95 @@ +name: KCL Data Patch - Replace H Music with THE MUZE + +on: + push: + branches: + - ops/replace-hmusic-the-muze-20260603 + workflow_dispatch: + +jobs: + replace-hmusic-the-muze: + runs-on: ubuntu-latest + timeout-minutes: 5 + env: + SUPABASE_URL: ${{ secrets.SUPABASE_URL }} + SUPABASE_SERVICE_ROLE_KEY: ${{ secrets.SUPABASE_SERVICE_ROLE_KEY }} + COMPANY_ID: 9e920899-4937-4c61-9aa6-5539e4953d2b + GROUP_ID: 62e5a962-66a1-4f9b-9271-676039888d7f + steps: + - name: Patch company and artist rows + shell: bash + run: | + set -euo pipefail + + if [ -z "${SUPABASE_URL:-}" ] || [ -z "${SUPABASE_SERVICE_ROLE_KEY:-}" ]; then + echo "Missing Supabase secrets" >&2 + exit 1 + fi + + api() { + local method="$1" + local path="$2" + local body="${3:-}" + if [ -n "$body" ]; then + curl -fsS -X "$method" \ + "${SUPABASE_URL}/rest/v1/${path}" \ + -H "apikey: ${SUPABASE_SERVICE_ROLE_KEY}" \ + -H "Authorization: Bearer ${SUPABASE_SERVICE_ROLE_KEY}" \ + -H "Content-Type: application/json" \ + -H "Accept: application/json" \ + -H "Prefer: return=representation" \ + --data "$body" + else + curl -fsS -X "$method" \ + "${SUPABASE_URL}/rest/v1/${path}" \ + -H "apikey: ${SUPABASE_SERVICE_ROLE_KEY}" \ + -H "Authorization: Bearer ${SUPABASE_SERVICE_ROLE_KEY}" \ + -H "Accept: application/json" + fi + } + + before_company=$(api GET "kcl_companies?id=eq.${COMPANY_ID}&select=id,name_ko,name_en,slug,rank,firepower,league_tier,previous_season_rank,deleted_at") + before_group=$(api GET "kcl_groups?id=eq.${GROUP_ID}&select=id,company_id,name_ko,name_en,slug,vote_count,is_active,debut_date,member_count,group_type") + + echo "Before company: ${before_company}" + echo "Before group: ${before_group}" + + python3 - <<'PY' "$before_company" "$before_group" +import json, sys +company = json.loads(sys.argv[1]) +group = json.loads(sys.argv[2]) +if len(company) != 1 or company[0].get('name_en') != 'H Music': + raise SystemExit(f"Unexpected company row before patch: {company}") +if len(group) != 1 or group[0].get('name_en') != 'woo!ah!': + raise SystemExit(f"Unexpected group row before patch: {group}") +PY + + api PATCH "kcl_companies?id=eq.${COMPANY_ID}" '{"name_ko":"더뮤즈","name_en":"THE MUZE","slug":"the-muze","logo_url":null,"gradient_color":"#A855F7"}' >/tmp/patched_company.json + api PATCH "kcl_groups?id=eq.${GROUP_ID}" '{"name_ko":"리센느","name_en":"RESCENE","slug":"rescene","debut_date":"2024-03-26","member_count":5,"group_type":"girl","is_active":true}' >/tmp/patched_group.json + + after_company=$(api GET "kcl_companies?id=eq.${COMPANY_ID}&select=id,name_ko,name_en,slug,rank,firepower,league_tier,previous_season_rank,deleted_at") + after_group=$(api GET "kcl_groups?id=eq.${GROUP_ID}&select=id,company_id,name_ko,name_en,slug,vote_count,is_active,debut_date,member_count,group_type") + top_list=$(api GET "kcl_companies?select=name_en,name_ko,slug,firepower,league_tier,previous_season_rank,groups:kcl_groups(name_en,name_ko,slug,is_active,debut_date)&deleted_at=is.null&order=firepower.desc,previous_season_rank.asc&limit=12") + + echo "After company: ${after_company}" + echo "After group: ${after_group}" + echo "Top list after patch: ${top_list}" + + python3 - <<'PY' "$after_company" "$after_group" "$top_list" +import json, sys +company = json.loads(sys.argv[1]) +group = json.loads(sys.argv[2]) +top = json.loads(sys.argv[3]) +assert len(company) == 1, company +c = company[0] +assert c['name_en'] == 'THE MUZE' and c['name_ko'] == '더뮤즈' and c['slug'] == 'the-muze', c +assert c['league_tier'] == 'premier' and c['previous_season_rank'] == 6, c +assert len(group) == 1, group +g = group[0] +assert g['name_en'] == 'RESCENE' and g['name_ko'] == '리센느' and g['slug'] == 'rescene', g +assert g['debut_date'] == '2024-03-26' and g['member_count'] == 5 and g['is_active'] is True, g +names = [item['name_en'] for item in top] +assert 'THE MUZE' in names, names +assert 'H Music' not in names, names +print('VERIFIED: THE MUZE / RESCENE replaced H Music / woo!ah! in live KCL DB') +PY From 5b06ef716b97371c563a4bc5b19c6361e3fb53b7 Mon Sep 17 00:00:00 2001 From: moony01 Date: Wed, 3 Jun 2026 16:58:46 +0900 Subject: [PATCH 2/8] fix(kcl): correct one-time data patch workflow --- .github/workflows/kcl-data-patch-the-muze.yml | 50 +++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/.github/workflows/kcl-data-patch-the-muze.yml b/.github/workflows/kcl-data-patch-the-muze.yml index f1b1a83..964f99a 100644 --- a/.github/workflows/kcl-data-patch-the-muze.yml +++ b/.github/workflows/kcl-data-patch-the-muze.yml @@ -55,14 +55,14 @@ jobs: echo "Before group: ${before_group}" python3 - <<'PY' "$before_company" "$before_group" -import json, sys -company = json.loads(sys.argv[1]) -group = json.loads(sys.argv[2]) -if len(company) != 1 or company[0].get('name_en') != 'H Music': - raise SystemExit(f"Unexpected company row before patch: {company}") -if len(group) != 1 or group[0].get('name_en') != 'woo!ah!': - raise SystemExit(f"Unexpected group row before patch: {group}") -PY + import json, sys + company = json.loads(sys.argv[1]) + group = json.loads(sys.argv[2]) + if len(company) != 1 or company[0].get('name_en') != 'H Music': + raise SystemExit(f"Unexpected company row before patch: {company}") + if len(group) != 1 or group[0].get('name_en') != 'woo!ah!': + raise SystemExit(f"Unexpected group row before patch: {group}") + PY api PATCH "kcl_companies?id=eq.${COMPANY_ID}" '{"name_ko":"더뮤즈","name_en":"THE MUZE","slug":"the-muze","logo_url":null,"gradient_color":"#A855F7"}' >/tmp/patched_company.json api PATCH "kcl_groups?id=eq.${GROUP_ID}" '{"name_ko":"리센느","name_en":"RESCENE","slug":"rescene","debut_date":"2024-03-26","member_count":5,"group_type":"girl","is_active":true}' >/tmp/patched_group.json @@ -76,20 +76,20 @@ PY echo "Top list after patch: ${top_list}" python3 - <<'PY' "$after_company" "$after_group" "$top_list" -import json, sys -company = json.loads(sys.argv[1]) -group = json.loads(sys.argv[2]) -top = json.loads(sys.argv[3]) -assert len(company) == 1, company -c = company[0] -assert c['name_en'] == 'THE MUZE' and c['name_ko'] == '더뮤즈' and c['slug'] == 'the-muze', c -assert c['league_tier'] == 'premier' and c['previous_season_rank'] == 6, c -assert len(group) == 1, group -g = group[0] -assert g['name_en'] == 'RESCENE' and g['name_ko'] == '리센느' and g['slug'] == 'rescene', g -assert g['debut_date'] == '2024-03-26' and g['member_count'] == 5 and g['is_active'] is True, g -names = [item['name_en'] for item in top] -assert 'THE MUZE' in names, names -assert 'H Music' not in names, names -print('VERIFIED: THE MUZE / RESCENE replaced H Music / woo!ah! in live KCL DB') -PY + import json, sys + company = json.loads(sys.argv[1]) + group = json.loads(sys.argv[2]) + top = json.loads(sys.argv[3]) + assert len(company) == 1, company + c = company[0] + assert c['name_en'] == 'THE MUZE' and c['name_ko'] == '더뮤즈' and c['slug'] == 'the-muze', c + assert c['league_tier'] == 'premier' and c['previous_season_rank'] == 6, c + assert len(group) == 1, group + g = group[0] + assert g['name_en'] == 'RESCENE' and g['name_ko'] == '리센느' and g['slug'] == 'rescene', g + assert g['debut_date'] == '2024-03-26' and g['member_count'] == 5 and g['is_active'] is True, g + names = [item['name_en'] for item in top] + assert 'THE MUZE' in names, names + assert 'H Music' not in names, names + print('VERIFIED: THE MUZE / RESCENE replaced H Music / woo!ah! in live KCL DB') + PY From c8c97408cf4c88ed5efd704c2f4b6e3bddb1e202 Mon Sep 17 00:00:00 2001 From: moony01 Date: Wed, 3 Jun 2026 17:05:30 +0900 Subject: [PATCH 3/8] chore(kcl): add Starship logo URL patch --- .github/workflows/kcl-data-patch-the-muze.yml | 68 +++++++++---------- src/lib/mock-data.ts | 1 + 2 files changed, 32 insertions(+), 37 deletions(-) diff --git a/.github/workflows/kcl-data-patch-the-muze.yml b/.github/workflows/kcl-data-patch-the-muze.yml index 964f99a..923a40b 100644 --- a/.github/workflows/kcl-data-patch-the-muze.yml +++ b/.github/workflows/kcl-data-patch-the-muze.yml @@ -1,4 +1,4 @@ -name: KCL Data Patch - Replace H Music with THE MUZE +name: KCL Data Patch - Add Starship Logo on: push: @@ -7,16 +7,16 @@ on: workflow_dispatch: jobs: - replace-hmusic-the-muze: + add-starship-logo: runs-on: ubuntu-latest timeout-minutes: 5 env: SUPABASE_URL: ${{ secrets.SUPABASE_URL }} SUPABASE_SERVICE_ROLE_KEY: ${{ secrets.SUPABASE_SERVICE_ROLE_KEY }} - COMPANY_ID: 9e920899-4937-4c61-9aa6-5539e4953d2b - GROUP_ID: 62e5a962-66a1-4f9b-9271-676039888d7f + STARSHIP_SLUG: starship-entertainment + STARSHIP_LOGO_URL: https://upload.wikimedia.org/wikipedia/commons/e/e7/Starship_Entertainment_New_Logo.png steps: - - name: Patch company and artist rows + - name: Patch Starship logo URL shell: bash run: | set -euo pipefail @@ -26,6 +26,8 @@ jobs: exit 1 fi + curl -fsSI "${STARSHIP_LOGO_URL}" | grep -qi 'content-type: image/png' + api() { local method="$1" local path="$2" @@ -48,48 +50,40 @@ jobs: fi } - before_company=$(api GET "kcl_companies?id=eq.${COMPANY_ID}&select=id,name_ko,name_en,slug,rank,firepower,league_tier,previous_season_rank,deleted_at") - before_group=$(api GET "kcl_groups?id=eq.${GROUP_ID}&select=id,company_id,name_ko,name_en,slug,vote_count,is_active,debut_date,member_count,group_type") - - echo "Before company: ${before_company}" - echo "Before group: ${before_group}" + before_company=$(api GET "kcl_companies?slug=eq.${STARSHIP_SLUG}&deleted_at=is.null&select=id,name_ko,name_en,slug,logo_url,gradient_color,league_tier,previous_season_rank") + echo "Before Starship: ${before_company}" - python3 - <<'PY' "$before_company" "$before_group" + python3 - <<'PY' "$before_company" import json, sys company = json.loads(sys.argv[1]) - group = json.loads(sys.argv[2]) - if len(company) != 1 or company[0].get('name_en') != 'H Music': - raise SystemExit(f"Unexpected company row before patch: {company}") - if len(group) != 1 or group[0].get('name_en') != 'woo!ah!': - raise SystemExit(f"Unexpected group row before patch: {group}") + if len(company) != 1 or company[0].get('name_en') != 'Starship': + raise SystemExit(f"Unexpected Starship row before patch: {company}") + PY + + escaped_logo_url=$(python3 - <<'PY' "${STARSHIP_LOGO_URL}" + import json, sys + print(json.dumps(sys.argv[1])) PY + ) - api PATCH "kcl_companies?id=eq.${COMPANY_ID}" '{"name_ko":"더뮤즈","name_en":"THE MUZE","slug":"the-muze","logo_url":null,"gradient_color":"#A855F7"}' >/tmp/patched_company.json - api PATCH "kcl_groups?id=eq.${GROUP_ID}" '{"name_ko":"리센느","name_en":"RESCENE","slug":"rescene","debut_date":"2024-03-26","member_count":5,"group_type":"girl","is_active":true}' >/tmp/patched_group.json + api PATCH "kcl_companies?slug=eq.${STARSHIP_SLUG}&deleted_at=is.null" "{\"logo_url\":${escaped_logo_url}}" >/tmp/patched_starship.json - after_company=$(api GET "kcl_companies?id=eq.${COMPANY_ID}&select=id,name_ko,name_en,slug,rank,firepower,league_tier,previous_season_rank,deleted_at") - after_group=$(api GET "kcl_groups?id=eq.${GROUP_ID}&select=id,company_id,name_ko,name_en,slug,vote_count,is_active,debut_date,member_count,group_type") - top_list=$(api GET "kcl_companies?select=name_en,name_ko,slug,firepower,league_tier,previous_season_rank,groups:kcl_groups(name_en,name_ko,slug,is_active,debut_date)&deleted_at=is.null&order=firepower.desc,previous_season_rank.asc&limit=12") + after_company=$(api GET "kcl_companies?slug=eq.${STARSHIP_SLUG}&deleted_at=is.null&select=id,name_ko,name_en,slug,logo_url,gradient_color,league_tier,previous_season_rank") + top_list=$(api GET "kcl_companies?select=name_en,name_ko,slug,logo_url,firepower,league_tier,previous_season_rank&deleted_at=is.null&order=firepower.desc,previous_season_rank.asc&limit=8") - echo "After company: ${after_company}" - echo "After group: ${after_group}" - echo "Top list after patch: ${top_list}" + echo "After Starship: ${after_company}" + echo "Top list after Starship logo patch: ${top_list}" - python3 - <<'PY' "$after_company" "$after_group" "$top_list" + python3 - <<'PY' "$after_company" "$top_list" "${STARSHIP_LOGO_URL}" import json, sys company = json.loads(sys.argv[1]) - group = json.loads(sys.argv[2]) - top = json.loads(sys.argv[3]) + top = json.loads(sys.argv[2]) + expected = sys.argv[3] assert len(company) == 1, company c = company[0] - assert c['name_en'] == 'THE MUZE' and c['name_ko'] == '더뮤즈' and c['slug'] == 'the-muze', c - assert c['league_tier'] == 'premier' and c['previous_season_rank'] == 6, c - assert len(group) == 1, group - g = group[0] - assert g['name_en'] == 'RESCENE' and g['name_ko'] == '리센느' and g['slug'] == 'rescene', g - assert g['debut_date'] == '2024-03-26' and g['member_count'] == 5 and g['is_active'] is True, g - names = [item['name_en'] for item in top] - assert 'THE MUZE' in names, names - assert 'H Music' not in names, names - print('VERIFIED: THE MUZE / RESCENE replaced H Music / woo!ah! in live KCL DB') + assert c['name_en'] == 'Starship' and c['slug'] == 'starship-entertainment', c + assert c['logo_url'] == expected, c + starship = [item for item in top if item['slug'] == 'starship-entertainment'] + assert starship and starship[0]['logo_url'] == expected, top + print('VERIFIED: Starship logo_url patched in live KCL DB') PY diff --git a/src/lib/mock-data.ts b/src/lib/mock-data.ts index fb46331..5c49714 100644 --- a/src/lib/mock-data.ts +++ b/src/lib/mock-data.ts @@ -109,6 +109,7 @@ export const MOCK_COMPANIES: CompanyType[] = [ firepower: 76000200, change: 'up', image: 'linear-gradient(135deg, #9C27B0 0%, #673AB7 100%)', + logoUrl: 'https://upload.wikimedia.org/wikipedia/commons/e/e7/Starship_Entertainment_New_Logo.png', stockHistory: generateHistory(72000000), }, { From 8db3b5b0a7a1dd44bf0d26e031ed952ce274a46a Mon Sep 17 00:00:00 2001 From: moony01 Date: Wed, 3 Jun 2026 17:07:23 +0900 Subject: [PATCH 4/8] chore(kcl): remove one-time data patch workflow --- .github/workflows/kcl-data-patch-the-muze.yml | 89 ------------------- 1 file changed, 89 deletions(-) delete mode 100644 .github/workflows/kcl-data-patch-the-muze.yml diff --git a/.github/workflows/kcl-data-patch-the-muze.yml b/.github/workflows/kcl-data-patch-the-muze.yml deleted file mode 100644 index 923a40b..0000000 --- a/.github/workflows/kcl-data-patch-the-muze.yml +++ /dev/null @@ -1,89 +0,0 @@ -name: KCL Data Patch - Add Starship Logo - -on: - push: - branches: - - ops/replace-hmusic-the-muze-20260603 - workflow_dispatch: - -jobs: - add-starship-logo: - runs-on: ubuntu-latest - timeout-minutes: 5 - env: - SUPABASE_URL: ${{ secrets.SUPABASE_URL }} - SUPABASE_SERVICE_ROLE_KEY: ${{ secrets.SUPABASE_SERVICE_ROLE_KEY }} - STARSHIP_SLUG: starship-entertainment - STARSHIP_LOGO_URL: https://upload.wikimedia.org/wikipedia/commons/e/e7/Starship_Entertainment_New_Logo.png - steps: - - name: Patch Starship logo URL - shell: bash - run: | - set -euo pipefail - - if [ -z "${SUPABASE_URL:-}" ] || [ -z "${SUPABASE_SERVICE_ROLE_KEY:-}" ]; then - echo "Missing Supabase secrets" >&2 - exit 1 - fi - - curl -fsSI "${STARSHIP_LOGO_URL}" | grep -qi 'content-type: image/png' - - api() { - local method="$1" - local path="$2" - local body="${3:-}" - if [ -n "$body" ]; then - curl -fsS -X "$method" \ - "${SUPABASE_URL}/rest/v1/${path}" \ - -H "apikey: ${SUPABASE_SERVICE_ROLE_KEY}" \ - -H "Authorization: Bearer ${SUPABASE_SERVICE_ROLE_KEY}" \ - -H "Content-Type: application/json" \ - -H "Accept: application/json" \ - -H "Prefer: return=representation" \ - --data "$body" - else - curl -fsS -X "$method" \ - "${SUPABASE_URL}/rest/v1/${path}" \ - -H "apikey: ${SUPABASE_SERVICE_ROLE_KEY}" \ - -H "Authorization: Bearer ${SUPABASE_SERVICE_ROLE_KEY}" \ - -H "Accept: application/json" - fi - } - - before_company=$(api GET "kcl_companies?slug=eq.${STARSHIP_SLUG}&deleted_at=is.null&select=id,name_ko,name_en,slug,logo_url,gradient_color,league_tier,previous_season_rank") - echo "Before Starship: ${before_company}" - - python3 - <<'PY' "$before_company" - import json, sys - company = json.loads(sys.argv[1]) - if len(company) != 1 or company[0].get('name_en') != 'Starship': - raise SystemExit(f"Unexpected Starship row before patch: {company}") - PY - - escaped_logo_url=$(python3 - <<'PY' "${STARSHIP_LOGO_URL}" - import json, sys - print(json.dumps(sys.argv[1])) - PY - ) - - api PATCH "kcl_companies?slug=eq.${STARSHIP_SLUG}&deleted_at=is.null" "{\"logo_url\":${escaped_logo_url}}" >/tmp/patched_starship.json - - after_company=$(api GET "kcl_companies?slug=eq.${STARSHIP_SLUG}&deleted_at=is.null&select=id,name_ko,name_en,slug,logo_url,gradient_color,league_tier,previous_season_rank") - top_list=$(api GET "kcl_companies?select=name_en,name_ko,slug,logo_url,firepower,league_tier,previous_season_rank&deleted_at=is.null&order=firepower.desc,previous_season_rank.asc&limit=8") - - echo "After Starship: ${after_company}" - echo "Top list after Starship logo patch: ${top_list}" - - python3 - <<'PY' "$after_company" "$top_list" "${STARSHIP_LOGO_URL}" - import json, sys - company = json.loads(sys.argv[1]) - top = json.loads(sys.argv[2]) - expected = sys.argv[3] - assert len(company) == 1, company - c = company[0] - assert c['name_en'] == 'Starship' and c['slug'] == 'starship-entertainment', c - assert c['logo_url'] == expected, c - starship = [item for item in top if item['slug'] == 'starship-entertainment'] - assert starship and starship[0]['logo_url'] == expected, top - print('VERIFIED: Starship logo_url patched in live KCL DB') - PY From e17d390d64494ded33ed816836cf2a9aa6eaf916 Mon Sep 17 00:00:00 2001 From: moony01 Date: Wed, 3 Jun 2026 17:16:32 +0900 Subject: [PATCH 5/8] chore(kcl): patch official Starship logo URL --- .../kcl-data-patch-starship-logo.yml | 83 +++++++++++++++++++ src/lib/mock-data.ts | 2 +- 2 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/kcl-data-patch-starship-logo.yml diff --git a/.github/workflows/kcl-data-patch-starship-logo.yml b/.github/workflows/kcl-data-patch-starship-logo.yml new file mode 100644 index 0000000..024a56a --- /dev/null +++ b/.github/workflows/kcl-data-patch-starship-logo.yml @@ -0,0 +1,83 @@ +name: KCL Data Patch - Add Official Starship Logo + +on: + push: + branches: + - ops/replace-hmusic-the-muze-20260603 + workflow_dispatch: + +jobs: + add-official-starship-logo: + runs-on: ubuntu-latest + timeout-minutes: 5 + env: + SUPABASE_URL: ${{ secrets.SUPABASE_URL }} + SUPABASE_SERVICE_ROLE_KEY: ${{ secrets.SUPABASE_SERVICE_ROLE_KEY }} + STARSHIP_SLUG: starship-entertainment + STARSHIP_LOGO_URL: https://www.starship-ent.com/logo192.png + steps: + - name: Patch Starship official logo URL + shell: bash + run: | + set -euo pipefail + + if [ -z "${SUPABASE_URL:-}" ] || [ -z "${SUPABASE_SERVICE_ROLE_KEY:-}" ]; then + echo "Missing Supabase secrets" >&2 + exit 1 + fi + + curl -fsSI "${STARSHIP_LOGO_URL}" | grep -qi 'content-type: image/png' + + api() { + local method="$1" + local path="$2" + local body="${3:-}" + if [ -n "$body" ]; then + curl -fsS -X "$method" \ + "${SUPABASE_URL}/rest/v1/${path}" \ + -H "apikey: ${SUPABASE_SERVICE_ROLE_KEY}" \ + -H "Authorization: Bearer ${SUPABASE_SERVICE_ROLE_KEY}" \ + -H "Content-Type: application/json" \ + -H "Accept: application/json" \ + -H "Prefer: return=representation" \ + --data "$body" + else + curl -fsS -X "$method" \ + "${SUPABASE_URL}/rest/v1/${path}" \ + -H "apikey: ${SUPABASE_SERVICE_ROLE_KEY}" \ + -H "Authorization: Bearer ${SUPABASE_SERVICE_ROLE_KEY}" \ + -H "Accept: application/json" + fi + } + + before_company=$(api GET "kcl_companies?slug=eq.${STARSHIP_SLUG}&deleted_at=is.null&select=id,name_ko,name_en,slug,logo_url,gradient_color,league_tier,previous_season_rank") + echo "Before Starship: ${before_company}" + + python3 - <<'PY' "$before_company" + import json, sys + company = json.loads(sys.argv[1]) + if len(company) != 1 or company[0].get('name_en') != 'Starship': + raise SystemExit(f"Unexpected Starship row before patch: {company}") + PY + + escaped_logo_url=$(python3 - <<'PY' "${STARSHIP_LOGO_URL}" + import json, sys + print(json.dumps(sys.argv[1])) + PY + ) + + api PATCH "kcl_companies?slug=eq.${STARSHIP_SLUG}&deleted_at=is.null" "{\"logo_url\":${escaped_logo_url}}" >/tmp/patched_starship.json + + after_company=$(api GET "kcl_companies?slug=eq.${STARSHIP_SLUG}&deleted_at=is.null&select=id,name_ko,name_en,slug,logo_url,gradient_color,league_tier,previous_season_rank") + echo "After Starship: ${after_company}" + + python3 - <<'PY' "$after_company" "${STARSHIP_LOGO_URL}" + import json, sys + company = json.loads(sys.argv[1]) + expected = sys.argv[2] + assert len(company) == 1, company + c = company[0] + assert c['name_en'] == 'Starship' and c['slug'] == 'starship-entertainment', c + assert c['logo_url'] == expected, c + print('VERIFIED: Official Starship logo_url patched in live KCL DB') + PY diff --git a/src/lib/mock-data.ts b/src/lib/mock-data.ts index 5c49714..7a9c0de 100644 --- a/src/lib/mock-data.ts +++ b/src/lib/mock-data.ts @@ -109,7 +109,7 @@ export const MOCK_COMPANIES: CompanyType[] = [ firepower: 76000200, change: 'up', image: 'linear-gradient(135deg, #9C27B0 0%, #673AB7 100%)', - logoUrl: 'https://upload.wikimedia.org/wikipedia/commons/e/e7/Starship_Entertainment_New_Logo.png', + logoUrl: 'https://www.starship-ent.com/logo192.png', stockHistory: generateHistory(72000000), }, { From 250020a0ef1198d2c2b69ebc0cfe3e7cede9a0f5 Mon Sep 17 00:00:00 2001 From: moony01 Date: Wed, 3 Jun 2026 17:17:25 +0900 Subject: [PATCH 6/8] chore(kcl): remove Starship logo patch workflow --- .../kcl-data-patch-starship-logo.yml | 83 ------------------- 1 file changed, 83 deletions(-) delete mode 100644 .github/workflows/kcl-data-patch-starship-logo.yml diff --git a/.github/workflows/kcl-data-patch-starship-logo.yml b/.github/workflows/kcl-data-patch-starship-logo.yml deleted file mode 100644 index 024a56a..0000000 --- a/.github/workflows/kcl-data-patch-starship-logo.yml +++ /dev/null @@ -1,83 +0,0 @@ -name: KCL Data Patch - Add Official Starship Logo - -on: - push: - branches: - - ops/replace-hmusic-the-muze-20260603 - workflow_dispatch: - -jobs: - add-official-starship-logo: - runs-on: ubuntu-latest - timeout-minutes: 5 - env: - SUPABASE_URL: ${{ secrets.SUPABASE_URL }} - SUPABASE_SERVICE_ROLE_KEY: ${{ secrets.SUPABASE_SERVICE_ROLE_KEY }} - STARSHIP_SLUG: starship-entertainment - STARSHIP_LOGO_URL: https://www.starship-ent.com/logo192.png - steps: - - name: Patch Starship official logo URL - shell: bash - run: | - set -euo pipefail - - if [ -z "${SUPABASE_URL:-}" ] || [ -z "${SUPABASE_SERVICE_ROLE_KEY:-}" ]; then - echo "Missing Supabase secrets" >&2 - exit 1 - fi - - curl -fsSI "${STARSHIP_LOGO_URL}" | grep -qi 'content-type: image/png' - - api() { - local method="$1" - local path="$2" - local body="${3:-}" - if [ -n "$body" ]; then - curl -fsS -X "$method" \ - "${SUPABASE_URL}/rest/v1/${path}" \ - -H "apikey: ${SUPABASE_SERVICE_ROLE_KEY}" \ - -H "Authorization: Bearer ${SUPABASE_SERVICE_ROLE_KEY}" \ - -H "Content-Type: application/json" \ - -H "Accept: application/json" \ - -H "Prefer: return=representation" \ - --data "$body" - else - curl -fsS -X "$method" \ - "${SUPABASE_URL}/rest/v1/${path}" \ - -H "apikey: ${SUPABASE_SERVICE_ROLE_KEY}" \ - -H "Authorization: Bearer ${SUPABASE_SERVICE_ROLE_KEY}" \ - -H "Accept: application/json" - fi - } - - before_company=$(api GET "kcl_companies?slug=eq.${STARSHIP_SLUG}&deleted_at=is.null&select=id,name_ko,name_en,slug,logo_url,gradient_color,league_tier,previous_season_rank") - echo "Before Starship: ${before_company}" - - python3 - <<'PY' "$before_company" - import json, sys - company = json.loads(sys.argv[1]) - if len(company) != 1 or company[0].get('name_en') != 'Starship': - raise SystemExit(f"Unexpected Starship row before patch: {company}") - PY - - escaped_logo_url=$(python3 - <<'PY' "${STARSHIP_LOGO_URL}" - import json, sys - print(json.dumps(sys.argv[1])) - PY - ) - - api PATCH "kcl_companies?slug=eq.${STARSHIP_SLUG}&deleted_at=is.null" "{\"logo_url\":${escaped_logo_url}}" >/tmp/patched_starship.json - - after_company=$(api GET "kcl_companies?slug=eq.${STARSHIP_SLUG}&deleted_at=is.null&select=id,name_ko,name_en,slug,logo_url,gradient_color,league_tier,previous_season_rank") - echo "After Starship: ${after_company}" - - python3 - <<'PY' "$after_company" "${STARSHIP_LOGO_URL}" - import json, sys - company = json.loads(sys.argv[1]) - expected = sys.argv[2] - assert len(company) == 1, company - c = company[0] - assert c['name_en'] == 'Starship' and c['slug'] == 'starship-entertainment', c - assert c['logo_url'] == expected, c - print('VERIFIED: Official Starship logo_url patched in live KCL DB') - PY From 10652359d6e0edfbda5bd723f730249e7213ba01 Mon Sep 17 00:00:00 2001 From: moony01 Date: Wed, 3 Jun 2026 17:30:55 +0900 Subject: [PATCH 7/8] chore(kcl): use official Starship company CI logo --- .../kcl-data-patch-starship-company-logo.yml | 94 +++++++++++++++++++ .../VoteController/VoteController.module.scss | 5 +- .../DashboardRankingItem.module.scss | 5 +- .../CompanySelector.module.scss | 5 +- .../home/VoteButton/VoteButton.module.scss | 5 +- .../LeagueRankingItem.module.scss | 5 +- .../PromotionBattle.module.scss | 5 +- .../TopThreeCard/TopThreeCard.module.scss | 5 +- .../SupportModal/SupportModal.module.scss | 5 +- .../ui/SearchBar/SearchBar.module.scss | 5 +- src/lib/mock-data.ts | 2 +- 11 files changed, 131 insertions(+), 10 deletions(-) create mode 100644 .github/workflows/kcl-data-patch-starship-company-logo.yml diff --git a/.github/workflows/kcl-data-patch-starship-company-logo.yml b/.github/workflows/kcl-data-patch-starship-company-logo.yml new file mode 100644 index 0000000..7f78403 --- /dev/null +++ b/.github/workflows/kcl-data-patch-starship-company-logo.yml @@ -0,0 +1,94 @@ +name: KCL Data Patch - Starship Company Logo + +on: + push: + branches: + - ops/replace-hmusic-the-muze-20260603 + paths: + - '.github/workflows/kcl-data-patch-starship-company-logo.yml' + workflow_dispatch: + +env: + SUPABASE_URL: ${{ secrets.SUPABASE_URL }} + STARSHIP_LOGO_URL: https://www.starship-ent.com/images/assets/starship_ci.jpg + +jobs: + patch-starship-company-logo: + name: Patch Starship company CI logo URL + runs-on: ubuntu-latest + steps: + - name: Verify official logo asset + run: | + set -euo pipefail + echo "Checking official Starship CI asset..." + curl -fsSL --max-time 20 "$STARSHIP_LOGO_URL" -o /tmp/starship_ci.jpg + python3 - <<'PY' + from pathlib import Path + import imghdr + p = Path('/tmp/starship_ci.jpg') + data = p.read_bytes() + kind = imghdr.what(p) + print(f'asset_kind={kind} bytes={len(data)}') + if kind not in {'jpeg', 'png'}: + raise SystemExit('unexpected image type') + if len(data) < 1000: + raise SystemExit('asset too small') + PY + + - name: Patch live Starship row + run: | + set -euo pipefail + if [ -z "${SUPABASE_URL:-}" ]; then + echo "SUPABASE_URL secret is missing" + exit 1 + fi + if [ -z "${{ secrets.SUPABASE_SERVICE_ROLE_KEY }}" ]; then + echo "SUPABASE_SERVICE_ROLE_KEY secret is missing" + exit 1 + fi + + API="$SUPABASE_URL/rest/v1/kcl_companies?slug=eq.starship-entertainment&deleted_at=is.null" + HEADERS=( + -H "apikey: ${{ secrets.SUPABASE_SERVICE_ROLE_KEY }}" + -H "Authorization: Bearer ${{ secrets.SUPABASE_SERVICE_ROLE_KEY }}" + -H "Content-Type: application/json" + ) + + before=$(curl -fsSL "$API&select=id,name_en,slug,logo_url" "${HEADERS[@]}") + echo "Before: $before" + python3 - <<'PY' "$before" + import json, sys + rows = json.loads(sys.argv[1]) + if len(rows) != 1: + raise SystemExit(f'expected exactly one Starship row, got {len(rows)}') + print('preflight_ok') + PY + + body=$(python3 - <<'PY' + import json, os + print(json.dumps({'logo_url': os.environ['STARSHIP_LOGO_URL']})) + PY + ) + + status=$(curl -sS -o /tmp/patch-response.txt -w '%{http_code}' -X PATCH "$API" \ + "${HEADERS[@]}" \ + -d "$body") + if [ "$status" != "204" ] && [ "$status" != "200" ]; then + echo "PATCH failed status=$status" + cat /tmp/patch-response.txt + exit 1 + fi + + after=$(curl -fsSL "$API&select=name_en,slug,logo_url" "${HEADERS[@]}") + echo "After: $after" + python3 - <<'PY' "$after" + import json, os, sys + rows = json.loads(sys.argv[1]) + expected = os.environ['STARSHIP_LOGO_URL'] + if len(rows) != 1: + raise SystemExit(f'expected exactly one Starship row after patch, got {len(rows)}') + got = rows[0].get('logo_url') + if got != expected: + raise SystemExit(f'logo_url mismatch: {got!r} != {expected!r}') + print('READBACK_OK') + PY diff --git a/src/components/features/VoteController/VoteController.module.scss b/src/components/features/VoteController/VoteController.module.scss index 48254f0..d3aae42 100644 --- a/src/components/features/VoteController/VoteController.module.scss +++ b/src/components/features/VoteController/VoteController.module.scss @@ -59,7 +59,10 @@ .logoImage { width: 100%; height: 100%; - object-fit: cover; + object-fit: contain; + background: rgba(255, 255, 255, 0.96); + padding: 6px; + box-sizing: border-box; border-radius: inherit; } diff --git a/src/components/features/dashboard/DashboardRankingItem/DashboardRankingItem.module.scss b/src/components/features/dashboard/DashboardRankingItem/DashboardRankingItem.module.scss index 6305fd1..654c738 100644 --- a/src/components/features/dashboard/DashboardRankingItem/DashboardRankingItem.module.scss +++ b/src/components/features/dashboard/DashboardRankingItem/DashboardRankingItem.module.scss @@ -148,7 +148,10 @@ .logoImage { width: 100%; height: 100%; - object-fit: cover; + object-fit: contain; + background: rgba(255, 255, 255, 0.96); + padding: 4px; + box-sizing: border-box; border-radius: inherit; } diff --git a/src/components/features/home/CompanySelector/CompanySelector.module.scss b/src/components/features/home/CompanySelector/CompanySelector.module.scss index bc819a0..a5afab1 100644 --- a/src/components/features/home/CompanySelector/CompanySelector.module.scss +++ b/src/components/features/home/CompanySelector/CompanySelector.module.scss @@ -104,7 +104,10 @@ .logoImage { width: 100%; height: 100%; - object-fit: cover; + object-fit: contain; + background: rgba(255, 255, 255, 0.96); + padding: 10px; + box-sizing: border-box; border-radius: inherit; } diff --git a/src/components/features/home/VoteButton/VoteButton.module.scss b/src/components/features/home/VoteButton/VoteButton.module.scss index 26e4323..fd3ef9d 100644 --- a/src/components/features/home/VoteButton/VoteButton.module.scss +++ b/src/components/features/home/VoteButton/VoteButton.module.scss @@ -46,7 +46,10 @@ .logoImage { width: 100%; height: 100%; - object-fit: cover; + object-fit: contain; + background: rgba(255, 255, 255, 0.96); + padding: 6px; + box-sizing: border-box; border-radius: inherit; } diff --git a/src/components/features/league/LeagueRankingItem/LeagueRankingItem.module.scss b/src/components/features/league/LeagueRankingItem/LeagueRankingItem.module.scss index f131f3c..0d70106 100644 --- a/src/components/features/league/LeagueRankingItem/LeagueRankingItem.module.scss +++ b/src/components/features/league/LeagueRankingItem/LeagueRankingItem.module.scss @@ -295,7 +295,10 @@ $color-promotion-chance: #eab308; // 승격 기회 (2부 2위) - 골드색 .logoImage { width: 100%; height: 100%; - object-fit: cover; + object-fit: contain; + background: rgba(255, 255, 255, 0.96); + padding: 3px; + box-sizing: border-box; border-radius: inherit; } diff --git a/src/components/features/league/PromotionBattle/PromotionBattle.module.scss b/src/components/features/league/PromotionBattle/PromotionBattle.module.scss index 6d964f1..8d2a2df 100644 --- a/src/components/features/league/PromotionBattle/PromotionBattle.module.scss +++ b/src/components/features/league/PromotionBattle/PromotionBattle.module.scss @@ -173,7 +173,10 @@ $color-gold: #d4af37; .logoImage { width: 100%; height: 100%; - object-fit: cover; + object-fit: contain; + background: rgba(255, 255, 255, 0.96); + padding: 6px; + box-sizing: border-box; border-radius: inherit; } diff --git a/src/components/features/league/TopThreeCard/TopThreeCard.module.scss b/src/components/features/league/TopThreeCard/TopThreeCard.module.scss index 5112264..8e97c88 100644 --- a/src/components/features/league/TopThreeCard/TopThreeCard.module.scss +++ b/src/components/features/league/TopThreeCard/TopThreeCard.module.scss @@ -188,7 +188,10 @@ $bronze: #cd7f32; .logoImage { width: 100%; height: 100%; - object-fit: cover; + object-fit: contain; + background: rgba(255, 255, 255, 0.96); + padding: 8px; + box-sizing: border-box; border-radius: inherit; } diff --git a/src/components/features/vote/SupportModal/SupportModal.module.scss b/src/components/features/vote/SupportModal/SupportModal.module.scss index 631f3f1..933e8eb 100644 --- a/src/components/features/vote/SupportModal/SupportModal.module.scss +++ b/src/components/features/vote/SupportModal/SupportModal.module.scss @@ -35,7 +35,10 @@ .logoImage { width: 100%; height: 100%; - object-fit: cover; + object-fit: contain; + background: rgba(255, 255, 255, 0.96); + padding: 6px; + box-sizing: border-box; border-radius: inherit; } diff --git a/src/components/ui/SearchBar/SearchBar.module.scss b/src/components/ui/SearchBar/SearchBar.module.scss index e7394f9..709144b 100644 --- a/src/components/ui/SearchBar/SearchBar.module.scss +++ b/src/components/ui/SearchBar/SearchBar.module.scss @@ -321,7 +321,10 @@ .avatarImage { width: 100%; height: 100%; - object-fit: cover; + object-fit: contain; + background: rgba(255, 255, 255, 0.96); + padding: 3px; + box-sizing: border-box; border-radius: inherit; } diff --git a/src/lib/mock-data.ts b/src/lib/mock-data.ts index 7a9c0de..b68b70f 100644 --- a/src/lib/mock-data.ts +++ b/src/lib/mock-data.ts @@ -109,7 +109,7 @@ export const MOCK_COMPANIES: CompanyType[] = [ firepower: 76000200, change: 'up', image: 'linear-gradient(135deg, #9C27B0 0%, #673AB7 100%)', - logoUrl: 'https://www.starship-ent.com/logo192.png', + logoUrl: 'https://www.starship-ent.com/images/assets/starship_ci.jpg', stockHistory: generateHistory(72000000), }, { From cc696208db77cca231907ba4ec6470bb5a22299f Mon Sep 17 00:00:00 2001 From: moony01 Date: Wed, 3 Jun 2026 17:32:08 +0900 Subject: [PATCH 8/8] chore(kcl): remove Starship company logo patch workflow --- .../kcl-data-patch-starship-company-logo.yml | 94 ------------------- 1 file changed, 94 deletions(-) delete mode 100644 .github/workflows/kcl-data-patch-starship-company-logo.yml diff --git a/.github/workflows/kcl-data-patch-starship-company-logo.yml b/.github/workflows/kcl-data-patch-starship-company-logo.yml deleted file mode 100644 index 7f78403..0000000 --- a/.github/workflows/kcl-data-patch-starship-company-logo.yml +++ /dev/null @@ -1,94 +0,0 @@ -name: KCL Data Patch - Starship Company Logo - -on: - push: - branches: - - ops/replace-hmusic-the-muze-20260603 - paths: - - '.github/workflows/kcl-data-patch-starship-company-logo.yml' - workflow_dispatch: - -env: - SUPABASE_URL: ${{ secrets.SUPABASE_URL }} - STARSHIP_LOGO_URL: https://www.starship-ent.com/images/assets/starship_ci.jpg - -jobs: - patch-starship-company-logo: - name: Patch Starship company CI logo URL - runs-on: ubuntu-latest - steps: - - name: Verify official logo asset - run: | - set -euo pipefail - echo "Checking official Starship CI asset..." - curl -fsSL --max-time 20 "$STARSHIP_LOGO_URL" -o /tmp/starship_ci.jpg - python3 - <<'PY' - from pathlib import Path - import imghdr - p = Path('/tmp/starship_ci.jpg') - data = p.read_bytes() - kind = imghdr.what(p) - print(f'asset_kind={kind} bytes={len(data)}') - if kind not in {'jpeg', 'png'}: - raise SystemExit('unexpected image type') - if len(data) < 1000: - raise SystemExit('asset too small') - PY - - - name: Patch live Starship row - run: | - set -euo pipefail - if [ -z "${SUPABASE_URL:-}" ]; then - echo "SUPABASE_URL secret is missing" - exit 1 - fi - if [ -z "${{ secrets.SUPABASE_SERVICE_ROLE_KEY }}" ]; then - echo "SUPABASE_SERVICE_ROLE_KEY secret is missing" - exit 1 - fi - - API="$SUPABASE_URL/rest/v1/kcl_companies?slug=eq.starship-entertainment&deleted_at=is.null" - HEADERS=( - -H "apikey: ${{ secrets.SUPABASE_SERVICE_ROLE_KEY }}" - -H "Authorization: Bearer ${{ secrets.SUPABASE_SERVICE_ROLE_KEY }}" - -H "Content-Type: application/json" - ) - - before=$(curl -fsSL "$API&select=id,name_en,slug,logo_url" "${HEADERS[@]}") - echo "Before: $before" - python3 - <<'PY' "$before" - import json, sys - rows = json.loads(sys.argv[1]) - if len(rows) != 1: - raise SystemExit(f'expected exactly one Starship row, got {len(rows)}') - print('preflight_ok') - PY - - body=$(python3 - <<'PY' - import json, os - print(json.dumps({'logo_url': os.environ['STARSHIP_LOGO_URL']})) - PY - ) - - status=$(curl -sS -o /tmp/patch-response.txt -w '%{http_code}' -X PATCH "$API" \ - "${HEADERS[@]}" \ - -d "$body") - if [ "$status" != "204" ] && [ "$status" != "200" ]; then - echo "PATCH failed status=$status" - cat /tmp/patch-response.txt - exit 1 - fi - - after=$(curl -fsSL "$API&select=name_en,slug,logo_url" "${HEADERS[@]}") - echo "After: $after" - python3 - <<'PY' "$after" - import json, os, sys - rows = json.loads(sys.argv[1]) - expected = os.environ['STARSHIP_LOGO_URL'] - if len(rows) != 1: - raise SystemExit(f'expected exactly one Starship row after patch, got {len(rows)}') - got = rows[0].get('logo_url') - if got != expected: - raise SystemExit(f'logo_url mismatch: {got!r} != {expected!r}') - print('READBACK_OK') - PY