h-lab/docs/superpowers/specs/2026-05-30-dashboard-fullset-design.md

81 lines
4.7 KiB
Markdown

# 대시보드 풀세트 강화 — 설계
작성일: 2026-05-30
상태: 승인됨 (구현 대기)
## 목적
홈 대시보드에서 파이프라인 전체(수집→큐레이션→재가공→발행)를 한눈에 본다.
현재 빠진 **완료(DONE)·발행(publish) 현황·카테고리 분포**를 채우고 단계별 흐름을 시각화한다.
## 제약 / 비범위
- **시계열 추이 없음**: `ChannelVideo`에 수집 시각 필드가 없어(있는 건 영상 업로드일 `publishedAt`) "날짜별 수집량" 차트는 만들지 않는다. "현재 스냅샷" 중심.
- AI/외부 호출 없음.
- 차트 라이브러리 추가 없음 — 막대는 CSS(div 너비 %)로 그린다. (채널 성장 차트가 쓰는 Chart.js는 CDN으로 이미 있으나 대시보드엔 도입 안 함, YAGNI.)
## 현재 상태
- `dashboard.html`: KPI 카드 3개(수집 총계/TARGET/NEW) + 떡상 후보 TOP5 + 수집 출처. `/api/v1/channel-videos/stats`·`/outperformers` 를 각각 fetch.
- `pipelineStats()`(curation): `total`, `byStatus`(NEW/REVIEWING/TARGET/DONE/EXCLUDED), `bySource`(CHANNEL/SEARCH) 반환.
- 발행/카테고리 집계는 대시보드에 없음.
## 화면 구성 (dashboard.html 재작성)
1. **KPI 카드 5개**: 수집 총계 · 미검토(NEW) · 작업대상(TARGET) · **완료(DONE)** · **발행완료(PUBLISHED)**. (뒤 2개 신규)
2. **파이프라인 깔때기**: `수집 → 검토중 → 작업대상 → 완료 → 발행완료` 가로 막대(각 단계 너비 = 총계 대비 %). 제외(EXCLUDED)는 깔때기 밖 작은 뱃지로 별도 표기.
3. **2단**: 떡상 후보 TOP5(기존 유지) | **발행 현황**(DRAFT/READY/PUBLISHED 카운트 막대 + 최근 5건 목록).
4. **2단**: **카테고리 분포**(카테고리 색상 막대 + 건수 + 총계 대비 %, 미분류 포함) | **수집 출처 & 포맷**(채널/검색 + Shorts/롱폼 비율).
전체는 **단일 호출** `GET /api/dashboard/summary` 로 받아 렌더(현재의 다중 fetch 제거).
## 백엔드
### 단위와 책임
1. **`ChannelVideoRepository`** (수정) — 카운트 2개 추가:
- `long countByIsShortsTrue();`
- `long countByCategoryIdIsNull();`
2. **`PublishPackageRepository`** (수정) — `long countByStatus(String status);`
3. **`ChannelVideoCurationService.pipelineStats()`** (수정) — 기존 반환에 `shorts`(Shorts 수), `longForm`(total - shorts) 키 추가. (기존 키 유지 → 보드 등 하위호환)
4. **`CategoryService.distribution()`** (신규) — `Map`: `categories`=[{id,name,color,count}], `uncategorized`=미분류 수. (이미 `categoryRepository` + `channelVideoRepository` 보유)
5. **`PublishService.dashboardSummary()`** (신규) — `Map`: `byStatus`={DRAFT,READY,PUBLISHED}, `recent`=최신 5건(`list(null)` 앞 5개).
6. **`DashboardService.summary()`** (신규, `service` 패키지) — 위 서비스들을 조합해 하나의 `Map` 반환:
```
{ pipeline: pipelineStats(), // total, byStatus, bySource, shorts, longForm
categories: categoryService.distribution(),
publish: publishService.dashboardSummary(),
outperformers: curationService.findOutperformers(5, BigDecimal.ONE) }
```
의존: `ChannelVideoCurationService`, `CategoryService`, `PublishService` (서비스만 조합, 리포지토리 직접 접근 없음).
7. **`DashboardApiController`** (신규, `web` 패키지) — `GET /api/dashboard/summary``ApiResponse<Map<String,Object>>`.
## 데이터 흐름
```
dashboard.html (진입)
→ GET /api/dashboard/summary
→ DashboardService.summary()
├ curationService.pipelineStats() (+shorts/longForm)
├ categoryService.distribution()
├ publishService.dashboardSummary()
└ curationService.findOutperformers(5, 1)
→ KPI/깔때기/떡상/발행/카테고리/출처 렌더
```
## 에러 / 빈 상태
- summary 호출 실패: 각 섹션에 "불러오기 실패" 표시(현재 dashboard.html 의 try/catch 패턴 유지, 단 단일 호출).
- 데이터 0: 깔때기·분포는 0% 막대 + "아직 데이터가 없습니다" 류 안내. 떡상 0건은 기존 문구 유지.
- 백필 안 된 옛 영상으로 `shorts`/비율이 0이어도 화면은 정상(0 표기).
## 검증 방법
테스트 인프라가 없으므로(기존 관행) `compileJava` + `bootRun` 기동(빈/쿼리 에러 0건) + (UI 수동 확인은 사용자가 나중에 일괄).
## 영향 / 변경 파일 요약
신규: `DashboardService`, `DashboardApiController`, 스펙 문서.
수정: `ChannelVideoRepository`(count 2), `PublishPackageRepository`(count 1), `ChannelVideoCurationService`(pipelineStats 확장), `CategoryService`(distribution 추가), `PublishService`(dashboardSummary 추가), `dashboard.html`(재작성).
기존 페이지/엔드포인트(보드·수집함·발굴 등)는 영향 없음.