Skip to content

πŸ› οΈ API-Football 동기화 μž₯μ•  λŒ€μ‘ 및 μƒνƒœ ν‘œμ‹œ κ°œμ„  - #28

Merged
son0307 merged 1 commit into
mainfrom
codex/api-football-sync-resilience
Jul 10, 2026
Merged

πŸ› οΈ API-Football 동기화 μž₯μ•  λŒ€μ‘ 및 μƒνƒœ ν‘œμ‹œ κ°œμ„ #28
son0307 merged 1 commit into
mainfrom
codex/api-football-sync-resilience

Conversation

@son0307

@son0307 son0307 commented Jul 10, 2026

Copy link
Copy Markdown
Owner

λ³€κ²½ λ‚΄μš©

동기화 μƒνƒœ 좔적 ν™•μž₯

  • api_football_sync_status에 λ‹€μŒ 정보λ₯Ό μ €μž₯ν•˜λ„λ‘ ν™•μž₯
    • λ§ˆμ§€λ§‰ μ‹œλ„ μ‹œκ°
    • λ§ˆμ§€λ§‰ 성곡 μ‹œκ°
    • λ§ˆμ§€λ§‰ μ‹€νŒ¨ μ‹œκ°
    • 연속 μ‹€νŒ¨ 횟수
    • λ§ˆμ§€λ§‰ 였λ₯˜ λ©”μ‹œμ§€
    • 동기화 μƒνƒœ
  • 동기화 μƒνƒœλ₯Ό 정상, μ§€μ—°, μ‹€νŒ¨, μž¬μ‹œλ„ λŒ€κΈ° 쀑, 기둝 μ—†μŒμœΌλ‘œ ꡬ뢄
  • Teams, Standings, Fixtures, Fixture Details, Players, Injuries λ™κΈ°ν™”μ˜ μ‹œλ„ 및 성곡 기둝 연동
  • μ‹€νŒ¨ μž¬μ‹œλ„ μŠ€μΌ€μ€„λŸ¬ μƒνƒœλ₯Ό 동기화 μƒνƒœμ— 반영
  • κ΄€λ¦¬μž Manual Sync νŒ¨λ„μ—μ„œ μž‘μ—…λ³„ μ„±κ³΅Β·μ‹œλ„Β·μ‹€νŒ¨ μ‹œκ°κ³Ό 였λ₯˜ 원인 ν‘œμ‹œ

