Skip to content

[WTH-508] V3 파일 마이그레이터 + 첨부 허용 형식 확장 - #107

Draft
hyxklee wants to merge 4 commits into
devfrom
feat/WTH-508-file-migrator
Draft

hyxklee wants to merge 4 commits into
devfrom
feat/WTH-508-file-migrator

Conversation

@hyxklee

@hyxklee hyxklee commented Sep 19, 2026

Copy link
Copy Markdown
Member

배경

V3 → V4 마이그레이션(WTH-508)에서 파일만은 SQL로 처리할 수 없습니다.

이유
file.file_size V4에서 NOT NULL인데 V3 DB에 값이 없음 → S3 HeadObject 필요
file.content_type 동일
storage_key 키 형식이 달라 모든 객체를 새 키로 복사해야 함
V3  b2835a47-8728-4570-b584-6c0a39d5dbad.pdf          (버킷 루트 평면)
V4  POST/2025-03/b2835a47-...-dbad_영수증.pdf          ({OWNER_TYPE}/{yyyy-MM}/{uuid}_{fileName})

StorageKey VO가 정규식으로 형식을 강제하므로 예외가 없습니다.

변경 내용

1. 파일 마이그레이터 (src/migration/kotlin)

  • 별도 소스셋 — 일회성 도구가 운영 아티팩트(bootJar)에 섞이지 않습니다.
  • Spring 컨텍스트 없이 JDBC + AWS SDK v2만 사용합니다.
  • 기본이 dry-run입니다. 실제 반영은 --apply를 명시해야 합니다.
  • 원본 버킷은 읽기만 합니다. 삭제하지 않으므로 롤백은 V4 쪽 정리로 충분합니다.
  • CopyObject는 서버사이드라 객체 바이트가 실행 머신을 거치지 않습니다.
  • uuid를 V3 키에서 재사용하므로 같은 입력이면 같은 키가 나옵니다(멱등).
  • --offline 모드 — 자격증명 없이 키 생성·소유 매핑만 검토합니다.

2. 첨부 허용 형식에 pptx / docx 추가

V3에 세션 자료(pptx 27건)와 문서(docx 2건)가 있어 현행 목록으로는 이전할 수 없습니다.

PPTX("application/vnd.openxmlformats-officedocument.presentationml.presentation", setOf("pptx")),
DOCX("application/vnd.openxmlformats-officedocument.wordprocessingml.document", setOf("docx")),

svg는 추가하지 않았습니다. XML이라 <script>를 품을 수 있어 인라인 서빙 시 XSS 벡터가 됩니다.
mp4도 제외했습니다(용량·전송비·Range 요청). 두 건은 UNSUPPORTED_TYPE으로 남습니다.

Swagger @Schema 설명과 FileTypeTest도 함께 갱신했습니다.

실행

# 자격증명 없이 키 생성·소유 매핑만 검토
MIG_DB_PASSWORD=... ./gradlew migrateFiles --args="--offline"

# HeadObject로 생존·크기 확인 (복사 없음)
MIG_DB_PASSWORD=... ./gradlew migrateFiles --args="--source-bucket=... --target-bucket=..."

# 실제 반영
MIG_DB_PASSWORD=... ./gradlew migrateFiles --args="--source-bucket=... --target-bucket=... --apply"

검증

로컬 V3 복제본(406건)에 --offline 전수 실행:

변경 전 변경 후
이전 가능 370 399
UNSUPPORTED_TYPE 31 2 (mp4 1 / svg 1)
FAILED (비표준 키) 5 5

98.3%가 이전 가능해졌습니다. 생성 키 최대 길이 216자(한도 500), 키 생성 실패 0건.

./gradlew ktlintCheck compileMigrationKotlin test --tests "*File*Test" 통과.

남은 확인 사항

  • S3 객체 생존율 — 개발 머신에 AWS 자격증명이 없어 실측하지 못했습니다. 자격증명이 있는 환경에서 dry-run을 돌리면 확정됩니다.
  • 비표준 키 5건 — 한글 원본 파일명이 URL 인코딩된 채 키에 들어 있어 수동 확인이 필요합니다.

관련

🤖 Generated with Claude Code

https://claude.ai/code/session_01FUfuUw4qjjHWfZKiyqgADJ

V3 S3 객체를 V4 storage_key 형식으로 복사하고 file 테이블을 채운다.

file_size/content_type이 V4에서 NOT NULL인데 V3 DB에 값이 없어
S3 HeadObject가 필요하고, 키 형식이 평면({uuid}.{ext})에서
{OWNER_TYPE}/{yyyy-MM}/{uuid}_{fileName}로 바뀌어 전량 복사가 불가피하다.
따라서 SQL만으로는 처리할 수 없다.

- 운영 아티팩트에 섞이지 않도록 별도 소스셋(src/migration)으로 분리
- 기본 dry-run, --apply 명시 시에만 반영
- 자격증명 없이 매핑을 검토하는 --offline 모드 제공
- 원본 버킷은 읽기만 하므로 롤백은 V4 정리로 충분

Refs: WTH-508

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FUfuUw4qjjHWfZKiyqgADJ
@coderabbitai

coderabbitai Bot commented Sep 19, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

V3 마이그레이션 대상에 세션 자료(pptx 27건)와 문서(docx 2건)가 있어
현행 허용 목록(jpg/jpeg/png/webp/pdf)으로는 이전할 수 없다.

svg는 추가하지 않는다. XML이라 <script>를 품을 수 있어
인라인 서빙 시 XSS 벡터가 된다. mp4도 용량·전송비·Range 요청
문제로 제외한다. 두 건은 마이그레이션에서 UNSUPPORTED_TYPE으로 남는다.

Refs: WTH-508

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FUfuUw4qjjHWfZKiyqgADJ
@hyxklee hyxklee changed the title [WTH-508] V3 파일 마이그레이터 [WTH-508] V3 파일 마이그레이터 + 첨부 허용 형식 확장 Sep 19, 2026
hyxklee and others added 2 commits September 20, 2026 00:12
V3 버킷과 V4 버킷이 서로 다른 AWS 계정에 있다.
CopyObject 주체를 대상(V4) 계정에 두어야 복사된 객체의 소유권이
V4에 귀속된다. 소스 계정 주체로 실행하면 이후 V3 계정 정리 시
접근 불능이 된다.

s3:ListBucket 누락 시 없는 객체에 403이 반환되어
MISSING_IN_S3 판별이 불가능해지는 점도 명시한다.

Refs: WTH-508

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FUfuUw4qjjHWfZKiyqgADJ
V3/V4 버킷이 서로 다른 AWS 계정에 있다. 지금까지는 단일 주체가
양쪽 권한을 갖도록 소스 계정 버킷 정책을 수정해야 했다.

--source-profile / --target-profile 로 각 계정 자격증명을 따로 주면
CopyObject 대신 GetObject → PutObject 스트리밍으로 전환한다.
소스 계정 버킷 정책을 건드리지 않아도 되고, 각 키가 자기 버킷
권한만 가지면 된다. 바이트가 로컬을 경유하므로 egress 비용이
발생하지만 406건 규모에서는 무시할 수준이다.

크기를 HeadObject로 미리 알고 있어 메모리에 전부 적재하지 않는다.

Refs: WTH-508

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FUfuUw4qjjHWfZKiyqgADJ
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant