[feat] 배너 미디어 타입 지원 (IMAGE/VIDEO) 및 동영상 업로드#38
Conversation
배너 API에 추가된 mediaType 필드를 프론트엔드 전 계층에 반영하고, 동영상(MP4) 업로드 및 미리보기 기능을 구현한다. - types: MediaType 타입, presigned URL contentType 파라미터 추가 - schema: 폼 스키마에 mediaType 필드 추가 (기본값: IMAGE) - service: S3 presigned URL 요청 시 contentType 전달 - form: 파일 업로드 시 file.type 기반 mediaType 자동 판별 - ImageUpload: 이미지/동영상 accept, 거부 콜백, 미리보기 분기 - BannerImageCard: 허용 외 파일 에러 토스트, mediaType 자동 설정 - BannerPreviewCard: form.mediaType 기반 비디오 미리보기 - fix: blob URL에서 useEffect가 isVideo를 덮어쓰는 버그 수정 - test: 유틸/컴포넌트/서비스/훅/E2E 테스트 51개 추가 (총 129개) Refs: bottle-note/workspace#205 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
배너 API의 mediaType(IMAGE/VIDEO) 추가에 맞춰 프론트 전 계층 타입/서비스/훅/폼/UI를 확장하고, MP4 업로드 및 미리보기까지 지원하도록 변경한 PR입니다.
Changes:
MediaType및 배너 API 타입(mediaType) / S3 presign 파라미터(contentType) 반영- 배너 등록/수정 폼에
mediaType포함, 업로드 컴포넌트가image/*,video/mp4및<video>미리보기 지원 - 관련 단위 테스트 및 E2E 테스트/fixture 추가
Reviewed changes
Copilot reviewed 17 out of 18 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/types/api/s3.api.ts | presign URL 요청 파라미터에 contentType? 추가 |
| src/types/api/banner.api.ts | MediaType/라벨, 배너 응답·요청에 mediaType 추가 |
| src/test/mocks/data.ts | 배너 mock 데이터에 mediaType 추가 |
| src/services/s3.service.ts | uploadImage에서 presign 요청 시 contentType 전달 |
| src/services/tests/s3.service.test.ts | contentType 전달 및 PUT 헤더 관련 테스트 추가 |
| src/pages/banners/useBannerDetailForm.ts | 폼 초기값/submit payload에 mediaType 포함 |
| src/pages/banners/components/BannerPreviewCard.tsx | mediaType에 따라 <img>/<video> 미리보기 분기 |
| src/pages/banners/components/BannerImageCard.tsx | accept/reject 처리, file.type 기반 mediaType 자동 판별 |
| src/pages/banners/banner.schema.ts | Zod 스키마에 mediaType 추가 및 기본값 설정 |
| src/pages/banners/tests/banner.schema.test.ts | mediaType 스키마 검증 테스트 추가 |
| src/pages/banners/tests/BannerImageCard.test.tsx | mediaType 자동 판별/거부/UI 상태 테스트 추가 |
| src/pages/banners/BannerDetail.tsx | 업로드/삭제 흐름에서 mediaType 상태 반영 |
| src/hooks/tests/useBanners.test.ts | 목록/상세/생성/수정에서 mediaType 검증 테스트 추가 |
| src/components/common/ImageUpload.tsx | accept/거부 콜백, 비디오 미리보기, blob URL 판별 로직 추가 |
| src/components/common/tests/ImageUpload.test.tsx | 파일 타입 유틸/거부/미리보기 분기/재렌더 안정성 테스트 추가 |
| e2e/specs/banners.spec.ts | 동영상/이미지 업로드 미리보기 분기 E2E 추가 |
| e2e/pages/banner-detail.page.ts | 업로드 대상 locator 및 업로드 헬퍼(video) 추가 |
| e2e/fixtures/test-video.mp4 | E2E용 MP4 fixture 추가 |
| uploadImage: async (file: File, rootPath: string, contentType?: string): Promise<string> => { | ||
| // 1. Presigned URL 발급 | ||
| const presignResponse = await s3Service.getPresignedUrls({ | ||
| rootPath, | ||
| uploadSize: 1, | ||
| contentType: contentType ?? file.type, | ||
| }); |
There was a problem hiding this comment.
[P1] uploadImage에서 contentType을 presign 요청에만 적용하고, 실제 S3 PUT은 항상 file.type으로 Content-Type 헤더를 보내서 불일치가 발생할 수 있습니다.
uploadImage(file, rootPath, 'video/webm')처럼 contentType을 명시한 경우 presigned URL의 서명 조건과 PUT 헤더가 달라져 업로드가 403으로 실패할 수 있습니다; PUT에도 동일한 contentType을 사용하도록 uploadToS3에 전달해 주세요.
There was a problem hiding this comment.
Fixed in 9bf359e.
변경 내용: uploadToS3에 contentType 파라미터를 추가하고, uploadImage에서 presign과 PUT 양쪽에 동일한 contentType을 전달하도록 수정했습니다.
이유: presigned URL 서명 조건과 S3 PUT 헤더가 불일치하면 403 에러가 발생하므로, 두 값을 항상 일치시켜야 합니다.
| setIsVideo(file.type.startsWith('video/')); | ||
| const url = URL.createObjectURL(file); | ||
| setPreviewUrl(url); | ||
| onImageChange(file, url); |
There was a problem hiding this comment.
[P1] URL.createObjectURL로 만든 blob URL을 URL.revokeObjectURL로 정리하지 않아 파일을 여러 번 교체/삭제하면 메모리가 누적될 수 있습니다.
배너 등록/수정 페이지에서 미디어를 여러 번 바꾸는 경우 탭 메모리가 계속 증가할 수 있으니, 새 blob URL 생성 전에 이전 URL을 revoke하고 unmount/삭제 시에도 revoke하도록 cleanup을 추가해 주세요.
There was a problem hiding this comment.
Fixed in e07e49f.
변경 내용: blobUrlRef로 현재 blob URL을 추적하고, 파일 교체 시 이전 blob URL을 URL.revokeObjectURL로 정리합니다. 삭제 시에도 동일하게 cleanup합니다.
이유: 파일을 여러 번 교체하면 blob URL이 누적되어 메모리 누수가 발생할 수 있습니다.
| const handleMediaTypeChange = (mediaType: 'IMAGE' | 'VIDEO') => { | ||
| form.setValue('mediaType', mediaType); | ||
| }; |
There was a problem hiding this comment.
[P2] 폼 validation 실패 시 console.log가 남아 있습니다.
프로덕션에서 콘솔 로그가 남으면 운영 중 디버그 출력이 노출될 수 있으니 제거하거나 로깅 유틸로 대체해 주세요.
There was a problem hiding this comment.
Fixed in bcf586c.
변경 내용: console.log 디버그 코드를 제거하고, 불필요한 에러 핸들러 콜백도 함께 제거했습니다.
uploadToS3에 contentType 파라미터를 추가하여 presigned URL 서명 조건과 S3 PUT 헤더가 항상 동일하도록 보장한다. Addresses review comment by @Copilot on src/services/s3.service.ts:66. PR: #38 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
파일 교체/삭제 시 이전 blob URL을 revokeObjectURL로 정리하여 메모리 누적을 방지한다. 빌드 에러 수정 포함. Addresses review comment by @Copilot on src/components/common/ImageUpload.tsx:95. PR: #38 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
폼 validation 에러 핸들러의 console.log를 제거한다. Addresses review comment by @Copilot on src/pages/banners/BannerDetail.tsx:70. PR: #38 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
요약
배너 API에 추가된
mediaType필드(IMAGE/VIDEO)를 프론트엔드 전 계층에 반영하고, 동영상(MP4) 업로드 및 미리보기 기능을 구현한다.동기
contentType파라미터 및 Banner 엔티티의mediaType필드가 이미 반영됨 (bottle-note-api-server#571)변경사항
API 타입 (types → service → hook 3계층)
MediaType타입(IMAGE|VIDEO) 및MEDIA_TYPE_LABELS추가mediaType필드 추가mediaType?필드 추가PresignUrlParams에contentType?파라미터 추가s3Service.uploadImage에서 presigned URL 요청 시contentType전달폼 / UI
mediaTypeenum 필드 추가 (기본값:IMAGE)useBannerDetailForm: 폼 초기화 및 API 요청 시mediaType포함ImageUpload:accept,onFileRejected, 비디오 미리보기 분기 지원BannerImageCard:image/*,video/mp4허용,file.type기반mediaType자동 판별, 허용 외 파일 에러 토스트BannerPreviewCard:form.mediaType기반<video>미리보기버그 수정
useEffect가isVideo상태를 덮어쓰는 문제 수정 (CDN URL만 확장자 기반 판별, blob URL은handleFile에서 설정한 값 유지)테스트
ImageUpload.test.tsx: 파일 검증 유틸(isFileTypeAllowed,isVideoFile), 파일 거부 콜백, 미리보기 렌더링 분기, blob URL 재렌더링 안정성 (35 cases)BannerImageCard.test.tsx:mediaType자동 판별, 파일 거부, UI 상태 (8 cases)banner.schema.test.ts: 폼 스키마 유효성 검사 (6 cases)s3.service.test.ts: presigned URLcontentType전달, S3 업로드 헤더, 에러 처리 (8 cases)useBanners.test.ts: 목록/상세mediaType포함, VIDEO 타입 생성/수정 (4 cases 추가)banners.spec.ts(E2E): 동영상/이미지 업로드 시 미리보기 분기 (2 cases)테스트
pnpm test:run— 129개 테스트 전부 통과pnpm build— 타입 체크 + 프로덕션 빌드 통과<img>미리보기 확인<video>미리보기 확인🤖 Generated with Claude Code