# PLAN.md — abcvideo 구현 계획 > 이 파일은 전체 구현 계획과 각 단계별 세부 태스크를 정의합니다. > 에이전트는 작업 시작 전 반드시 이 파일을 읽고, 자신이 담당할 단계를 확인합니다. --- ## 단계 1: 프로젝트 구조 세팅 ### 목표 모노레포 구조 생성, TypeScript/빌드 설정, 개발 환경 구축 ### 세부 태스크 - [ ] 루트 `package.json` (npm workspaces: client, server, shared) - [ ] `client/` — Vite + React 18 + TypeScript 초기화 - [ ] `server/` — TypeScript + ts-node/tsx 설정 - [ ] `shared/` — 공유 타입 패키지 설정 - [ ] Tailwind CSS 설치 및 설정 (client) - [ ] ESLint + Prettier 설정 (루트) - [ ] `tsconfig.json` — 루트/client/server/shared 각각 설정 (경로 별칭 포함) - [ ] `storage/` 디렉토리 구조 생성 + `.gitignore` 설정 - [ ] `server/.env.example` 작성 - [ ] 개발 서버 동시 실행 스크립트 (`concurrently` 또는 npm scripts) - [ ] 빈 앱 기동 확인 (client dev + server dev 동시 실행) ### 산출물 (완료 기준) - `npm install` 성공 - `npm run dev`로 client(5173) + server(3001) 동시 기동 - TypeScript 컴파일 에러 없음 - 빈 React 앱이 브라우저에 표시됨 ### 다음 단계 의존성 - 단계 2, 3 모두 이 단계 완료 후 시작 가능 --- ## 단계 2: 백엔드 서버 ### 목표 Express 서버 + Range Request 스트리밍 + FFmpeg spawn 래퍼 + tus 업로드 + HLS 변환 + SSE 진행률 ### 세부 태스크 #### 2-1. 서버 기본 골격 - [ ] Express 앱 생성 (`server/src/app.ts`) - [ ] CORS 미들웨어 설정 (개발: localhost:5173 허용) - [ ] 보안 미들웨어: Path traversal 방어 (`middleware/security.ts`) - [ ] 에러 핸들링 미들웨어 - [ ] 환경변수 로드 (dotenv + `server/.env`) - [ ] `storage/` 하위 디렉토리 자동 생성 로직 #### 2-2. Range Request 스트리밍 - [ ] `routes/stream.ts` — GET /api/stream/:videoId - [ ] `services/streaming.ts` — Range 파싱, createReadStream, 206 응답 - [ ] Accept-Ranges 헤더, Content-Range 헤더 정확한 구현 - [ ] highWaterMark 1MB, 청크 크기 10MB 제한 - [ ] 테스트: curl로 Range Request 동작 확인 #### 2-3. FFmpeg spawn 래퍼 - [ ] `services/ffmpeg.ts` — runFFmpeg(), runFFprobe() 함수 - [ ] FFmpeg 설치 확인 로직 (서버 시작 시) - [ ] stderr 진행률 파싱 (`time=HH:MM:SS.ms` 패턴) - [ ] 코덱 감지: FFprobe로 H.264 여부 확인 → `-c copy` vs 트랜스코딩 분기 - [ ] 프레임 추출: `-accurate_seek -ss {time} -i {file} -frames:v 1` #### 2-4. HLS 변환 - [ ] `routes/hls.ts` — POST /api/hls/:videoId/convert, GET 플레이리스트/세그먼트 - [ ] 변환 작업 관리 (Map 기반 인메모리 상태: idle/converting/done/error) - [ ] H.264 → `-c copy` (빠른 리먹스), 비-H.264 → 트랜스코딩 - [ ] 세그먼트 6초, 키프레임 2초 간격 - [ ] SSE 진행률 엔드포인트: GET /api/hls/:videoId/progress #### 2-5. tus 업로드 - [ ] `@tus/server` + `@tus/file-store` 설정 - [ ] `routes/upload.ts` — /api/upload 경로에 tus 서버 마운트 - [ ] 업로드 완료 훅: `onUploadFinish`에서 파일 이동 + FFprobe 메타데이터 추출 - [ ] 업로드 크기 제한: MAX_UPLOAD_SIZE (기본 20GB) - [ ] MIME 타입 + FFprobe 실제 코덱 검증 #### 2-6. 메타데이터 & 영상 관리 - [ ] `routes/meta.ts` — GET /api/meta/:videoId (FFprobe 기반) - [ ] GET /api/videos — 업로드된 영상 목록 - [ ] DELETE /api/videos/:videoId — 원본+HLS+프레임+썸네일+DB 일괄 삭제 #### 2-7. SQLite + 주석 API - [ ] `db/schema.sql` — annotations 테이블 스키마 - [ ] better-sqlite3 초기화 (`services/storage.ts`) - [ ] `routes/annotations.ts` — CRUD + 내보내기 (VTT, SRT, JSON, CSV) #### 2-8. 파일 정리 - [ ] 서버 시작 시 24시간 이상 된 임시 파일 정리 - [ ] 주기적 정리 (setInterval, 1시간마다) - [ ] 디스크 잔여 공간 체크 (check-disk-space, 10GB 미만 시 로그 경고) ### 산출물 (완료 기준) - 서버 기동 성공 (FFmpeg 감지 로그 출력) - curl로 Range Request 스트리밍 동작 확인 - curl로 영상 업로드 (tus) 성공 - HLS 변환 시작/진행률/완료 확인 - 주석 CRUD API 동작 확인 ### 다음 단계 의존성 - 단계 3 (기본 플레이어)은 최소 2-1, 2-2 완료 시 시작 가능 - 단계 4 (프레임 추출)은 2-3 완료 필요 - 단계 6 (텍스트 오버레이)은 2-7 완료 필요 --- ## 단계 3: 기본 플레이어 ### 목표 Video.js + 이중 경로 재생 (로컬 File API + 서버 Range Request/HLS) + 기본 UI ### 세부 태스크 #### 3-1. Video.js 통합 - [ ] Video.js 8.23.x + 타입 정의 설치 - [ ] `components/player/VideoPlayer.tsx` — ref + useEffect 패턴 - [ ] `hooks/useVideoPlayer.ts` — 초기화/제어/이벤트 추상화 - [ ] Video.js 옵션: fluid, responsive, playbackRates 설정 - [ ] 전체화면: 컨테이너 div 기준 fullscreen (오버레이 유지) #### 3-2. 서버 파일 재생 - [ ] 서버 영상 목록 조회 UI - [ ] Range Request URL로 즉시 재생 - [ ] HLS 변환 트리거 + SSE 진행률 표시 - [ ] HLS 준비 완료 시 hls.js로 소스 전환 #### 3-3. 로컬 파일 재생 - [ ] 파일 드래그앤드롭 / 파일 선택 UI - [ ] `URL.createObjectURL()` → Video.js src 설정 - [ ] 재생 종료/파일 변경 시 `URL.revokeObjectURL()` 호출 #### 3-4. hls.js 설정 - [ ] hls.js 1.6.x 설치 및 Video.js VHS와의 역할 분담 결정 - [ ] backBufferLength: 30, maxBufferSize: 60MB 등 필수 설정 적용 - [ ] 에러 복구 로직 (QuotaExceededError 대응) #### 3-5. 기본 UI 레이아웃 - [ ] 메인 레이아웃: 플레이어 영역 + 사이드 패널 (영상 목록/주석) - [ ] 반응형 기본 구조 (Tailwind) - [ ] Zustand 스토어 기본 구조 (현재 영상, 재생 상태, 소스 타입) ### 산출물 (완료 기준) - 로컬 mp4 파일 드래그앤드롭 → 즉시 재생 - 서버 영상 선택 → Range Request로 재생 - HLS 변환 완료 후 HLS로 전환 재생 - 전체화면 동작 확인 ### 다음 단계 의존성 - 단계 4, 5, 6 모두 이 단계 완료 후 시작 가능 --- ## 단계 4: 프레임 추출 ### 목표 Canvas 즉시 미리보기 + 서버 FFmpeg API를 통한 정확한 프레임 추출 ### 세부 태스크 - [ ] `utils/frameCapture.ts` — Canvas 기반 현재 프레임 캡처 (로컬 파일용 즉시 미리보기) - [ ] 단일 Canvas 재사용 패턴 적용 - [ ] `routes/frame.ts` 연동 — 서버 FFmpeg 프레임 추출 요청 - [ ] 프레임 추출 결과 표시 UI (모달 또는 패널) - [ ] 프레임 이미지 다운로드 기능 - [ ] Shift+S 단축키 → 현재 프레임 캡처 ### 산출물 (완료 기준) - 일시정지 상태에서 Shift+S → 프레임 이미지 표시 + 다운로드 - 서버 영상: FFmpeg 정확 추출 - 로컬 파일: Canvas 즉시 캡처 ### 다음 단계 의존성 - 단계 5에서 FPS 감지 로직과 연계 --- ## 단계 5: 단위 이동 ### 목표 프레임/초/장면 단위 seek + requestVideoFrameCallback FPS 감지 + 키보드 단축키 ### 세부 태스크 - [ ] `hooks/useFrameStep.ts` — requestVideoFrameCallback으로 FPS 동적 감지 (fallback 30fps) - [ ] 프레임 이동: `,`(이전) / `.`(다음) — 일시정지 상태에서만 - [ ] 초 이동: ←/→(5초), J/L(10초) - [ ] 장면 이동: `[`/`]` — 키프레임 기반 또는 일정 간격(30초) 이동 - [ ] 10% 단위 탐색: 0~9 키 - [ ] 재생 속도: +/- 키 (0.25x ~ 4x) - [ ] 전체화면 토글: F 키 - [ ] 음소거 토글: M 키 - [ ] 키보드 이벤트: 플레이어 포커스 시에만 활성, 텍스트 입력 시 비활성 - [ ] 현재 프레임 번호 / 타임코드 표시 UI ### 산출물 (완료 기준) - 모든 키보드 단축키 동작 확인 - 프레임 단위 이동 시 타임코드 정확 갱신 - FPS 감지 로그 출력 ### 다음 단계 의존성 - 없음 (단계 6과 병렬 진행 가능) --- ## 단계 6: 텍스트 오버레이 ### 목표 자막형(WebVTT track) + 메모형(interact.js DOM 오버레이) + 내보내기(subsrt) ### 세부 태스크 #### 6-1. 자막형 - [ ] WebVTT `` 연동 - [ ] 자막 추가/편집 UI (시작 시간, 종료 시간, 텍스트) - [ ] 서버 주석 API 연동 (type: "subtitle") - [ ] VTT/SRT 내보내기 (subsrt 라이브러리) #### 6-2. 메모형 - [ ] `components/overlay/MemoOverlay.tsx` — DOM 오버레이 컨테이너 - [ ] interact.js 드래그/리사이즈 연동 - [ ] 좌표 정규화: px → % 변환/저장 - [ ] 메모 추가 UI: Shift+M → 현재 시점에 메모 생성 - [ ] 메모 편집/삭제 UI - [ ] 표시 로직: requestAnimationFrame 루프 + 이진 탐색 - [ ] 서버 주석 API 연동 (type: "memo") - [ ] JSON/CSV 내보내기 #### 6-3. 주석 관리 패널 - [ ] `hooks/useAnnotations.ts` — 주석 CRUD + 서버 동기화 - [ ] 사이드 패널: 시간순 주석 목록, 클릭 시 해당 시점으로 이동 - [ ] 타임라인 위 주석 마커 표시 ### 산출물 (완료 기준) - 자막 추가 → 영상 재생 시 하단에 표시 - 메모 추가 → 드래그로 위치 조정 가능 - VTT/SRT/JSON/CSV 내보내기 동작 확인 ### 다음 단계 의존성 - 없음 (단계 5와 병렬 진행 가능) --- ## 단계 7: UI/UX 통합 ### 목표 전체 기능 통합, UI 다듬기, 썸네일 미리보기, 디스크 관리 ### 세부 태스크 - [ ] 전체 레이아웃 정리 (플레이어 + 컨트롤 + 사이드패널 통합) - [ ] 탐색바 썸네일 미리보기 (서버 FFmpeg 스프라이트 + VTT) - [ ] HLS 변환 진행률 UI (프로그레스 바 + 상태 텍스트) - [ ] 영상 목록 UI 개선 (업로드 상태, HLS 변환 상태, 용량) - [ ] 디스크 사용량 표시 + 경고 - [ ] 로딩/에러 상태 처리 (스켈레톤, 에러 바운더리) - [ ] 키보드 단축키 도움말 오버레이 (? 키) - [ ] 전체 기능 통합 테스트 - [ ] README.md 작성 (설치, 실행, 사용법) ### 산출물 (완료 기준) - 전체 기능이 하나의 UI에서 동작 - 서버 파일 + 로컬 파일 모두 테스트 완료 - README.md로 프로젝트 세팅/실행 가능 ### 다음 단계 의존성 - 모든 이전 단계 완료 필요 --- ## 단계 의존성 다이어그램 ``` 단계 1 (프로젝트 구조) ├── 단계 2 (백엔드 서버) │ ├── 단계 4 (프레임 추출) ──┐ │ └── 단계 6-자막 (주석 API) │ └── 단계 3 (기본 플레이어) │ ├── 단계 4 (프레임 추출) ──┤ ├── 단계 5 (단위 이동) ────┤ → 단계 7 (UI/UX 통합) └── 단계 6 (텍스트 오버레이)┘ ※ 단계 5와 6은 병렬 진행 가능 ```