Files
music_bot_v2/page/src/app/page.tsx
claude-bot b670a61192 page 전체 코드 품질/보안 개선 및 봇 RPC 검증 정합
[보안/인증]
- 모든 player/queue API 라우트에 세션 가드 추가 (이전: /api/servers 만 보호)
- NextAuth 환경변수 부팅 시점 검증, NEXTAUTH_SECRET 명시
- next.config.ts CSP/보안 헤더 추가, 잘못된 allowedDevOrigins 제거
- Redis 호스트 하드코딩 IP 제거(필수 env 로 강제)

[안정성]
- 봇 RPC 패턴(@/lib/api) 공용화: crypto.randomUUID requestId, JSON.parse 안전, EXPIRE 자동, 폴링 백오프
- SSE(@/lib/sse) 공용화: subscriber error 처리, JSON.parse 안전, 30초 keep-alive, abort/에러 정리
- pause API 양 끝(boolean) 정상화: 프론트 String() 캐스트 + 백엔드 .trim().toLowerCase() 비교 제거
- 봇 RedisClient: isPaused/index/seek/volume falsy 거부 → typeof 검사로 교체(0/false 정상 허용)

[타입/품질]
- next-auth 모듈 보강 → session.user.id, session.accessToken 타입 안전
- DiscordServer/Track/SearchTrack 공용 타입 도입, 컴포넌트 any 제거
- BigInt permissions 안전 검증(타입 가드)
- Logger: NODE_ENV 게이트, error → stderr, ISO 기반 안전 timestamp
- tsconfig target → ES2020 (BigInt 리터럴)

[취약점]
- next 16.2.2 → 16.2.4 (DoS/postcss XSS 패치)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-28 14:56:55 +09:00

67 lines
2.1 KiB
TypeScript

"use client";
import { useState } from "react";
import TopNav from "@/components/layout/TopNav";
import LeftSidebar from "@/components/layout/LeftSidebar";
import MainContent from "@/components/player/MainContent";
import QueueSidebar from "@/components/player/QueueSidebar";
import PlayerBar from "@/components/player/PlayerBar";
import type { DiscordServer } from "@/types/music";
// 화면 모드 타입 정의
export type ViewMode = "SERVER_LIST" | "SERVER_DETAIL" | "SEARCH_RESULT";
export default function MusicPlayerLayout() {
const [viewMode, setViewMode] = useState<ViewMode>("SERVER_LIST");
const [selectedServer, setSelectedServer] = useState<DiscordServer | null>(null);
const [searchQuery, setSearchQuery] = useState("");
// 홈 버튼 클릭 시: 서버 목록(또는 상세)으로 복귀
const handleHome = () => {
if (selectedServer) {
setViewMode("SERVER_DETAIL");
} else {
setViewMode("SERVER_LIST");
setSelectedServer(null);
setSearchQuery("");
}
};
// 검색 실행 시
const handleSearch = (query: string) => {
setSearchQuery(query);
setViewMode("SEARCH_RESULT");
};
// 서버 선택 시
const handleSelectServer = (server: DiscordServer) => {
setSelectedServer(server);
setViewMode("SERVER_DETAIL");
};
return (
<div className="flex flex-col h-screen bg-neutral-900 text-white overflow-hidden font-sans">
<TopNav
onSearch={handleSearch}
onHome={handleHome}
selectedServer={selectedServer} // 🌟 이 줄을 추가해서 선택된 서버 정보를 넘깁니다.
/>
<div className="flex flex-1 overflow-hidden">
<LeftSidebar />
<MainContent
viewMode={viewMode}
setViewMode={setViewMode}
selectedServer={selectedServer}
setSelectedServer={setSelectedServer}
searchQuery={searchQuery}
setSearchQuery={setSearchQuery}
onSelectServer={handleSelectServer}
/>
<QueueSidebar selectedServer={selectedServer} />
</div>
<PlayerBar selectedServer={selectedServer} />
</div>
);
}