# 🎡 MyListBridge μŒμ•… 슀트리밍 μ„œλΉ„μŠ€ κ°„ ν”Œλ ˆμ΄λ¦¬μŠ€νŠΈλ₯Ό μ†μ‰½κ²Œ 이전할 수 μžˆλŠ” μ›Ή μ• ν”Œλ¦¬μΌ€μ΄μ…˜μž…λ‹ˆλ‹€. ## ✨ μ£Όμš” κΈ°λŠ₯ ### VIBE β†’ Spotify ν”Œλ ˆμ΄λ¦¬μŠ€νŠΈ 이전 - πŸ” VIBE λ‘œκ·ΈμΈμ„ ν†΅ν•œ ν”Œλ ˆμ΄λ¦¬μŠ€νŠΈ κ°€μ Έμ˜€κΈ° - πŸ”— VIBE ν”Œλ ˆμ΄λ¦¬μŠ€νŠΈ URL둜 직접 κ°€μ Έμ˜€κΈ° - 🎯 νŠΈλž™ λ‹¨μœ„ 선택 및 이전 - πŸ“ Spotify μ‹ κ·œ ν”Œλ ˆμ΄λ¦¬μŠ€νŠΈ 생성 λ˜λŠ” κΈ°μ‘΄ ν”Œλ ˆμ΄λ¦¬μŠ€νŠΈμ— μΆ”κ°€ - πŸ”„ μžλ™ 토큰 κ°±μ‹ μœΌλ‘œ λŠκΉ€ μ—†λŠ” μ‚¬μš©μž κ²½ν—˜ ### λ³΄μ•ˆ - πŸ”’ AES256 μ•”ν˜Έν™”λ₯Ό ν†΅ν•œ μ•ˆμ „ν•œ 둜그인 정보 전솑 - 🎫 OAuth 2.0 PKCE λ°©μ‹μ˜ Spotify 인증 - ⏱️ Access Token μžλ™ κ°±μ‹  (만료 5λΆ„ μ „) ### μ‚¬μš©μž κ²½ν—˜ - 🎨 λͺ¨λ˜ν•œ UI/UX (shadcn/ui) - πŸŒ“ 닀크 λͺ¨λ“œ 지원 - πŸ“± λ°˜μ‘ν˜• λ””μžμΈ (λͺ¨λ°”일/νƒœλΈ”λ¦Ώ/λ°μŠ€ν¬ν†±) - ⚑ λΆ€λ“œλŸ¬μš΄ μ• λ‹ˆλ©”μ΄μ…˜ (Framer Motion) - πŸ”” μ‹€μ‹œκ°„ μ•Œλ¦Ό (Toast) - 🚫 쀑볡 클릭 λ°©μ§€ 및 λ‘œλ”© μƒνƒœ ν‘œμ‹œ ## πŸ› οΈ 기술 μŠ€νƒ ### Frontend - **React 18** - UI 라이브러리 - **TypeScript** - νƒ€μž… μ•ˆμ •μ„± - **Vite** - λΉŒλ“œ 도ꡬ - **React Router** - λΌμš°νŒ… ### Styling - **Tailwind CSS** - μœ ν‹Έλ¦¬ν‹° CSS ν”„λ ˆμž„μ›Œν¬ - **shadcn/ui** - UI μ»΄ν¬λ„ŒνŠΈ 라이브러리 - **Framer Motion** - μ• λ‹ˆλ©”μ΄μ…˜ ### Libraries - **crypto-js** - AES256 μ•”ν˜Έν™” - **sonner** - Toast μ•Œλ¦Ό - **Lucide React** - μ•„μ΄μ½˜ ## πŸ“¦ μ„€μΉ˜ 및 μ‹€ν–‰ ### 1. μ €μž₯μ†Œ 클둠 ```bash git clone https://github.com/yourusername/MyListBridge.git cd MyListBridge ``` ### 2. μ˜μ‘΄μ„± μ„€μΉ˜ ```bash npm install ``` ### 3. ν™˜κ²½ λ³€μˆ˜ μ„€μ • `.env.example` νŒŒμΌμ„ `.env`둜 λ³΅μ‚¬ν•˜κ³  ν•„μš”ν•œ 값을 μ„€μ •ν•˜μ„Έμš”: ```bash cp .env.example .env ``` `.env` 파일 λ‚΄μš©: ```env # API Base URL VITE_API_BASE_URL=http://localhost:9099/api # Spotify OAuth VITE_SPOTIFY_CLIENT_ID=your_spotify_client_id_here # VITE_SPOTIFY_REDIRECT_URI=http://127.0.0.1:3001/callback/spotify ``` ### 4. Spotify μ•± μ„€μ • 1. [Spotify Developer Dashboard](https://developer.spotify.com/dashboard/applications)μ—μ„œ μ•± 생성 2. Client ID λ³΅μ‚¬ν•˜μ—¬ `.env`에 μ„€μ • 3. **Redirect URI** μ„€μ •: - `http://127.0.0.1:3001/callback/spotify` μΆ”κ°€ - ⚠️ **μ€‘μš”**: SpotifyλŠ” `localhost`λ₯Ό μ§€μ›ν•˜μ§€ μ•ŠμœΌλ―€λ‘œ λ°˜λ“œμ‹œ `127.0.0.1`을 μ‚¬μš©ν•΄μ•Ό ν•©λ‹ˆλ‹€ ### 5. 개발 μ„œλ²„ μ‹€ν–‰ ```bash npm run dev ``` λΈŒλΌμš°μ €μ—μ„œ λ‹€μŒ μ£Όμ†Œλ‘œ 접속: - `http://localhost:3001` (ꢌμž₯) - `http://127.0.0.1:3001` ### 6. ν”„λ‘œλ•μ…˜ λΉŒλ“œ ```bash npm run build ``` λΉŒλ“œλœ νŒŒμΌμ€ `build/` 디렉토리에 μƒμ„±λ©λ‹ˆλ‹€. ## πŸ“ ν”„λ‘œμ νŠΈ ꡬ쑰 ``` MyListBridge/ β”œβ”€β”€ src/ β”‚ β”œβ”€β”€ components/ # React μ»΄ν¬λ„ŒνŠΈ β”‚ β”‚ β”œβ”€β”€ common/ # 곡톡 μ»΄ν¬λ„ŒνŠΈ β”‚ β”‚ β”œβ”€β”€ features/ # κΈ°λŠ₯별 μ»΄ν¬λ„ŒνŠΈ β”‚ β”‚ β”‚ β”œβ”€β”€ playlist/ # ν”Œλ ˆμ΄λ¦¬μŠ€νŠΈ κ΄€λ ¨ β”‚ β”‚ β”‚ β”œβ”€β”€ service/ # μ„œλΉ„μŠ€ 선택 κ΄€λ ¨ β”‚ β”‚ β”‚ └── spotify/ # Spotify κ΄€λ ¨ β”‚ β”‚ └── ui/ # shadcn/ui μ»΄ν¬λ„ŒνŠΈ β”‚ β”œβ”€β”€ pages/ # νŽ˜μ΄μ§€ μ»΄ν¬λ„ŒνŠΈ β”‚ β”‚ β”œβ”€β”€ VibePage.tsx # VIBE ν”Œλ ˆμ΄λ¦¬μŠ€νŠΈ νŽ˜μ΄μ§€ β”‚ β”‚ └── SpotifyCallback.tsx # Spotify OAuth 콜백 β”‚ β”œβ”€β”€ services/ # API μ„œλΉ„μŠ€ β”‚ β”‚ β”œβ”€β”€ vibeService.ts # VIBE API β”‚ β”‚ └── spotifyService.ts # Spotify API β”‚ β”œβ”€β”€ utils/ # μœ ν‹Έλ¦¬ν‹° β”‚ β”‚ β”œβ”€β”€ api.ts # API ν΄λΌμ΄μ–ΈνŠΈ β”‚ β”‚ β”œβ”€β”€ crypto.ts # AES256 μ•”ν˜Έν™” β”‚ β”‚ └── alert.ts # μ•Œλ¦Ό μœ ν‹Έλ¦¬ν‹° β”‚ β”œβ”€β”€ types/ # TypeScript νƒ€μž… μ •μ˜ β”‚ β”‚ └── api.ts β”‚ β”œβ”€β”€ constants/ # μƒμˆ˜ β”‚ β”‚ └── streamingServices.ts β”‚ β”œβ”€β”€ App.tsx # 메인 μ•± μ»΄ν¬λ„ŒνŠΈ β”‚ └── main.tsx # μ•± μ§„μž…μ  β”œβ”€β”€ .env.example # ν™˜κ²½ λ³€μˆ˜ μ˜ˆμ‹œ β”œβ”€β”€ package.json β”œβ”€β”€ vite.config.ts # Vite μ„€μ • β”œβ”€β”€ tsconfig.json # TypeScript μ„€μ • └── tailwind.config.js # Tailwind CSS μ„€μ • ``` ## πŸ” λ³΄μ•ˆ μ„€μ • ### AES256 μ•”ν˜Έν™” VIBE 둜그인 μ‹œ 아이디와 λΉ„λ°€λ²ˆν˜Έκ°€ AES256으둜 μ•”ν˜Έν™”λ˜μ–΄ μ „μ†‘λ©λ‹ˆλ‹€. ```typescript // src/utils/crypto.ts const SECRET_KEY = 'MyListBridgeSecretKey1234567890'; ``` **⚠️ μ€‘μš”**: ν”„λ‘œλ•μ…˜ ν™˜κ²½μ—μ„œλŠ” ν™˜κ²½ λ³€μˆ˜λ‘œ κ΄€λ¦¬ν•˜μ„Έμš”! ### Spotify OAuth 2.0 (PKCE) - PKCE (Proof Key for Code Exchange) 방식 μ‚¬μš© - Code Verifier 및 Code Challenge μžλ™ 생성 - Refresh Token을 ν†΅ν•œ μžλ™ κ°±μ‹  ## πŸš€ μ‚¬μš© 방법 ### 1. VIBE ν”Œλ ˆμ΄λ¦¬μŠ€νŠΈ κ°€μ Έμ˜€κΈ° 1. 메인 νŽ˜μ΄μ§€μ—μ„œ **VIBE** μ„œλΉ„μŠ€ 선택 2. 두 κ°€μ§€ 방법 쀑 선택: - **둜그인**: VIBE κ³„μ •μœΌλ‘œ λ‘œκ·ΈμΈν•˜μ—¬ λͺ¨λ“  ν”Œλ ˆμ΄λ¦¬μŠ€νŠΈ κ°€μ Έμ˜€κΈ° - **URL μž…λ ₯**: νŠΉμ • ν”Œλ ˆμ΄λ¦¬μŠ€νŠΈ URL μž…λ ₯ ### 2. νŠΈλž™ 선택 1. ν”Œλ ˆμ΄λ¦¬μŠ€νŠΈλ₯Ό 펼쳐 νŠΈλž™ 확인 2. 이전할 νŠΈλž™ 선택 (κ°œλ³„ 선택 λ˜λŠ” ν”Œλ ˆμ΄λ¦¬μŠ€νŠΈ 전체 선택) 3. **λ‹€μŒ** λ²„νŠΌ 클릭 ### 3. Spotify둜 이전 1. **Spotify** μ„œλΉ„μŠ€ 선택 2. Spotify 둜그인 (OAuth νŒμ—…) 3. λŒ€μƒ ν”Œλ ˆμ΄λ¦¬μŠ€νŠΈ 선택: - **μƒˆ ν”Œλ ˆμ΄λ¦¬μŠ€νŠΈ 생성**: 이름과 μ„€λͺ… μž…λ ₯ - **κΈ°μ‘΄ ν”Œλ ˆμ΄λ¦¬μŠ€νŠΈ**: λͺ©λ‘μ—μ„œ 선택 4. 이전 μ™„λ£Œ ν›„ μžλ™μœΌλ‘œ 메인 νŽ˜μ΄μ§€λ‘œ 이동 ## 🎯 API λͺ…μ„Έ ### Backend API μ—”λ“œν¬μΈνŠΈ #### VIBE ```typescript // 둜그인 및 ν”Œλ ˆμ΄λ¦¬μŠ€νŠΈ λͺ©λ‘ 쑰회 POST /api/v2/vibe/playlists Body: { id: string (encrypted), password: string (encrypted) } // ν”Œλ ˆμ΄λ¦¬μŠ€νŠΈ νŠΈλž™ 쑰회 GET /api/v2/vibe/playlists/:playlistId/tracks Headers: { X-Session-Id: string } ``` #### Spotify ```typescript // ν”Œλ ˆμ΄λ¦¬μŠ€νŠΈ λͺ©λ‘ 쑰회 POST /api/v2/spotify/playlists Body: { access_token: string } // νŠΈλž™ μΆ”κ°€ POST /api/v2/spotify/playlists/tracks Body: { access_token: string, playlist_id?: string, playlist_name?: string, playlist_description?: string, is_public?: boolean, tracks: TrackInfo[] } ``` ## πŸ› 문제 ν•΄κ²° ### Spotify 둜그인 였λ₯˜: "INVALID_CLIENT: Invalid redirect URI" - Spotify Dashboard의 Redirect URIλ₯Ό `127.0.0.1`둜 μ„€μ •ν–ˆλŠ”μ§€ 확인 - `localhost` λŒ€μ‹  `127.0.0.1`을 μ‚¬μš©ν•΄μ•Ό ν•©λ‹ˆλ‹€ ### μ—°κ²° κ±°λΆ€ (ERR_CONNECTION_REFUSED) - 개발 μ„œλ²„κ°€ 포트 3001μ—μ„œ μ‹€ν–‰ 쀑인지 확인 - Spotify Dashboard의 Redirect URI ν¬νŠΈκ°€ μΌμΉ˜ν•˜λŠ”μ§€ 확인 ### Alertκ°€ ν‘œμ‹œλ˜μ§€ μ•ŠμŒ - `` μ»΄ν¬λ„ŒνŠΈκ°€ `main.tsx`에 μΆ”κ°€λ˜μ–΄ μžˆλŠ”μ§€ 확인 ### 토큰 만료 였λ₯˜ - Access Token은 1μ‹œκ°„ ν›„ μžλ™μœΌλ‘œ κ°±μ‹ λ©λ‹ˆλ‹€ - Refresh Token이 없을 경우 λ‹€μ‹œ λ‘œκ·ΈμΈν•˜μ„Έμš” ## πŸ“ 개발 κ°€μ΄λ“œ ### μ½”λ“œ μž‘μ„± κ·œμΉ™ - βœ… **νƒ€μž… μ•ˆμ •μ„±**: TypeScript 엄격 λͺ¨λ“œ μ€€μˆ˜ - βœ… **μ‹€μ œ κ΅¬ν˜„**: Mock 데이터 μ‚¬μš© κΈˆμ§€ - βœ… **μ»΄ν¬λ„ŒνŠΈ 넀이밍**: PascalCase μ‚¬μš© - βœ… **파일 ꡬ쑰**: `.types.ts`, `.constants.ts`, `.utils.ts` 뢄리 ### κΈˆμ§€ 사항 - ❌ `any` νƒ€μž… μ‚¬μš© - ❌ 직접적인 DOM μ‘°μž‘ - ❌ ν”„λ‘œλ•μ…˜ μ½”λ“œμ— `console.log` 남기기 - ❌ Mock λ°μ΄ν„°λ‚˜ κ°€μ§œ κ΅¬ν˜„ ## 🀝 κΈ°μ—¬ν•˜κΈ° 1. Fork the Project 2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`) 3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`) 4. Push to the Branch (`git push origin feature/AmazingFeature`) 5. Open a Pull Request ## πŸ“„ λΌμ΄μ„ μŠ€ 이 ν”„λ‘œμ νŠΈλŠ” MIT λΌμ΄μ„ μŠ€ ν•˜μ— λ°°ν¬λ©λ‹ˆλ‹€. ## πŸ™ κ°μ‚¬μ˜ 말 - [shadcn/ui](https://ui.shadcn.com/) - μ•„λ¦„λ‹€μš΄ UI μ»΄ν¬λ„ŒνŠΈ - [Lucide Icons](https://lucide.dev/) - μ•„μ΄μ½˜ μ„ΈνŠΈ - [Spotify Web API](https://developer.spotify.com/documentation/web-api) - Spotify 톡합 ## πŸ“ž 문의 ν”„λ‘œμ νŠΈμ— λŒ€ν•œ μ§ˆλ¬Έμ΄λ‚˜ μ œμ•ˆμ‚¬ν•­μ΄ μžˆμœΌμ‹œλ©΄ 이슈λ₯Ό λ“±λ‘ν•΄μ£Όμ„Έμš”. --- Made with ❀️ by MyListBridge Team