docs: add discovery page design spec

This commit is contained in:
hehih 2026-05-30 21:44:13 +09:00
parent 487dfc6d0f
commit 50afa4ae51
2 changed files with 107 additions and 1 deletions

View File

@ -6,7 +6,11 @@
"Bash(git rm *)",
"Bash(git add *)",
"Bash(git -c user.name=hehih -c user.email=hehihoho86@gmail.com commit -q -m 'Retire Opal/YtVideo pipeline; ChannelVideo is the single video master *)",
"Bash(git -c user.name=hehih -c user.email=hehihoho86@gmail.com commit -q -m 'docs: update CLAUDE.md for ChannelVideo single-master architecture *)"
"Bash(git -c user.name=hehih -c user.email=hehihoho86@gmail.com commit -q -m 'docs: update CLAUDE.md for ChannelVideo single-master architecture *)",
"Bash(export JAVA_HOME=\"D:/Development/app/JDK/jdk-21.0.5\")",
"Bash(./gradlew.bat bootRun --console=plain)",
"Bash(echo \"bootRun started in background, PID $!\")",
"Bash(git -c user.name=\"hehih\" -c user.email=\"hehihoho86@gmail.com\" commit -q -m \"docs: add discovery page design spec\")"
]
}
}

View File

@ -0,0 +1,102 @@
# 발굴(Discovery) 전용 페이지 — 설계
작성일: 2026-05-30
상태: 승인됨 (구현 대기)
## 목적
수집된 영상(`ChannelVideo`) 중 "재가공할 만한 떡상 후보"를 빠르게 골라내는 일일 작업 화면을 제공한다.
파이프라인 "수집→**분류/발굴**→재가공→유통"에서 발굴 단계를 전용 화면으로 끌어올린다.
**제약: 비용 0** — 새로운 외부 API 호출이나 신규 수집 없이, 이미 보유한 파생 지표(`viewsPerHour`, `viewsPerSubRatio`, `viewCount`, `publishedAt`)만으로 랭킹/필터한다.
## 배경 / 현재 상태
- 떡상 발굴은 현재 `GET /api/v1/channel-videos/outperformers` 하나뿐 — `viewsPerSubRatio >= minRatio`인 Shorts를 비율순으로만 반환하며, 대시보드 TOP 리스트로만 노출된다. **전용 작업 화면이 없다.**
- 큐레이션 액션(북마크/상태변경/메모/재가공 이동)은 `ChannelVideoCurationController`(`/api/v1/channel-videos/...`)에 이미 구현되어 있다 — 재사용한다.
- UI 패턴은 `collection.html`(필터 바 + 테이블 + 행별 인라인 액션)을 따른다.
## 비범위 (YAGNI)
- 복합 "발굴 점수"(가중치 합산) — 도입하지 않음. 기존 단일 지표 정렬로 충분.
- AI/외부 호출 — 없음.
- 새 액션 엔드포인트 — 없음(기존 큐레이션 API 재사용).
## 아키텍처 / 컴포넌트
신규로 추가되는 단위는 다음 5개이며 각각 책임이 단일하다.
### 1. `ChannelVideoRepository.discover(...)` (신규 쿼리)
수집 영상을 발굴 조건으로 필터링하는 조회 쿼리.
입력(모두 nullable, null이면 해당 필터 미적용):
- `publishedAfter: LocalDateTime` — 이 시각 이후 업로드분만 (최근성 필터)
- `minRatio: BigDecimal``viewsPerSubRatio >= minRatio`
- `shortsOnly: boolean` — true면 `isShorts = true`
- `source: String``CHANNEL` | `SEARCH`
- `unprocessedOnly: boolean` — true면 상태가 `NEW` 또는 `REVIEWING`인 것만
- `sort: Sort` — 정렬 기준
규칙: **`interestStatus = 'EXCLUDED'`는 항상 제외**한다.
### 2. `ChannelVideoCurationService.discover(...)` (신규 서비스 메서드)
파라미터 검증·기본값 적용 후 리포지토리 호출.
- `periodDays`(Integer) → `publishedAfter = now - periodDays일` (null/0이면 전체)
- `sortBy` → 기존 `ALLOWED_SORT` 화이트리스트(`viewsPerHour|viewsPerSubRatio|viewCount|publishedAt|durationSec`) 재사용, 기본 `viewsPerSubRatio` 내림차순
- `minRatio` 그대로 전달(null이면 미적용)
- 결과 개수는 `limit`(기본 100, 최대 200)으로 캡
### 3. `GET /api/v1/channel-videos/discover` (신규 엔드포인트)
`ChannelVideoCurationController`에 추가.
쿼리 파라미터: `periodDays`, `minRatio`, `shortsOnly`(기본 false), `source`, `unprocessedOnly`(기본 false), `sortBy`, `limit`.
응답: `ApiResponse<List<ChannelVideo>>`.
### 4. `discover.html` + `/discover` 라우트
- `WebController``GET /discover` 추가 (`currentPage = "discover"`, 뷰 `discover`).
- 템플릿은 `collection.html` 구조를 따른다(공유 `layout/base`).
- **필터 바**: 기간(전체/7/14/30일), 최소 배율(전체/≥2x/≥3x/≥5x), Shorts만 토글, 출처(전체/CHANNEL/SEARCH), 미처리만 토글, 정렬 드롭다운(떡상속도/배율/조회수/최신).
- **결과 테이블**: 썸네일 · 제목 · 채널 · 조회수 · 구독자 · 배율(viewsPerSubRatio) · 떡상속도(viewsPerHour) · 업로드일 · 상태뱃지.
- **행별 액션**(기존 API 재사용): 북마크 토글(`POST /{id}/bookmark`), TARGET 지정(`POST /{id}/status`), 🪄 재가공(`/rework/{id}` 이동), YouTube 열기(외부 링크).
### 5. 사이드바 링크
`layout/sidebar.html`에 "발굴" 항목 추가(수집함과 보드 사이 권장). 아이콘 후보: lucide `radar` 또는 `telescope`. `currentPage == 'discover'`일 때 active.
## 데이터 흐름
```
discover.html (필터 변경/진입)
→ GET /api/v1/channel-videos/discover?필터
→ CurationService.discover() → Repository.discover()
→ 행 렌더링
→ 행별 액션 → 기존 POST 엔드포인트(bookmark/status) → 낙관적 UI 갱신
```
## 기본값 (페이지 진입 시)
- 기간: 전체
- 최소 배율: 전체(미적용)
- Shorts만: off
- 출처: 전체
- 미처리만: off (단, EXCLUDED는 항상 숨김)
- 정렬: 구독자 대비 배율(viewsPerSubRatio) 내림차순
→ 진입 즉시 "구독자 적은데 조회수 터진" 영상이 상단에 온다.
## 에러 / 빈 상태
- 결과 0건: "조건에 맞는 발굴 후보가 없습니다" 안내 행.
- API 실패: 테이블에 에러 메시지(`ApiResponse.message`) 표시. (`collection.html` 방식과 동일)
- 백필 안 된 옛 데이터(`viewsPerSubRatio = null`)는 배율 정렬/필터에서 자연히 하단·제외됨 — 별도 처리 불필요(기존 백필 기능으로 보정 가능).
## 검증 방법
이 프로젝트는 테스트 인프라가 없고(`src/test` 부재) 원격 운영 DB에 붙으므로, 기존 관행대로 검증한다:
1. `gradlew.bat clean compileJava` 통과.
2. `gradlew.bat bootRun` 기동(빈 와이어링·엔티티 매핑 정상 확인).
3. Swagger(`/swagger-ui.html`)에서 `/discover` 응답 확인 + 브라우저에서 `/discover` 페이지 필터/정렬/액션 동작 수동 확인.
## 영향 / 변경 파일 요약
신규: `discover.html`, 스펙 문서.
수정: `ChannelVideoRepository`(메서드 1), `ChannelVideoCurationService`(메서드 1), `ChannelVideoCurationController`(엔드포인트 1), `WebController`(라우트 1), `layout/sidebar.html`(링크 1).
기존 액션 API·엔티티·다른 페이지는 변경 없음.