Crossλ κ°μ²΄ μΈμ κΈ°μ κ³Ό μ€μκ° λ°μ΄ν° μκ°νλ₯Ό νμ©ν μ€νΈλ¦¬λ° μΉ μλΉμ€μ λλ€. κΈ°μ‘΄μ μΌλ°©μ μΈ μ€ν¬μΈ μ€κ³μ λ¬λ¦¬, μνΈμμ© κΈ°λ°μ μ½ν μΈ λ₯Ό μ 곡νμ¬ μμ²μλ€μ΄ μΆκ΅¬λ₯Ό λ³΄λ€ λΆμμ μ΄κ³ μ§κ΄μ μΌλ‘ μ¦κΈΈ μ μλλ‘ μ§μν©λλ€.
- Enhanced Viewing: μμ μμ μ¦κ°λ λ°μ΄ν°λ₯Ό ν΅ν μ§κ΄μ κ²½κΈ° μμ²
- Player Recognition: κ°μ²΄ μΈμ κΈ°μ κΈ°λ° μ€μκ° μ μ μΆμ μμ€ν
- Interactive Dashboard: μ¬μ©μ λ§μΆ€ν λλκ·Έμ€λλ‘ ν΅κ³ λμ보λ
- Real-time Analytics: μ€μκ° κ²½κΈ° λ°μ΄ν° λΆμ λ° μκ°ν
- κ°μ²΄ μΆμ νλ‘κ·Έλ¨ κΈ°λ° μ μ λΌλ²¨λ§ λ°μ΄ν° νμ©
- μ€μκ° μ μ λ§νΉ λ° μμΉ μΆμ
- ν μ 보 ν¨λκ³Ό μ°λλ μ μ μ 보 μ‘°ν
- λ₯λ ₯μΉ λΉκ΅ ν¨λ: λ μ΄λ μ°¨νΈ κΈ°λ° μ μ λ₯λ ₯μΉ λΆμ λ° λΉκ΅
- μ€μκ° κΈ°λ‘ ν¨λ: λ§λ κ·Έλνλ‘ μ€μκ° κ²½κΈ° λ°μ΄ν° μκ°ν
- 곡격 μνμ€ ν¨λ: μ€μκ° κ³΅κ²© κ³Όμ λ° λ³Ό μμ κΆ μκ°ν
- μν λ°μ΄ν° ν¨λ: μν λΆν¬λ λ° κ³¨ κ·Όμ λ λμ λ°μ΄ν° λΆμ
- κ° ν μ μ μ 보 μμΈ μ‘°ν
- μ μ μΆμ λ²νΌκ³Ό μ°κ³ν λ§νΉ κΈ°λ₯
- μ€μκ° μ μ μν μ 보 μ λ°μ΄νΈ
- 보λ‘λ Έμ΄ λ€μ΄μ΄κ·Έλ¨: μ μλ³ μν₯λ ₯ κ³΅κ° μκ°ν
- ν¨μ€ λ°μ΄ν° μκ°ν: μ’ν λ°μ΄ν°μ μ΄λ²€νΈ λ°μ΄ν° κ²°ν© λΆμ
μ΄ νλ‘μ νΈλ λμΌ λ°±μλ(Dual Backend) κ΅¬μ‘°λ‘ μ€κ³λμμ΅λλ€.
- Node.js μ€νΈλ¦¬λ° λ°±μλ: HLS λΉλμ€ μ€νΈλ¦¬λ°κ³Ό WebSocketμ μ΄μ©ν μ€μκ° ν΅μ μ λ΄λΉν©λλ€.
- Python λΆμ λ°±μλ: FastAPIλ₯Ό κΈ°λ°μΌλ‘, κ²½κΈ° λΆμ λ°μ΄ν° μμ²μ μ²λ¦¬νκ³ ν΅κ³ μ 보λ₯Ό κ°κ³΅νμ¬ μ 곡ν©λλ€.
βββββββββββββββββββββββ HTTP/API ββββββββββββββββββββββββββ
β Vue.js Frontend β ββββββββββββββββββΊ β Python/FastAPI Backend β
β (UI & Interactions) β β (Data Analytics API) β
βββββββββββββββββββββββ ββββββββββββββββββββββββββ
β² β
β WebSocket/HTTP βΌ
β (Video Stream) ββββββββββββββββββββ
β β File System β
ββββββββββββββββββββββββ β (CSV, JSON Data) β
β Node.js Backend β ββββββββββββββββββββ
β (Streaming & Sockets)β
ββββββββββββββββββββββββ
Alternative Architecture (exhibition-ver branch):
βββββββββββββββββββββββ HTTP/API ββββββββββββββββββββββββββ
β Vue.js Frontend β ββββββββββββββββββΊ β Python/FastAPI Backend β
β (UI & Interactions) β β (Data Analytics API) β
βββββββββββββββββββββββ ββββββββββββββββββββββββββ
β² β
β HTTPS/HLS βΌ
β (Video Stream) ββββββββββββββββββββ
β β File System β
ββββββββββββββββββββββββ β (CSV, JSON Data) β
β AWS CloudFront CDN β ββββββββββββββββββββ
β (Global Delivery) β
ββββββββββββββββββββββββ
β
βΌ
ββββββββββββββββββββββββ
β AWS S3 β
β (Video Storage) β
ββββββββββββββββββββββββ
# Frontend (Vue.js)
cd frontend
npm install
# Streaming Backend (Node.js)
cd ../socket-backend
npm install
# Analytics Backend (Python)
cd ../backend
# Conda νκ²½ μμ± (μ΅μ΄ 1ν)
conda env create -f environment.ymlFrontend (Port: 8080)
cd frontend
npm run serveStreaming Backend (Port: 3000)
cd socket-backend
node server.jsAnalytics Backend (Port: 8000)
cd backend
conda activate snakemake
uvicorn app.main:app --reloadstartup/
βββ π frontend/ # Vue.js νλ‘ νΈμλ μ ν리μΌμ΄μ
βββ π socket-backend/ # Node.js μ€νΈλ¦¬λ° λ°±μλ
β βββ π router/
β βββ π video/
β βββ π server.js
βββ π backend/ # Python λ°μ΄ν° λΆμ λ°±μλ
β βββ π app/
β β βββ π common/ # κ³΅ν΅ μ€μ (Config)
β β βββ π routes/ # API λΌμ°νΈ
β β β βββ π endpoints/ # μλν¬μΈνΈ λ‘μ§ (matches, tracking)
β β βββ π schemas/ # λ°μ΄ν° μ ν¨μ± κ²μ¦ μ€ν€λ§
β β βββ π main.py # FastAPI μ ν리μΌμ΄μ
μ§μ
μ
β βββ π matches/ # κ²½κΈ° λ°μ΄ν° (CSV, JSON)
β βββ π Dockerfile
βββ π TECHNICAL_DOCUMENTATION.md
βββ π README.md
GET /video/:videoName: HTTP Range Requestλ₯Ό μ§μνλ λΉλμ€ μ€νΈλ¦¬λ°GET /audio/:audioName: μ€λμ€ μ€νΈλ¦¬λ°WebSocket: μ€μκ° ν΅μ μ μν μμΌ μ°κ²°
GET /routes/matches/lineup/{time}: νΉμ μκ°μ μΆμ μ€μΈ μ μ λͺ©λ‘ μ‘°νGET /routes/matches/stats/{time}: νΉμ μκ°κΉμ§μ κ²½κΈ° λ° μ μλ³ μμΈ ν΅κ³ λ°μ΄ν° μ§κ³GET /routes/matches/sequence/{time}: νμ¬ μκ° κΈ°μ€ κ³΅κ²© μνμ€ λ°μ΄ν° μ‘°νGET /routes/matches/shots/{time}: μν λ° κΈ°λ λμ (xG) λ°μ΄ν° μ‘°νGET /routes/tracking/info/{frame}: νΉμ νλ μμ μ μ λ° κ³΅ νΈλνΉ μ’ν λ°μ΄ν° μ‘°ν
npm run serve # κ°λ° μλ² μ€ν
npm run build # νλ‘λμ
λΉλCrossλ 3-tier μν€ν μ²λ‘ μ€κ³λμ΄ Frontend, Streaming Backend, Analytics Backendκ° λ 립μ μΌλ‘ λμνλ©° ν¨μ¨μ μΌλ‘ ν΅μ ν©λλ€.
μΆκ΅¬ κ²½κΈ°μ νΈλνΉ λ°μ΄ν°λ₯Ό μμ§νκ³ μ μ²λ¦¬νλ νμ΄νλΌμΈμ ꡬμΆνμ΅λλ€.
Player Tracking Dataμ Voronoi Diagramμ κ²°ν©νμ¬ μμ μμ μ¦κ°λ λ°μ΄ν° μκ°νλ₯Ό μ 곡νλ λ λλ§ μμ€ν μ λλ€.
- HLS μ μν μ€νΈλ¦¬λ°: HLS.jsλ₯Ό νμ©νμ¬ λ€νΈμν¬ μνμ λ°λΌ λΉλμ€ νμ§μ μλ μ‘°μ νλ μ μν μ€νΈλ¦¬λ°μ ꡬννμ΅λλ€.
- ν¨μ¨μ μΈ λΉλμ€ μνΉ: HTTP 206 Partial Content μλ΅μ μ²λ¦¬νμ¬, λμ©λ λΉλμ€ νμΌμμλ λΉ λ₯΄κ³ ν¨μ¨μ μΈ νμ(seeking)μ΄ κ°λ₯νλλ‘ μ΅μ ννμ΅λλ€.
- λκ·λͺ¨ μ€νΈλ¦¬λ° λ°μ΄ν° κ΄λ¦¬: 6,000κ° μ΄μμ HLS μΈκ·Έλ¨ΌνΈ(.ts) νμΌκ³Ό λ€μ€ λΉλμ€ μ€νΈλ¦Ό(video.m3u8, video_passroot.m3u8 λ±)μ μμ μ μΌλ‘ κ΄λ¦¬νλ μμ€ν μ ꡬμΆνμ΅λλ€.
- μ¬μ©μ λ§μΆ€ν λμ보λ: vuedraggable λΌμ΄λΈλ¬λ¦¬λ₯Ό μ¬μ©νμ¬ μ¬μ©μκ° μ§μ PlayerStats, MatchStats λ±μ ν΅κ³ μ»΄ν¬λνΈλ₯Ό λλκ·Έμ€λλ‘μΌλ‘ λ°°μΉν μ μλ λμ λμ보λλ₯Ό ꡬννμ΅λλ€.
- μ€μκ° λ°μ΄ν° μκ°ν: Chart.js κΈ°λ°μ λ§λ(Bar) λ° λ μ΄λ(Radar) μ°¨νΈλ₯Ό ν΅ν΄ μ€ν¬μΈ ν΅κ³ λ°μ΄ν°λ₯Ό ν¨κ³Όμ μΌλ‘ μκ°ννμ΅λλ€.
- 체κ³μ μΈ μν κ΄λ¦¬: Vuexλ₯Ό λμ νμ¬ λΉλμ€ μ¬μ μν, UI μ»΄ν¬λνΈμ νμ μ¬λΆ, λμ보λ λ μ΄μμ λ± λ³΅μ‘ν μνλ₯Ό μ€μμμ 체κ³μ μΌλ‘ κ΄λ¦¬ν©λλ€.
보λ‘λ Έμ΄ λ€μ΄μ΄κ·Έλ¨ κΈ°λ° μ μ μν₯λ ₯ μκ°ν
μ μλ€μ μμΉ λ°μ΄ν°λ₯Ό κΈ°λ°μΌλ‘ 보λ‘λ Έμ΄ λ€μ΄μ΄κ·Έλ¨μ μμ±νμ¬, κ²½κΈ°μ₯ λ΄ κ° μ μμ μ§λ°° μμκ³Ό μν₯λ ₯μ μ§κ΄μ μΌλ‘ ννν©λλ€.
ν¨μ€ λ€νΈμν¬ λ° λ£¨νΈ μκ°ν
κ²½κΈ° μ΄λ²€νΈ λ°μ΄ν°μ μ’ν λ°μ΄ν°λ₯Ό κ²°ν©νμ¬ νμ ν¨μ€ λ€νΈμν¬μ 곡격 루νΈλ₯Ό μμ μμ μκ°νν©λλ€.
- FastAPI κΈ°λ° λΆμ μλ²: Pythonμ FastAPIμ Pandasλ₯Ό μ¬μ©νμ¬ λμ©λ κ²½κΈ° λ°μ΄ν°(CSV)λ₯Ό μ€μκ°μΌλ‘ κ°κ³΅νλ λΆμ API μλ²λ₯Ό ꡬμΆνμ΅λλ€.
- λμ λ°μ΄ν° μ§κ³: μμ μ¬μ μκ°μ λ§μΆ° κ΄λ ¨ κ²½κΈ° μ΄λ²€νΈλ€μ λμ μΌλ‘ νν°λ§νκ³ , μ μλ³ μ€ν―, 곡격 μνμ€, κΈ°λ λμ (xG)κ³Ό κ°μ μ μ λ λ°μ΄ν°λ₯Ό κ³μ°νμ¬ μ 곡ν©λλ€.
- 컨ν μ΄λνλ λ°±μλ: Dockerλ₯Ό ν΅ν΄ Python μ€ν νκ²½μ 컨ν μ΄λννμ¬, κ°λ° λ° λ°°ν¬ νκ²½μ μΌκ΄μ±κ³Ό νμ₯μ±μ ν보νμ΅λλ€.