μ‚¬μš©μž ν™”λ©΄ 데이터 κΈ°μ€€ μ‹œκ° ν‘œμ‹œ

  • μˆœμœ„ 및 κ²½κΈ° 화면에 졜근 μ—…λ°μ΄νŠΈ μ‹œκ°„ ν‘œμ‹œ
  • λ§ˆμ§€λ§‰ 성곡 μ‹œκ°μ΄ 24μ‹œκ°„ 이상 μ§€λ‚œ 경우 μ§€μ—° μƒνƒœλ‘œ 처리
  • κ΄€λ¦¬μž μˆ˜λ™ 갱신은 κΈ°μ‘΄ /api/v1/admin/sync/** 흐름을 μž¬μ‚¬μš©
  • κ΄€λ¦¬μž κΆŒν•œ 검증, 감사 둜그, ν”„λ‘ νŠΈΒ·λ°±μ—”λ“œ μΏ¨λ‹€μš΄ 적용

API-Football 전체 μž₯μ•  λŒ€μ‘

  • λͺ¨λ“  API-Football μš”μ²­μ— κ³΅ν†΅μœΌλ‘œ μ μš©λ˜λŠ” μ „μ—­ μ„œν‚· 브레이컀 μΆ”κ°€
  • 연속 μ‹€νŒ¨ μž„κ³„μΉ˜ 도달 μ‹œ 일정 μ‹œκ°„ μ™ΈλΆ€ API 호좜 차단
  • 정상 응닡 μˆ˜μ‹  μ‹œ μ‹€νŒ¨ μƒνƒœμ™€ 차단 μƒνƒœ μ΄ˆκΈ°ν™”
  • κΈ°μ‘΄ μ§€μˆ˜ λ°±μ˜€ν”„ μž¬μ‹œλ„μ™€ μŠ€μΌ€μ€„λŸ¬ μž¬μ‹œλ„ 둜직 μœ μ§€
  • 전체 API μž₯μ•  μƒνƒœλ₯Ό κ΄€λ¦¬μž ν™”λ©΄μ—μ„œ 확인 κ°€λŠ₯ν•˜λ„λ‘ ν‘œμ‹œ

κ΄€λ¦¬μž 감사 둜그 κ°œμ„ 

  • Recent Admin Logs에 μš”μ²­ 식별 νŒŒλΌλ―Έν„° ν‘œμ‹œ
  • leagueId, season, teamId, playerId, fixtureId, eventSequence 등을 μ•ˆμ „ν•˜κ²Œ λ…ΈμΆœ
  • μˆ˜μ • μ „ν›„ κ°’μ΄λ‚˜ μ™ΈλΆ€ API 였λ₯˜ λ³Έλ¬Έ μ „μ²΄λŠ” 계속 μˆ¨κΉ€

검증

  • ν”„λ‘ νŠΈμ—”λ“œ TypeScript 및 Vite λΉŒλ“œ 톡과
  • AdminService κ΄€λ ¨ ν…ŒμŠ€νŠΈ 톡과
  • κ΄€λ¦¬μž μˆ˜λ™ 동기화 USER κΆŒν•œ 403 ν…ŒμŠ€νŠΈ 톡과
  • λͺ¨λ°”일 μˆœμœ„Β·κ²½κΈ° ν™”λ©΄μ—μ„œ μ—…λ°μ΄νŠΈ μ‹œκ°κ³Ό λ ˆμ΄μ•„μ›ƒ 확인

@github-actions

Copy link
Copy Markdown

Codex PR Review

PR μš”μ•½

μš”μ•½

API-Football λ™κΈ°ν™”μ˜ μ‹€νŒ¨Β·μ§€μ—° μƒνƒœλ₯Ό 더 μ„Έλ°€ν•˜κ²Œ μΆ”μ ν•˜κ³ , κ΄€λ¦¬μžμ™€ μ‚¬μš©μž ν™”λ©΄μ—μ„œ μ΅œμ‹  데이터 μ‹œμ κ³Ό μž₯μ•  μƒνƒœλ₯Ό 더 잘 보이도둝 κ°œμ„ ν–ˆμŠ΅λ‹ˆλ‹€. λ˜ν•œ μ „μ—­ μ„œν‚· λΈŒλ ˆμ΄μ»€μ™€ 곡용 μˆ˜λ™ 동기화 μ—”λ“œν¬μΈνŠΈλ₯Ό μΆ”κ°€ν•΄ μž₯μ•  μ‹œ λŒ€μ‘μ„±κ³Ό μž¬μ‹œλ„ 흐름을 κ°•ν™”ν–ˆμŠ΅λ‹ˆλ‹€.

μ£Όμš” 변경사항

  • 동기화 μƒνƒœμ— λ§ˆμ§€λ§‰ μ‹œλ„/성곡/μ‹€νŒ¨ μ‹œκ°, 연속 μ‹€νŒ¨ 횟수, 였λ₯˜ λ©”μ‹œμ§€, μƒνƒœκ°’μ„ μ €μž₯ν•˜λ„λ‘ ν™•μž₯
  • κ΄€λ¦¬μž νŽ˜μ΄μ§€μ—μ„œ 동기화 μž‘μ—…λ³„ μƒνƒœ λ°°μ§€, 성곡/μ‹œλ„/μ‹€νŒ¨ μ‹œκ°, μ‹€νŒ¨ μ‚¬μœ λ₯Ό ν‘œμ‹œν•˜λ„λ‘ κ°œμ„ 
  • μˆœμœ„/κ²½κΈ° 화면에 졜근 μ—…λ°μ΄νŠΈ μ‹œκ°κ³Ό 데이터 신선도 ν‘œμ‹œλ₯Ό μΆ”κ°€ν•˜κ³ , μ§€μ—° μ‹œ μˆ˜λ™ κ°±μ‹  λ²„νŠΌ 제곡
  • API-Football μš”μ²­ μ „μ—­ μ„œν‚· 브레이컀λ₯Ό μΆ”κ°€ν•΄ 연속 μ‹€νŒ¨ μ‹œ μ™ΈλΆ€ API ν˜ΈμΆœμ„ μΌμ‹œ 차단
  • Teams, Standings, Fixtures, Players, Injuries, Fixture Details 동기화 μ‹œλ„/성곡/μ‹€νŒ¨ 기둝을 연동
  • μˆ˜λ™ λ™κΈ°ν™”μš© /api/v1/sync/** POST μ—”λ“œν¬μΈνŠΈλ₯Ό μΆ”κ°€ν•˜κ³  인증 및 μΏ¨λ‹€μš΄μ„ 적용
  • κ΄€λ¦¬μž 감사 λ‘œκ·Έμ— leagueId, season, teamId, playerId, fixtureId λ“± μš”μ²­ μ‹λ³„μžλ§Œ μ•ˆμ „ν•˜κ²Œ λ…ΈμΆœν•˜λ„λ‘ κ°œμ„ 
  • μƒνƒœ ν‘œμ‹œμš© UI μŠ€νƒ€μΌκ³Ό κ΄€λ ¨ νƒ€μž…/APIλ₯Ό 정리

영ν–₯ λ²”μœ„

  • 라이브 κ²½κΈ°/μˆœμœ„ ν™”λ©΄μ˜ 데이터 신선도 ν‘œμ‹œ
  • Fixture / Standings 곡개 μˆ˜λ™ 동기화
  • κ΄€λ¦¬μž 동기화 νŒ¨λ„ 및 감사 둜그
  • API-Football 동기화 μƒνƒœ 관리
  • 인증/κΆŒν•œ μ„€μ •
  • μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μ„€μ • 및 CI/λΉŒλ“œ κ΄€λ ¨ μ½”λ“œ

검증

  • ν”„λ‘ νŠΈμ—”λ“œ TypeScript 및 Vite λΉŒλ“œ 톡과
  • AdminService κ΄€λ ¨ ν…ŒμŠ€νŠΈ 톡과
  • κ΄€λ¦¬μž μˆ˜λ™ 동기화 USER κΆŒν•œ 403 ν…ŒμŠ€νŠΈ 톡과

μ‹œλ‹ˆμ–΄ 개발자 리뷰

  • [P1] src/main/java/com/son/soccerStreaming/apifootball/service/ApiFootballSyncStatusController.java:29-94 - 곡용 동기화 APIκ°€ κ΄€λ¦¬μž κΆŒν•œ 없이 λ…ΈμΆœλ¨

    • 문제: /api/v1/sync/statusesλŠ” 인증만 ν•„μš”ν•˜κ³ , /api/v1/sync/standings, /api/v1/sync/fixturesλŠ” authenticated()만 κ±Έλ € μžˆμŠ΅λ‹ˆλ‹€. ν”„λ‘ νŠΈμ—μ„œλŠ” currentUserκ°€ 있으면 λ²„νŠΌμ„ λ…ΈμΆœν•˜μ§€λ§Œ, μ„œλ²„ μΈ‘μ—μ„œ κ΄€λ¦¬μž κΆŒν•œ 검증이 μ—†μ–΄ 일반 둜그인 μ‚¬μš©μžκ°€ μ™ΈλΆ€ 데이터 동기화λ₯Ό 직접 νŠΈλ¦¬κ±°ν•  수 μžˆμŠ΅λ‹ˆλ‹€. @AuthenticationPrincipal userDetails도 μ‹€μ œλ‘œ μ‚¬μš©λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
    • 영ν–₯: λΉ„κ΄€λ¦¬μž μ‚¬μš©μžκ°€ μˆ˜λ™ 동기화λ₯Ό 반볡 ν˜ΈμΆœν•΄ μ™ΈλΆ€ API ν˜ΈμΆœλŸ‰/λ ˆμ΄νŠΈλ¦¬λ°‹μ„ μ†Œλͺ¨ν•˜κ±°λ‚˜, 운영 μ˜λ„μ™€ λ‹€λ₯΄κ²Œ 데이터 갱신을 μœ λ°œν•  수 μžˆμŠ΅λ‹ˆλ‹€.
    • μˆ˜μ • λ°©ν–₯: /api/v1/sync/** POST μ—”λ“œν¬μΈνŠΈλ₯Ό hasRole("ADMIN")둜 μ œν•œν•˜κ³ , μ»¨νŠΈλ‘€λŸ¬μ—μ„œλ„ AuthUserDetails μ—­ν•  검증을 μΆ”κ°€ν•˜μ„Έμš”. μ΅œμ†Œν•œ ν˜„μž¬ userDetailsλ₯Ό μ‚¬μš©ν•΄ ADMIN인지 확인해야 ν•©λ‹ˆλ‹€.
  • [P1] src/main/java/com/son/soccerStreaming/apifootball/service/ApiFootballSyncStatusController.java:40-57,75-92 - 곡용 μˆ˜λ™ 동기화 μΏ¨λ‹€μš΄μ΄ μ„œλ²„ μΈμŠ€ν„΄μŠ€ 둜컬 λ©”λͺ¨λ¦¬λΌ 우회 κ°€λŠ₯

    • 문제: publicSyncCooldownsκ°€ ConcurrentHashMap의 인메λͺ¨λ¦¬ μƒνƒœλΌμ„œ, μ„œλ²„κ°€ μ—¬λŸ¬ λŒ€μ΄κ±°λ‚˜ μž¬μ‹œμž‘λ˜λ©΄ μΏ¨λ‹€μš΄μ΄ μ‚¬λΌμ§‘λ‹ˆλ‹€. 같은 킀라도 μΈμŠ€ν„΄μŠ€λ³„λ‘œ 각각 호좜 κ°€λŠ₯ν•˜κ³ , μž₯μ•  μ‹œ 반볡 μš”μ²­μ„ 막지 λͺ»ν•©λ‹ˆλ‹€.
    • 영ν–₯: 운영 ν™˜κ²½μ—μ„œ β€œ30초 μΏ¨λ‹€μš΄β€μ΄ 사싀상 무λ ₯ν™”λ˜μ–΄ μ™ΈλΆ€ API 보호 λͺ©μ μ„ λ‹¬μ„±ν•˜μ§€ λͺ»ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
    • μˆ˜μ • λ°©ν–₯: μ΅œμ†Œν•œ κ΄€λ¦¬μž μ „μš©μœΌλ‘œ μ œν•œν•˜κ³ , ν•„μš”ν•˜λ©΄ κΈ°μ‘΄ AdminSyncJob/락 λ©”μ»€λ‹ˆμ¦˜μ²˜λŸΌ μ €μž₯μ†Œ 기반 λ˜λŠ” λΆ„μ‚° κ°€λŠ₯ν•œ μ œν•œμœΌλ‘œ λ°”κΎΈμ„Έμš”. ν˜„μž¬ λ²”μœ„μ—μ„œλŠ” μΈμŠ€ν„΄μŠ€ 둜컬 μ œν•œμ΄λΌλŠ” 점을 μ „μ œλ‘œ μ‚¬μš©μž λ…ΈμΆœμ„ μ€„μ΄λŠ” 것이 μ•ˆμ „ν•©λ‹ˆλ‹€.
  • [P1] frontend/src/pages/LeagueStandingsPage.tsx:67-112, frontend/src/pages/LeagueFixturesPage.tsx:233-278, src/main/java/com/son/soccerStreaming/apifootball/service/ApiFootballSyncStatusController.java:58-93 - μž¬μš”μ²­ 직후 μƒνƒœ 갱신이 λˆ„λ½λ˜μ–΄ λ²„νŠΌμ΄ 계속 β€œμ§€μ—°β€μœΌλ‘œ 남을 수 있음

    • 문제: 두 νŽ˜μ΄μ§€ λͺ¨λ‘ refresh*Sync() 성곡 μ‹œ loadStandings/loadFixtures와 loadSyncStatus()λ₯Ό ν˜ΈμΆœν•˜μ§€λ§Œ, μ„œλ²„μ˜ requestPublicSync()λŠ” 동기화 μˆ˜ν–‰ 후에도 μ‹€νŒ¨ μ‹œ μƒνƒœλ₯Ό κ°±μ‹ ν•  수 있고, 성곡 μ‹œμ—λ„ loadSyncStatus()κ°€ μ¦‰μ‹œ ν˜ΈμΆœλ˜λ”λΌλ„ 아직 반영 μ „ μƒνƒœλ₯Ό 읽을 수 μžˆμŠ΅λ‹ˆλ‹€. λ˜ν•œ μ‹€νŒ¨ μ‹œμ—λŠ” μƒνƒœλ§Œ λ‹€μ‹œ 읽고 UI λ©”μ‹œμ§€λŠ” μœ μ§€λ˜λ―€λ‘œ μ‚¬μš©μžλŠ” μ‹€μ œ μž¬μ‹œλ„ κ²°κ³Όλ₯Ό μ¦‰μ‹œ κ΅¬λΆ„ν•˜κΈ° μ–΄λ ΅μŠ΅λ‹ˆλ‹€.
    • 영ν–₯: μ‚¬μš©μžλŠ” μƒˆλ‘œκ³ μΉ¨μ„ λˆŒλ €λŠ”λ°λ„ μ—¬μ „νžˆ stale/failed μƒνƒœκ°€ 남아 μžˆμ–΄μ„œ, 동기화가 μ‹€νŒ¨ν–ˆλŠ”μ§€ 아직 처리 쀑인지 ν—·κ°ˆλ¦΄ 수 μžˆμŠ΅λ‹ˆλ‹€. λͺ¨λ°”μΌμ—μ„œλŠ” 특히 ν˜Όλž€μ΄ μ»€μ§‘λ‹ˆλ‹€.
    • μˆ˜μ • λ°©ν–₯: 곡개 동기화 APIκ°€ 비동기라면 β€œμš”μ²­λ¨β€κ³Ό β€œμ™„λ£Œλ¨β€μ„ λͺ…ν™•νžˆ λΆ„λ¦¬ν•˜κ³ , ν”„λ‘ νŠΈλŠ” 성곡 응닡 ν›„ 일정 μ§€μ—° λ’€ μƒνƒœλ₯Ό μž¬μ‘°νšŒν•˜κ±°λ‚˜ polling ν•˜μ„Έμš”. μ΅œμ†Œν•œ μš”μ²­ 성곡 μ‹œμ—λŠ” μƒνƒœ λ©”μ‹œμ§€λ₯Ό β€œμš”μ²­λ¨/처리 μ€‘β€μœΌλ‘œ ν‘œμ‹œν•΄ μ˜€ν•΄λ₯Ό μ€„μ΄μ„Έμš”.
  • [P2] src/main/java/com/son/soccerStreaming/apifootball/client/ApiFootballCircuitBreaker.java:18-21,42-43 - μ„œν‚· 브레이컀 μƒνƒœκ°€ μΈμŠ€ν„΄μŠ€ 둜컬이라 배포 ν™˜κ²½μ—μ„œ λ³΄ν˜Έκ°€ λΆˆμ™„μ „ν•¨

    • 문제: consecutiveFailures와 openUntilEpochMsκ°€ λ©”λͺ¨λ¦¬ λ‚΄ Atomic 값이라 μ„œλ²„ μΈμŠ€ν„΄μŠ€λ§ˆλ‹€ λ³„λ„μž…λ‹ˆλ‹€. ν•œ μΈμŠ€ν„΄μŠ€μ—μ„œ 연속 μ‹€νŒ¨κ°€ μŒ“μ—¬λ„ λ‹€λ₯Έ μΈμŠ€ν„΄μŠ€λŠ” κ·ΈλŒ€λ‘œ μ™ΈλΆ€ APIλ₯Ό 계속 ν˜ΈμΆœν•  수 μžˆμŠ΅λ‹ˆλ‹€.
    • 영ν–₯: λ©€ν‹° μΈμŠ€ν„΄μŠ€ ν™˜κ²½μ—μ„œ API-Football μž₯μ•  μ‹œ 호좜 차단 νš¨κ³Όκ°€ 절반 μ΄ν•˜λ‘œ λ–¨μ–΄μ§ˆ 수 μžˆμŠ΅λ‹ˆλ‹€.
    • μˆ˜μ • λ°©ν–₯: ν˜„μž¬ κ΅¬μ‘°μ—μ„œ μ™„μ „ν•œ λΆ„μ‚° μ„œν‚· λΈŒλ ˆμ΄μ»€κΉŒμ§€λŠ” λ²”μœ„κ°€ ν¬λ‹ˆ, μ΅œμ†Œν•œ 운영 λ¬Έμ„œ/μ„€μ •μœΌλ‘œ 단일 μΈμŠ€ν„΄μŠ€ 가정이 μ•„λ‹ˆλ©΄ κΈ°λŒ€ νš¨κ³Όκ°€ μ œν•œμ μž„μ„ λͺ…μ‹œν•˜κ±°λ‚˜, 곡톡 μƒνƒœ μ €μž₯μ†Œλ₯Ό μ“°λŠ” λ°©ν–₯을 κ³ λ €ν•˜μ„Έμš”.
  • [P2] src/main/java/com/son/soccerStreaming/apifootball/service/ApiFootballSyncStatusService.java:25-62 및 src/main/java/com/son/soccerStreaming/apifootball/entity/ApiFootballSyncStatus.java:33-55 - μ‹€νŒ¨ μ‹œ 이전 성곡 μ‹œκ°μ΄ λ³΄μ‘΄λ˜μ§€ μ•Šμ•„ β€œμ§€μ—°β€ νŒμ •μ΄ λΆ€μ •ν™•ν•  수 있음

    • 문제: recordFailure()κ°€ lastSuccessAtλ₯Ό μœ μ§€ν•˜κΈ΄ ν•˜μ§€λ§Œ recordAttempt()λŠ” 졜초 1회만 lastSyncedAt을 μ±„μš°κ³ , recordRetryPending()/recordFailure()κ°€ μƒνƒœ μ „ν™˜ 쀑 lastSyncedAt 의미λ₯Ό μΌκ΄€λ˜κ²Œ μœ μ§€ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. 특히 toSyncStatusItem()κ³Ό ν”„λ‘ νŠΈμ˜ lastSuccessfulSyncTime()κ°€ lastSuccessAt β†’ lastSyncedAt 순으둜 fallback ν•˜λŠ”λ°, μ‹€νŒ¨/μž¬μ‹œλ„ νŒ¨ν„΄μ— 따라 β€œμ΅œκ·Ό 성곡 μ‹œκ°β€κ³Ό β€œλ§ˆμ§€λ§‰ μ‹œλ„ μ‹œκ°β€μ΄ μ„žμ—¬ 보일 수 μžˆμŠ΅λ‹ˆλ‹€.
    • 영ν–₯: κ΄€λ¦¬μž ν™”λ©΄κ³Ό μ‚¬μš©μž ν™”λ©΄μ˜ β€œμ΅œκ·Ό μ—…λ°μ΄νŠΈβ€ ν‘œκΈ°κ°€ μ‹€μ œ μ΅œμ‹  성곡 μ‹œμ κ³Ό λ‹€λ₯΄κ²Œ 해석될 수 μžˆμŠ΅λ‹ˆλ‹€.
    • μˆ˜μ • λ°©ν–₯: lastSyncedAtλŠ” 성곡 μ‹œκ°μœΌλ‘œλ§Œ μ“°κ³ , μ‹€νŒ¨/μ‹œλ„λŠ” 별도 ν•„λ“œλ§Œ μ‚¬μš©ν•˜λ„λ‘ 의미λ₯Ό λͺ…ν™•νžˆ λ§žμΆ”μ„Έμš”. ν”„λ‘ νŠΈ fallback도 lastSuccessAt만 κΈ°μ€€μœΌλ‘œ ν†΅μΌν•˜λŠ” 편이 μ•ˆμ „ν•©λ‹ˆλ‹€.
  • [P2] frontend/src/pages/LeagueFixturesPage.tsx:368-376, frontend/src/pages/LeagueStandingsPage.tsx:129-137 - μ—…λ°μ΄νŠΈ μ‹œκ° λ°°μ§€κ°€ μž‘μ€ ν™”λ©΄μ—μ„œ μ‰½κ²Œ μ€„λ°”κΏˆ/클리핑될 수 있음

    • 문제: data-freshnessκ°€ display:flex + justify-content: space-between인데 λ²„νŠΌ/문ꡬλ₯Ό ν•œ 쀄에 κ³ μ •ν•˜λŠ” μΆ”κ°€ 처리 없이 κΈ΄ ν•œκ΅­μ–΄/λ‚ μ§œ ν…μŠ€νŠΈκ°€ λ“€μ–΄κ°‘λ‹ˆλ‹€. 특히 λͺ¨λ°”μΌμ—μ„œ λ‚ μ§œ 문ꡬ와 λ²„νŠΌμ΄ ν•œ 쀄에 λ“€μ–΄κ°€λ©΄ 폭이 λΆ€μ‘±ν•΄μ Έ μž˜λ¦¬κ±°λ‚˜ 두 μ€„λ‘œ 깨질 수 μžˆμŠ΅λ‹ˆλ‹€.
    • 영ν–₯: μ‚¬μš©μžκ°€ μ΅œμ‹ μ„± 정보λ₯Ό λΉ λ₯΄κ²Œ μŠ€μΊ”ν•˜κΈ° μ–΄λ €μ›Œμ§€κ³ , λ²„νŠΌ μ˜μ—­μ΄ 눌리기 νž˜λ“€μ–΄μ§ˆ 수 μžˆμŠ΅λ‹ˆλ‹€.
    • μˆ˜μ • λ°©ν–₯: λͺ¨λ°”일 ν­μ—μ„œλŠ” μ„Έλ‘œ 배치둜 μ „ν™˜ν•˜κ±°λ‚˜ flex-wrap: wrap을 μΆ”κ°€ν•˜μ„Έμš”. μ΅œμ†Œν•œ ν…μŠ€νŠΈμ™€ λ²„νŠΌμ΄ μžμ—°μŠ€λŸ½κ²Œ 내렀가도둝 μ²˜λ¦¬ν•˜λŠ” 게 μ’‹μŠ΅λ‹ˆλ‹€.

λ³΄μ•ˆ 리뷰

  • [Medium] src/main/java/com/son/soccerStreaming/apifootball/service/ApiFootballSyncStatusController.java:20-80 - 곡개 동기화 μ—”λ“œν¬μΈνŠΈμ— 인증만 있고 κ΄€λ¦¬μž κΆŒν•œ μ œν•œμ΄ μ—†μŒ

    • 문제:
      • /api/v1/sync/standings, /api/v1/sync/fixtures POSTκ°€ authenticated()만 μš”κ΅¬ν•©λ‹ˆλ‹€. 즉, 일반 둜그인 μ‚¬μš©μžκ°€ μ™ΈλΆ€ API-Football 동기화λ₯Ό νŠΈλ¦¬κ±°ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
      • PR μ„€λͺ…상 β€œκ΄€λ¦¬μž μˆ˜λ™ 갱신” μš©λ„μΈλ°, μ‹€μ œ λΌμš°νŒ…μ€ μ‚¬μš©μž ν™”λ©΄μ—μ„œ currentUser만 있으면 λ²„νŠΌμ΄ ν‘œμ‹œλ˜κ³  μš”μ²­λ„ μ‹œλ„λ©λ‹ˆλ‹€.
    • 곡격/λ…ΈμΆœ μ‹œλ‚˜λ¦¬μ˜€:
      • μž„μ˜μ˜ 일반 μ‚¬μš©μžκ°€ 반볡적으둜 동기화 μš”μ²­μ„ 보내 μ™ΈλΆ€ API μΏΌν„° μ†Œμ§„, 동기화 큐 적체, κ΄€λ¦¬μž 운영 λ°©ν•΄λ₯Ό μœ λ°œν•  수 μžˆμŠ΅λ‹ˆλ‹€.
      • κ³Όλ„ν•œ μš”μ²­μœΌλ‘œ μ„œν‚· 브레이컀/μΏ¨λ‹€μš΄μ΄ κ°œλ³„ ν‚€ κΈ°μ€€μœΌλ‘œλ§Œ μž‘λ™ν•˜λ©΄, μ—¬λŸ¬ 계정 λ˜λŠ” μ—¬λŸ¬ μ„Έμ…˜μ„ 톡해 우회 μ‹œλ„κ°€ κ°€λŠ₯ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
    • μˆ˜μ • λ°©ν–₯:
      • ν•΄λ‹Ή 곡개 동기화 POSTλŠ” ROLE_ADMIN μ „μš©μœΌλ‘œ μ œν•œν•˜κ±°λ‚˜, μ΅œμ†Œν•œ μ„œλ²„ μΈ‘μ—μ„œ κ΄€λ¦¬μž κΆŒν•œμ„ λͺ…μ‹œμ μœΌλ‘œ κ²€μ¦ν•˜μ„Έμš”.
      • ν”„λ‘ νŠΈμ—”λ“œμ˜ λ²„νŠΌ ν‘œμ‹œλ„ κ΄€λ¦¬μžμ—κ²Œλ§Œ λ…ΈμΆœλ˜λ„λ‘ λ§žμΆ”λŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€.
  • [Medium] frontend/src/pages/LeagueStandingsPage.tsx:67-110, frontend/src/pages/LeagueFixturesPage.tsx:233-270 - 일반 μ‚¬μš©μž ν™”λ©΄μ—μ„œ 동기화 μš”μ²­ UI와 호좜이 λ…ΈμΆœλ¨

    • 문제:
      • νŽ˜μ΄μ§€ μ»΄ν¬λ„ŒνŠΈκ°€ currentUser만 있으면 stale μƒνƒœμ—μ„œ refresh λ²„νŠΌμ„ 보여주고 /api/v1/sync/**둜 POSTλ₯Ό λ³΄λƒ…λ‹ˆλ‹€.
      • ν˜„μž¬ λ°±μ—”λ“œ 인증 정책상 일반 μ‚¬μš©μžλ„ μ ‘κ·Ό κ°€λŠ₯ν•˜λ―€λ‘œ, ν”„λ‘ νŠΈλŠ” 사싀상 λΉ„κ΄€λ¦¬μž μ‚¬μš©μžμ—κ²Œ 동기화 κΈ°λŠ₯을 λ…ΈμΆœν•©λ‹ˆλ‹€.
    • 곡격/λ…ΈμΆœ μ‹œλ‚˜λ¦¬μ˜€:
      • λ‘œκ·ΈμΈν•œ 일반 μ‚¬μš©μžκ°€ κ²½κΈ°/μˆœμœ„ νŽ˜μ΄μ§€μ—μ„œ 데이터 κ°±μ‹  μš”μ²­μ„ λ°˜λ³΅ν•΄ μ„œλΉ„μŠ€ λ¦¬μ†ŒμŠ€μ™€ μ™ΈλΆ€ APIλ₯Ό μ†Œλͺ¨ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
    • μˆ˜μ • λ°©ν–₯:
      • μ‚¬μš©μž ν™”λ©΄μ—μ„œ λ²„νŠΌμ„ κ΄€λ¦¬μž κΆŒν•œ 보유 μ‹œμ—λ§Œ ν‘œμ‹œν•˜μ„Έμš”.
      • λ°±μ—”λ“œ κΆŒν•œ 체크도 λ°˜λ“œμ‹œ ν•¨κ»˜ κ°•ν™”ν•΄μ•Ό ν•©λ‹ˆλ‹€.
  • [Low] src/main/java/com/son/soccerStreaming/admin/service/AdminService.java:1299-1368 - 감사 둜그 상세 λ…ΈμΆœ λ²”μœ„κ°€ λΆ€λΆ„μ μœΌλ‘œ ν™•μž₯됨

    • 문제:
      • publicAuditDetails()κ°€ targetId, leagueId, teamId, playerId, fixtureId, eventSequence 등을 μ‘°ν•©ν•΄ 외뢀에 λ…ΈμΆœν•©λ‹ˆλ‹€.
      • λ³Έλ¬Έμ—μ„œ 민감 데이터 μ „μ²΄λŠ” μˆ¨κΈ΄λ‹€κ³  ν–ˆμ§€λ§Œ, AdminAuditType.SYNC의 detailsλ₯Ό νŒŒμ‹±ν•΄ λ…ΈμΆœν•˜λ―€λ‘œ ν–₯ν›„ details 포맷이 λ°”λ€Œλ©΄ μ˜ˆμƒμΉ˜ λͺ»ν•œ 값이 λ“œλŸ¬λ‚  수 μžˆμŠ΅λ‹ˆλ‹€.
    • 곡격/λ…ΈμΆœ μ‹œλ‚˜λ¦¬μ˜€:
      • 감사 둜그 쑰회 κΆŒν•œμ΄ μžˆλŠ” μ‚¬μš©μžμ—κ²Œ λ‚΄λΆ€ μ‹λ³„μžμ™€ μž‘μ—… νŒŒλΌλ―Έν„°κ°€ 더 많이 λ…ΈμΆœλ©λ‹ˆλ‹€.
    • μˆ˜μ • λ°©ν–₯:
      • ν—ˆμš© νŒŒλΌλ―Έν„° ν™”μ΄νŠΈλ¦¬μŠ€νŠΈλ₯Ό 더 μ—„κ²©νžˆ μœ μ§€ν•˜κ³ , 포맷 λ³€κ²½ μ‹œ λˆ„μΆœλ˜μ§€ μ•Šλ„λ‘ ν…ŒμŠ€νŠΈλ₯Ό μΆ”κ°€ν•˜μ„Έμš”.
      • 특히 details λ¬Έμžμ—΄ 전체λ₯Ό νŒŒμ‹±ν•˜λŠ” λ‘œμ§μ€ μž…λ ₯ ν˜•μ‹μ΄ λ°”λ€Œλ©΄ κ³Όλ…ΈμΆœ μœ„ν—˜μ΄ μžˆμœΌλ‹ˆ κ΅¬μ‘°ν™”λœ ν•„λ“œ μ‚¬μš©μ„ κ³ λ €ν•˜μ„Έμš”.
        Model: gpt-5.4-mini

@son0307
son0307 merged commit dd132b0 into main Jul 10, 2026
1 check passed
@son0307
son0307 deleted the codex/api-football-sync-resilience branch July 10, 2026 08:00
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