8.3 KiB
Music YouTube Tab Frontend — Design Spec
Date: 2026-05-01
Repo: web-page (React + Vite SPA at /Users/jaeohpark/development/web-page/)
1. Goal
MusicStudio 페이지에 🎯 YouTube 탭을 추가한다. 기존 4개 탭(Create / Lyrics / Library / Remix) 옆에 하나 더 붙이며, 탭 내부에 3개의 서브탭을 둔다.
- 🎬 영상 제작 — 트랙 선택 → 포맷·국가 설정 → 렌더링 → 내보내기
- 💰 수익 추적 — 수동 수익 기록 입력 + 장르별 RPM 차트 + 기록 테이블
- 📊 시장 트렌드 — agent-office가 매일 수집한 YouTube/Trends/Billboard 데이터 표시 + AI 프롬프트 추천
2. 영향 파일
수정
| 파일 | 변경 내용 |
|---|---|
src/pages/music/MusicStudio.jsx |
tab 상태에 'youtube' 추가, 탭 버튼 추가, YoutubeTab 렌더링 |
src/api.js |
비디오 프로젝트 / 수익 / 시장 트렌드 API 함수 추가 |
신규 생성
| 파일 | 역할 |
|---|---|
src/pages/music/components/YoutubeTab.jsx |
YouTube 탭 루트 컴포넌트 (서브탭 상태 관리) |
src/pages/music/components/VideoProjectsTab.jsx |
🎬 영상 제작 서브탭 |
src/pages/music/components/RevenueTab.jsx |
💰 수익 추적 서브탭 |
src/pages/music/components/TrendsTab.jsx |
📊 시장 트렌드 서브탭 |
3. 컴포넌트 계층
MusicStudio
└── [tab === 'youtube']
└── YoutubeTab
├── subtab 상태: 'video' | 'revenue' | 'trends'
├── [subtab === 'video'] → VideoProjectsTab
├── [subtab === 'revenue'] → RevenueTab
└── [subtab === 'trends'] → TrendsTab
YoutubeTab props:
library: Array— 라이브러리 트랙 목록 (MusicStudio에서 내려줌, 트랙 선택 드롭다운용)initialTrackId?: string— Library 탭의 "영상 만들기" 버튼 클릭 시 pre-select용
4. 서브탭 상세
4-1. VideoProjectsTab (subtab === 'video')
① 새 영상 만들기 패널
- 트랙 선택 드롭다운 (
libraryprop에서 목록,title표시) - 형식 선택:
비주얼라이저|슬라이드쇼(toggle) - 타겟 국가 칩: BR / US / ID / MX / KR (복수 선택 가능)
- "프로젝트 생성" 버튼 →
POST /api/music/video-project
② 영상 프로젝트 목록
GET /api/music/video-projects폴링 (렌더링 중인 프로젝트 있을 때 5초 간격)- 상태별 표시:
pending— "대기" 배지 + "▶ 렌더" 버튼 →POST /api/music/video-project/:id/renderrendering— "처리중" 배지 + 진행 바 (시작 시각 기준 경과 시간 표시)done— "✓ 완료" 배지 + "↓ 내보내기" 버튼failed— "실패" 배지 (빨간색)
③ 내보내기 패키지 (done 상태 프로젝트 선택 시)
GET /api/music/video-project/:id/export→{mp4_url, thumbnail_url, metadata}- mp4 다운로드 링크, thumbnail 다운로드 링크, metadata.json 미리보기 (title / tags / target)
상태 관리:
const [projects, setProjects] = useState([])
const [selectedTrackId, setSelectedTrackId] = useState(initialTrackId ?? '')
const [format, setFormat] = useState('visualizer')
const [countries, setCountries] = useState(['BR'])
const [creating, setCreating] = useState(false)
const [exportData, setExportData] = useState(null) // 선택된 done 프로젝트의 export
4-2. RevenueTab (subtab === 'revenue')
대시보드 카드 (3개)
GET /api/music/revenue/dashboard→{total_revenue_usd, total_views, avg_rpm}- 총 수익 / 총 조회수 / 가중평균 RPM
장르별 RPM 바 차트
GET /api/music/revenue→ 레코드 목록에서 장르별로 RPM 집계- 바 차트 (CSS 기반, 라이브러리 없음) — genre / rpm / color 매핑
수익 기록 추가 폼
- 필드:
yt_video_id,record_month(YYYY-MM),revenue_usd,views,country - "저장" →
POST /api/music/revenue - 성공 시 목록 + 대시보드 리프레시
수익 기록 테이블
GET /api/music/revenue— 영상 제목 / 월 / 수익 / 조회수 / RPM- 행 클릭 → 수정 폼 인라인 펼침
- 삭제 버튼 →
DELETE /api/music/revenue/:id
장르 추론: yt_video_id는 자유 입력이고 장르 컬럼이 DB에 없으므로, genre 필드를 수익 기록 폼에 optional 셀렉트로 추가한다. DB 스키마에 이미 없으면 프론트에서만 관리하지 않고, API 명세 확인 후 처리.
참고:
revenue_records테이블에genre컬럼이 없다. 차트는yt_video_id별 집계만 가능. 장르별 RPM 차트는 "영상별 RPM 비교"로 레이블을 바꿔서 구현한다.
상태 관리:
const [dashboard, setDashboard] = useState(null)
const [records, setRecords] = useState([])
const [form, setForm] = useState({ yt_video_id:'', record_month:'', revenue_usd:'', views:'', country:'BR' })
const [editingId, setEditingId] = useState(null)
4-3. TrendsTab (subtab === 'trends')
수집 상태 바
GET /api/music/market/report/latest→{report_date, created_at, top_genres, recommended_styles}- 마지막 수집 일시 + 트렌드 수 표시
- "↻ 수동 수집" 버튼 →
POST /api/agent-office/youtube/research(body:{})
오늘의 인기 장르 Top 5
top_genres배열에서 상위 5개 렌더링- 각 항목: 장르명 / 대상 국가 플래그 / 점수 바
AI 추천 Suno 프롬프트
GET /api/music/market/suggest→[{genre, suno_prompt, target_countries, reason}]- 카드 형태, 프롬프트 클릭 시 클립보드 복사
트렌드 리포트 이력
GET /api/music/market/report→ 날짜 목록- 날짜 클릭 → 해당 날짜 리포트 상세 표시 (top_genres + recommended_styles)
상태 관리:
const [latestReport, setLatestReport] = useState(null)
const [reports, setReports] = useState([])
const [suggestions, setSuggestions] = useState([])
const [selectedReport, setSelectedReport] = useState(null)
const [researching, setResearching] = useState(false)
5. API 추가 목록 (src/api.js)
// 기존 api.js 헬퍼: apiGet / apiPost / apiPut / apiDelete (plain fetch 래퍼)
// Video Projects
export const createVideoProject = (data) => apiPost('/api/music/video-project', data)
export const getVideoProjects = () => apiGet('/api/music/video-projects')
export const renderVideoProject = (id) => apiPost(`/api/music/video-project/${id}/render`)
export const exportVideoProject = (id) => apiGet(`/api/music/video-project/${id}/export`)
export const deleteVideoProject = (id) => apiDelete(`/api/music/video-project/${id}`)
// Revenue
export const getRevenueDashboard = () => apiGet('/api/music/revenue/dashboard')
export const getRevenueRecords = () => apiGet('/api/music/revenue')
export const addRevenueRecord = (data) => apiPost('/api/music/revenue', data)
export const updateRevenueRecord = (id, data) => apiPut(`/api/music/revenue/${id}`, data)
export const deleteRevenueRecord = (id) => apiDelete(`/api/music/revenue/${id}`)
// Market Trends
export const getLatestTrendReport = () => apiGet('/api/music/market/report/latest')
export const getTrendReports = () => apiGet('/api/music/market/report')
export const getMarketSuggestions = () => apiGet('/api/music/market/suggest')
export const triggerYoutubeResearch = () => apiPost('/api/agent-office/youtube/research', {})
6. Library 탭 연동
MusicStudio.jsx의 LibraryCard 컴포넌트에 "🎬 영상 만들기" 버튼 추가:
<button onClick={() => {
setTab('youtube')
setInitialTrackId(track.id)
}}>🎬 영상 만들기</button>
initialTrackId 상태를 MusicStudio 루트에 두고 YoutubeTab에 prop으로 내려준다. VideoProjectsTab이 마운트되면 해당 트랙을 드롭다운에 pre-select.
7. 스타일 가이드
기존 MusicStudio.css의 다크 테마 변수 재사용:
- 배경:
#111827/#0d1117/#1f2937 - 강조색:
#22c55e(초록, 완료·생성),#f59e0b(노랑, 처리중),#3b82f6(파랑, 수익),#a855f7(보라, 트렌드) - 새 CSS 클래스는
MusicStudio.css에 추가 (별도 파일 없음)
8. 범위 외 (Out of scope)
- YouTube Analytics OAuth 자동 동기화 (나중에 확장)
- 영상 업로드 자동화 (YouTube Data API write scope)
- 차트 라이브러리 도입 (CSS 바로 구현)