Files
music_bot_v2/page/README.md

94 lines
4.6 KiB
Markdown

# music_bot_v2 — 웹 대시보드(`page/`)
디스코드 음악봇(`../bot`)을 브라우저에서 제어하는 웹 대시보드. 디스코드 로그인 후 내가 속한 서버를 골라
검색·재생·대기열 관리·볼륨/탐색 등을 조작하고, 현재 재생 상태를 실시간으로 본다.
- **스택**: Next.js 16 (App Router) · React 19 · TypeScript · Tailwind CSS 4 · NextAuth 4(Discord OAuth) · ioredis
- **봇과의 통신**: 직접 호출이 아니라 **Redis Pub/Sub + Key**로 봇과 주고받는다(아래 3장).
- 리포 전체 개요는 [`../README.md`](../README.md), 봇 본체는 [`../bot/README.md`](../bot/README.md) 참고.
---
## 1. 빠른 시작 (개발)
```bash
cd page
npm install
# .env.local 작성 (2장 참고)
npm run dev # http://localhost:3000
```
빌드/구동: `npm run build` → `npm run start`. 린트: `npm run lint`.
> Redis(봇과 공유)와 디스코드 OAuth 앱이 있어야 실제 동작한다. Redis에 연결되지 않으면 부팅 시 에러를 던진다(`src/lib/Redis.ts`).
---
## 2. 환경변수 (`.env.local`)
| 변수 | 설명 |
|------|------|
| `REDIS_HOST` / `REDIS_PORT` | 봇과 공유하는 Redis. 봇 `.env`의 값과 동일해야 한다(미설정 시 부팅 에러). |
| `DISCORD_CLIENT_ID` / `DISCORD_CLIENT_SECRET` | 디스코드 OAuth 앱 자격증명(로그인·서버목록 scope). |
| `NEXTAUTH_SECRET` | NextAuth 세션 서명 키. |
| `NEXTAUTH_URL` | 배포 URL(예: `https://music.example.com`). 개발은 `http://localhost:3000`. |
- 로그인 scope는 `identify email guilds`(유저 정보 + 서버 목록). `src/app/api/auth/[...nextauth]/route.ts`.
- 디스코드 개발자 포털의 OAuth2 Redirect에 `<NEXTAUTH_URL>/api/auth/callback/discord`를 등록해야 한다.
---
## 3. 봇과의 통신 구조 (Redis)
대시보드는 봇을 직접 호출하지 않고 **Redis를 메시지 버스**로 쓴다. 봇 쪽 구현은 `../bot/src/classes/RedisClient.ts`.
### 3-1. 명령 (site → bot, 요청/응답 RPC) — `src/lib/api.ts`의 `botRpc`
```
site: PUBLISH "site-bot" {action, serverId, userId, requestId, …}
bot : 처리 후 SETEX "<action-key>:<requestId>" (예: player:play:<reqId>) 에 결과 저장
site: 그 키를 짧게 폴링(100ms→최대400ms 백오프, 기본 3초 타임아웃)해 결과 수신
```
- `requestId`는 CSPRNG(`randomUUID`). 결과 키는 읽은 즉시 삭제 + TTL 보험.
- action: `search`, `player_play`, `player_playlist`, `player_now`, `player_pause`, `player_skip`,
`player_seek`, `player_volume`, `queue_list`, `queue_set`, `queue_remove`.
### 3-2. 실시간 상태 (bot → site, SSE) — `src/lib/sse.ts`의 `botEventStream`
```
bot : PUBLISH "bot-site" {event:"player_update"|"queue_update", guildId}
site: "bot-site" 구독 → serverId 일치하는 것만 EventSource(SSE)로 브라우저에 전달(30초 keep-alive)
```
- 브라우저는 `/api/player/events?serverId=…`, `/api/queue/events?serverId=…`(SSE)를 구독해
상태 변경 알림을 받고 `now`/`queue/list`를 다시 당겨온다.
---
## 4. API 라우트 (`src/app/api`)
모든 라우트는 세션 가드(`requireSession`)를 거치고 `{ success, … }` 형태로 응답한다.
- **player**: `play`, `pause`, `skip`, `seek`, `volume`, `playlist`, `now`, `events`(SSE)
- **queue**: `list`, `set`, `remove`, `events`(SSE)
- **servers**: 로그인 유저의 디스코드 서버 목록(봇이 있는 서버로 필터링)
- **search**: 검색(봇의 `search` action → Spotify/YT Music/YT Video 결과)
- **auth**: `[...nextauth]`(Discord OAuth)
공용 헬퍼(`src/lib/api.ts`): `requireSession`, `botRpc`, `readJsonBody`, `requireString/Number/Boolean`, `errorResponse`.
---
## 5. UI 구성 (`src/`)
- `app/layout.tsx`, `app/page.tsx` — 루트 레이아웃/페이지. `components/Providers.tsx`(세션 등), `ToastProvider.tsx`.
- `components/layout/` — `TopNav`(상단/서버선택·로그인), `LeftSidebar`(탐색).
- `components/player/` — `PlayerBar`(재생바/볼륨/탐색), `MainContent`(검색·결과), `QueueSidebar`(대기열).
- `types/music.ts` — `DiscordServer`, `Track`/`TrackInfo`, `SearchTrack`, `SearchResults` 등 공용 도메인 타입.
- `next.config.ts` — 보안 헤더(CSP: self + discord/spotify/ytimg/google 이미지 CDN만 허용, `frame-ancestors 'none'` 등).
---
## 6. 배포 메모
- Next.js 16 standalone/`next start`로 구동. 봇과 같은 Redis(.7)에 접근 가능해야 한다.
- `NEXTAUTH_URL`/디스코드 Redirect URI를 실제 도메인으로 맞춘다.
- 이 디렉터리는 Next가 제공하는 에이전트 규칙 파일(`AGENTS.md`, `CLAUDE.md`)을 둔다 — 코드 수정 전 참고.