diff --git a/README.md b/README.md index d426a00..f774675 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,259 @@ +# 🎡 MyListBridge - # Streaming Service Selector +μŒμ•… 슀트리밍 μ„œλΉ„μŠ€ κ°„ ν”Œλ ˆμ΄λ¦¬μŠ€νŠΈλ₯Ό μ†μ‰½κ²Œ 이전할 수 μžˆλŠ” μ›Ή μ• ν”Œλ¦¬μΌ€μ΄μ…˜μž…λ‹ˆλ‹€. - This is a code bundle for Streaming Service Selector. The original project is available at https://www.figma.com/design/vhBIkRImRpWwzCKsEmGqeB/Streaming-Service-Selector. +## ✨ μ£Όμš” κΈ°λŠ₯ - ## Running the code +### VIBE β†’ Spotify ν”Œλ ˆμ΄λ¦¬μŠ€νŠΈ 이전 +- πŸ” VIBE λ‘œκ·ΈμΈμ„ ν†΅ν•œ ν”Œλ ˆμ΄λ¦¬μŠ€νŠΈ κ°€μ Έμ˜€κΈ° +- πŸ”— VIBE ν”Œλ ˆμ΄λ¦¬μŠ€νŠΈ URL둜 직접 κ°€μ Έμ˜€κΈ° +- 🎯 νŠΈλž™ λ‹¨μœ„ 선택 및 이전 +- πŸ“ Spotify μ‹ κ·œ ν”Œλ ˆμ΄λ¦¬μŠ€νŠΈ 생성 λ˜λŠ” κΈ°μ‘΄ ν”Œλ ˆμ΄λ¦¬μŠ€νŠΈμ— μΆ”κ°€ +- πŸ”„ μžλ™ 토큰 κ°±μ‹ μœΌλ‘œ λŠκΉ€ μ—†λŠ” μ‚¬μš©μž κ²½ν—˜ - Run `npm i` to install the dependencies. +### λ³΄μ•ˆ +- πŸ”’ AES256 μ•”ν˜Έν™”λ₯Ό ν†΅ν•œ μ•ˆμ „ν•œ 둜그인 정보 전솑 +- 🎫 OAuth 2.0 PKCE λ°©μ‹μ˜ Spotify 인증 +- ⏱️ Access Token μžλ™ κ°±μ‹  (만료 5λΆ„ μ „) - Run `npm run dev` to start the development server. - \ No newline at end of file +### μ‚¬μš©μž κ²½ν—˜ +- 🎨 λͺ¨λ˜ν•œ 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