mmday-firebase/graphify-out/cache/semantic/ebee6bb0067bafc39c67b1de39ada6b1f03f1a3cd0acef3975cd27c01b09b725.json
윤정민 20e3b1cbf0 Add a script to fetch and display KBO team rankings and records.
- KBO 공식 홈페이지에서 연도별 팀 순위 및 상대 전적 데이터를 가져오는 크롤링 스크립트를 구현했습니다.
- ASP.NET의 ViewState 및 EventValidation 필드를 처리하여 동적인 연도 전환 요청을 지원합니다.
- 데이터를 가독성 높은 콘솔 테이블 형태로 출력하거나 JSON 형식으로 변환하는 기능을 제공합니다.
2026-05-29 14:59:50 +09:00

1 line
18 KiB
JSON

{"nodes": [{"id": "opt_W1", "label": "W1: Games Sync Diff Optimization", "file_type": "document", "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": null, "source_url": null, "captured_at": null, "author": null, "contributor": null}, {"id": "opt_W2", "label": "W2: voteHistory Double Write Consolidation", "file_type": "document", "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": null, "source_url": null, "captured_at": null, "author": null, "contributor": null}, {"id": "opt_W3", "label": "W3: Stats Invalidation Fan-out Per User", "file_type": "document", "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": null, "source_url": null, "captured_at": null, "author": null, "contributor": null}, {"id": "opt_W4", "label": "W4: Users Cron Write Deduplication", "file_type": "document", "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": null, "source_url": null, "captured_at": null, "author": null, "contributor": null}, {"id": "opt_W5", "label": "W5: getMe photoUrl Write Conservative", "file_type": "document", "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": null, "source_url": null, "captured_at": null, "author": null, "contributor": null}, {"id": "opt_W6", "label": "W6: kboCache game_detail TTL Natural Expiry", "file_type": "document", "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": null, "source_url": null, "captured_at": null, "author": null, "contributor": null}, {"id": "opt_R1", "label": "R1: dailyArchive listByDate Sharing", "file_type": "document", "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": null, "source_url": null, "captured_at": null, "author": null, "contributor": null}, {"id": "opt_R2", "label": "R2: getStats Incremental Aggregation", "file_type": "document", "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": null, "source_url": null, "captured_at": null, "author": null, "contributor": null}, {"id": "opt_R3", "label": "R3: dailyArchive userVotes Shallow Read", "file_type": "document", "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": null, "source_url": null, "captured_at": null, "author": null, "contributor": null}, {"id": "opt_R4", "label": "R4: Cache Stampede Polling Backoff", "file_type": "document", "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": null, "source_url": null, "captured_at": null, "author": null, "contributor": null}, {"id": "opt_R5", "label": "R5: Scoreboard getUser Select + Rank Cache", "file_type": "document", "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": null, "source_url": null, "captured_at": null, "author": null, "contributor": null}, {"id": "opt_R6", "label": "R6: createMe/updateMe Remove Secondary getUser", "file_type": "document", "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": null, "source_url": null, "captured_at": null, "author": null, "contributor": null}, {"id": "opt_R7", "label": "R7: Rank Multi-year getOrFetch Parallelization", "file_type": "document", "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": null, "source_url": null, "captured_at": null, "author": null, "contributor": null}, {"id": "opt_C1", "label": "C1: voteSummary Polling to RTDB Subscription", "file_type": "document", "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": null, "source_url": null, "captured_at": null, "author": null, "contributor": null}, {"id": "opt_C2", "label": "C2: rank/h2h Duplicate Call Removal", "file_type": "document", "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": null, "source_url": null, "captured_at": null, "author": null, "contributor": null}, {"id": "opt_C3", "label": "C3: pitchers/acePitcher Duplicate Call Removal", "file_type": "document", "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": null, "source_url": null, "captured_at": null, "author": null, "contributor": null}, {"id": "opt_C4", "label": "C4: Uncached autoDispose Providers SWR/keepAlive", "file_type": "document", "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": null, "source_url": null, "captured_at": null, "author": null, "contributor": null}, {"id": "backend_debug_handlers", "label": "debugHandlers.ts (Unauthenticated forceSync/dailyArchive)", "file_type": "code", "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": "debugHandlers.ts", "source_url": null, "captured_at": null, "author": null, "contributor": null}, {"id": "backend_sync_games_service", "label": "syncGamesForMonth (gameSyncService.ts:63)", "file_type": "code", "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": "gameSyncService.ts:63", "source_url": null, "captured_at": null, "author": null, "contributor": null}, {"id": "backend_daily_archive", "label": "dailyArchive.ts (setDay + judgeDay)", "file_type": "code", "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": "dailyArchive.ts", "source_url": null, "captured_at": null, "author": null, "contributor": null}, {"id": "backend_judge_day", "label": "judgeDay (judgmentService.ts:94)", "file_type": "code", "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": "judgmentService.ts:94", "source_url": null, "captured_at": null, "author": null, "contributor": null}, {"id": "backend_invalidate_stats", "label": "invalidateStats (/cache/stats/{uid} delete)", "file_type": "code", "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": null, "source_url": null, "captured_at": null, "author": null, "contributor": null}, {"id": "backend_game_result_service", "label": "gameResultService.ts:42 (stats fan-out on game complete)", "file_type": "code", "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": "gameResultService.ts:42", "source_url": null, "captured_at": null, "author": null, "contributor": null}, {"id": "backend_on_game_completed", "label": "onGameCompleted.ts:59 (Firestore trigger)", "file_type": "code", "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": "onGameCompleted.ts:59", "source_url": null, "captured_at": null, "author": null, "contributor": null}, {"id": "fs_games", "label": "Firestore: games collection", "file_type": "code", "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": null, "source_url": null, "captured_at": null, "author": null, "contributor": null}, {"id": "fs_vote_history", "label": "Firestore: voteHistory collection", "file_type": "code", "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": null, "source_url": null, "captured_at": null, "author": null, "contributor": null}, {"id": "fs_daily_archive", "label": "Firestore: dailyArchive collection", "file_type": "code", "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": null, "source_url": null, "captured_at": null, "author": null, "contributor": null}, {"id": "fs_cache_stats", "label": "Firestore/Cache: /cache/stats/{uid}", "file_type": "code", "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": null, "source_url": null, "captured_at": null, "author": null, "contributor": null}, {"id": "rtdb_user_votes", "label": "RTDB: /userVotes (full tree, all users/dates)", "file_type": "code", "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": null, "source_url": null, "captured_at": null, "author": null, "contributor": null}, {"id": "rtdb_votes_gameId", "label": "RTDB: votes/{gameId}/counts (public read)", "file_type": "code", "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": null, "source_url": null, "captured_at": null, "author": null, "contributor": null}, {"id": "fs_kbo_cache", "label": "Firestore/Cache: kboCache (game_detail__ TTL)", "file_type": "code", "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": null, "source_url": null, "captured_at": null, "author": null, "contributor": null}, {"id": "backend_get_stats_cf", "label": "CF: /stats (getStats Cloud Function)", "file_type": "code", "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": null, "source_url": null, "captured_at": null, "author": null, "contributor": null}, {"id": "backend_wait_for_cache", "label": "waitForCache / getOrFetchDynamic (polling lock)", "file_type": "code", "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": null, "source_url": null, "captured_at": null, "author": null, "contributor": null}, {"id": "backend_cron_0200", "label": "Cron Job: 02:00 daily (syncGamesForMonth + kboCache invalidation)", "file_type": "code", "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": null, "source_url": null, "captured_at": null, "author": null, "contributor": null}], "edges": [{"source": "backend_sync_games_service", "target": "fs_games", "relation": "writes_to", "confidence": "EXTRACTED", "confidence_score": 1.0, "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": "gameSyncService.ts:63", "weight": 1.0}, {"source": "backend_cron_0200", "target": "backend_sync_games_service", "relation": "triggers", "confidence": "EXTRACTED", "confidence_score": 1.0, "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": null, "weight": 1.0}, {"source": "opt_W1", "target": "backend_sync_games_service", "relation": "optimized_by", "confidence": "EXTRACTED", "confidence_score": 1.0, "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": null, "weight": 1.0}, {"source": "opt_W1", "target": "fs_games", "relation": "optimized_by", "confidence": "INFERRED", "confidence_score": 0.95, "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": null, "weight": 0.9}, {"source": "backend_daily_archive", "target": "fs_vote_history", "relation": "writes_to", "confidence": "EXTRACTED", "confidence_score": 1.0, "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": "dailyArchive.ts:130", "weight": 1.0}, {"source": "backend_judge_day", "target": "fs_vote_history", "relation": "writes_to", "confidence": "EXTRACTED", "confidence_score": 1.0, "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": "judgmentService.ts:94", "weight": 1.0}, {"source": "opt_W2", "target": "backend_daily_archive", "relation": "optimized_by", "confidence": "EXTRACTED", "confidence_score": 1.0, "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": null, "weight": 1.0}, {"source": "opt_W2", "target": "backend_judge_day", "relation": "optimized_by", "confidence": "EXTRACTED", "confidence_score": 1.0, "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": null, "weight": 1.0}, {"source": "backend_daily_archive", "target": "fs_daily_archive", "relation": "reads_from", "confidence": "EXTRACTED", "confidence_score": 1.0, "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": "dailyArchive.ts:96", "weight": 1.0}, {"source": "opt_R1", "target": "backend_daily_archive", "relation": "optimized_by", "confidence": "EXTRACTED", "confidence_score": 1.0, "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": null, "weight": 1.0}, {"source": "opt_R1", "target": "fs_games", "relation": "optimized_by", "confidence": "INFERRED", "confidence_score": 0.95, "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": null, "weight": 0.9}, {"source": "backend_on_game_completed", "target": "backend_invalidate_stats", "relation": "triggers", "confidence": "EXTRACTED", "confidence_score": 1.0, "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": "onGameCompleted.ts:59", "weight": 1.0}, {"source": "backend_invalidate_stats", "target": "fs_cache_stats", "relation": "invalidates", "confidence": "EXTRACTED", "confidence_score": 1.0, "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": null, "weight": 1.0}, {"source": "backend_game_result_service", "target": "backend_invalidate_stats", "relation": "triggers", "confidence": "EXTRACTED", "confidence_score": 1.0, "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": "gameResultService.ts:42", "weight": 1.0}, {"source": "opt_W3", "target": "backend_invalidate_stats", "relation": "optimized_by", "confidence": "EXTRACTED", "confidence_score": 1.0, "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": null, "weight": 1.0}, {"source": "opt_R2", "target": "fs_cache_stats", "relation": "optimized_by", "confidence": "EXTRACTED", "confidence_score": 1.0, "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": null, "weight": 1.0}, {"source": "opt_R2", "target": "fs_vote_history", "relation": "optimized_by", "confidence": "EXTRACTED", "confidence_score": 1.0, "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": null, "weight": 1.0}, {"source": "backend_get_stats_cf", "target": "fs_vote_history", "relation": "reads_from", "confidence": "EXTRACTED", "confidence_score": 1.0, "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": null, "weight": 1.0}, {"source": "backend_get_stats_cf", "target": "fs_cache_stats", "relation": "reads_from", "confidence": "INFERRED", "confidence_score": 0.95, "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": null, "weight": 0.9}, {"source": "opt_R3", "target": "rtdb_user_votes", "relation": "optimized_by", "confidence": "EXTRACTED", "confidence_score": 1.0, "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": null, "weight": 1.0}, {"source": "backend_daily_archive", "target": "rtdb_user_votes", "relation": "reads_from", "confidence": "EXTRACTED", "confidence_score": 1.0, "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": "dailyArchive.ts:96", "weight": 1.0}, {"source": "opt_R4", "target": "backend_wait_for_cache", "relation": "optimized_by", "confidence": "EXTRACTED", "confidence_score": 1.0, "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": null, "weight": 1.0}, {"source": "backend_cron_0200", "target": "fs_kbo_cache", "relation": "invalidates", "confidence": "EXTRACTED", "confidence_score": 1.0, "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": null, "weight": 1.0}, {"source": "opt_W6", "target": "fs_kbo_cache", "relation": "optimized_by", "confidence": "EXTRACTED", "confidence_score": 1.0, "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": null, "weight": 1.0}, {"source": "opt_C1", "target": "client_provider_vote_summary", "relation": "optimized_by", "confidence": "EXTRACTED", "confidence_score": 1.0, "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": null, "weight": 1.0}, {"source": "opt_C1", "target": "rtdb_votes_gameId", "relation": "reads_from", "confidence": "EXTRACTED", "confidence_score": 1.0, "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": null, "weight": 1.0}, {"source": "opt_C2", "target": "client_provider_h2h", "relation": "optimized_by", "confidence": "EXTRACTED", "confidence_score": 1.0, "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": null, "weight": 1.0}, {"source": "opt_C3", "target": "client_provider_ace_pitcher", "relation": "optimized_by", "confidence": "EXTRACTED", "confidence_score": 1.0, "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": null, "weight": 1.0}, {"source": "opt_C4", "target": "client_provider_current_user", "relation": "optimized_by", "confidence": "EXTRACTED", "confidence_score": 1.0, "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": null, "weight": 1.0}, {"source": "opt_C4", "target": "client_provider_scoreboard", "relation": "optimized_by", "confidence": "EXTRACTED", "confidence_score": 1.0, "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": null, "weight": 1.0}, {"source": "opt_C4", "target": "client_provider_user_stats", "relation": "optimized_by", "confidence": "EXTRACTED", "confidence_score": 1.0, "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": null, "weight": 1.0}, {"source": "backend_debug_handlers", "target": "backend_sync_games_service", "relation": "calls", "confidence": "EXTRACTED", "confidence_score": 1.0, "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": "debugHandlers.ts", "weight": 1.0}, {"source": "backend_debug_handlers", "target": "backend_daily_archive", "relation": "calls", "confidence": "EXTRACTED", "confidence_score": 1.0, "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md", "source_location": "debugHandlers.ts", "weight": 1.0}], "hyperedges": [{"id": "tier1_optimizations", "label": "Tier 1 High-Impact Low-Risk Optimizations", "nodes": ["opt_W1", "opt_W2", "opt_R1", "opt_C1"], "relation": "form", "confidence": "EXTRACTED", "confidence_score": 1.0, "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md"}, {"id": "tier2_optimizations", "label": "Tier 2 Medium-Impact Optimizations", "nodes": ["opt_R2", "opt_W3", "opt_R3", "opt_R4", "opt_C2", "opt_C3"], "relation": "form", "confidence": "EXTRACTED", "confidence_score": 1.0, "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md"}, {"id": "tier3_optimizations", "label": "Tier 3 Small / Housekeeping Optimizations", "nodes": ["opt_W4", "opt_W5", "opt_W6", "opt_R5", "opt_R6", "opt_R7", "opt_C4"], "relation": "form", "confidence": "EXTRACTED", "confidence_score": 1.0, "source_file": "graphify-out/tmp-corpus/backend_optimization-plan.md"}]}