diff --git a/docs/superpowers/specs/2026-05-01-music-youtube-tab-frontend-design.md b/docs/superpowers/specs/2026-05-01-music-youtube-tab-frontend-design.md new file mode 100644 index 0000000..1547fd5 --- /dev/null +++ b/docs/superpowers/specs/2026-05-01-music-youtube-tab-frontend-design.md @@ -0,0 +1,208 @@ +# 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'`) + +**① 새 영상 만들기 패널** +- 트랙 선택 드롭다운 (`library` prop에서 목록, `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/render` + - `rendering` — "처리중" 배지 + 진행 바 (시작 시각 기준 경과 시간 표시) + - `done` — "✓ 완료" 배지 + "↓ 내보내기" 버튼 + - `failed` — "실패" 배지 (빨간색) + +**③ 내보내기 패키지 (done 상태 프로젝트 선택 시)** +- `GET /api/music/video-project/:id/export` → `{mp4_url, thumbnail_url, metadata}` +- mp4 다운로드 링크, thumbnail 다운로드 링크, metadata.json 미리보기 (title / tags / target) + +**상태 관리:** +```js +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 비교"로 레이블을 바꿔서 구현한다. + +**상태 관리:** +```js +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) + +**상태 관리:** +```js +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`) + +```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` 컴포넌트에 **"🎬 영상 만들기"** 버튼 추가: + +```jsx + +``` + +`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 바로 구현)