[QRoad]PDF 기반 publication 업로드 구조 개선기 – 2편: S3 presigned URL 설계
이 글은 「PDF 기반 publication 업로드 구조 개선기」 시리즈의 2편입니다.
(1편) 기존 구조의 문제점 → (2편) S3 presigned URL 설계 → (3편) Spring Boot 구현
1편에서는 기존 텍스트 기반 publication 저장 구조가
왜 PDF 업로드 방식과 맞지 않았는지를 정리했다.
이번 글에서는 그 고민의 연장선에서
“서버가 파일을 직접 받지 않는 업로드 구조”를 어떻게 설계했는지,
그리고 왜 S3 presigned URL을 선택했는지를 정리해보려고 한다.
서버가 파일을 직접 받으면 생기는 문제
가장 단순한 파일 업로드 구조는 보통 이렇다.
서버가 multipart 요청으로 파일을 받고,
그 파일을 다시 S3에 업로드하는 방식이다.
처음엔 익숙하고 구현도 쉬워 보이지만,
실제로는 여러 문제가 숨어 있었다.
- 서버가 파일 데이터를 직접 처리해야 하고
- 파일 크기가 커질수록 메모리/디스크 부담이 커지며
- 업로드 도중 서버가 죽으면 전체 요청이 실패한다
특히 publication 생성처럼
파일 업로드 이후 추가 작업이 이어지는 흐름에서는
서버가 병목이 되기 쉽다.
“파일 업로드”와 “비즈니스 로직”은 성격이 다르다
여기서 한 가지를 분리해서 볼 필요가 있었다.
- 파일 업로드: 대용량 I/O 작업
- publication 생성: 비즈니스 로직
이 둘을 같은 API에서 처리하면:
- 실패 지점이 불분명해지고
- 예외 처리가 복잡해지며
- 역할 경계도 흐려진다
그래서 목표를 이렇게 잡았다.
“서버는 파일을 저장하지 말고,
파일을 다루는 ‘흐름’만 관리하자.”
presigned URL이 해결해준 것
S3 presigned URL은
서버가 가진 S3 접근 권한을,
아주 제한된 형태로 잠시 빌려주는 URL이다.
이 방식을 사용하면 업로드 흐름이 바뀐다.
서버는:
- 파일 데이터를 직접 받지 않고
- “어디에 업로드할지”만 결정한다
이 구조가 마음에 들었던 이유는 명확했다.
1. 서버 부담이 거의 없다
파일 데이터는 프론트에서 S3로 바로 전송된다.
서버는 업로드 요청을 처리하지 않기 때문에
- 메모리/디스크 부담이 없고
- 트래픽 증가에도 비교적 안정적이다
2. 업로드와 비즈니스 로직을 분리할 수 있다
파일 업로드는 사전 작업,
publication 생성은 확정 작업으로 분리할 수 있다.
이 덕분에:
- 파일만 다시 올리는 것도 가능하고
- publication 생성 실패 시에도
파일을 바로 버릴 필요가 없다
3. 보안도 충분히 통제할 수 있다
presigned URL은:
- 특정 객체(key)에만 접근 가능하고
- PUT 같은 특정 동작만 허용되며
- 짧은 시간 후 자동으로 만료된다
버킷을 public으로 열 필요도 없고,
프론트에 AWS 키를 노출할 필요도 없다.
임시(temp) 경로와 확정(final) 경로
설계를 하면서 한 가지 규칙을 더 추가했다.
“업로드된 파일은 바로 확정하지 않는다.”
그래서 S3 경로를 두 단계로 나눴다.
temp/{uuid}.pdf // 임시 업로드
paper/{id}.pdf // publication 확정 파일
- temp/ 경로의 파일은 언제든 사라질 수 있고
- publication 생성이 끝난 뒤에만
paper/ 경로로 이동한다
이렇게 하면:
- 업로드만 하고 취소된 파일은 정리할 수 있고
- DB에는 확정된 파일만 남길 수 있다
전체 흐름 정리
지금까지 정리한 구조를 한 번에 보면 이렇다.
1. 프론트 → 서버 임시 업로드용 presigned URL 요청
2. 프론트 → S3 PDF 파일 임시 업로드 (temp)
3. 프론트 → publication API tempKey 전달
4.publication 처리 완료 후 파일 확정 요청 → temp → final 이동
이 흐름에서 서버는
- 파일 내용을 직접 다루지 않고
- 파일의 “상태 변화”만 관리한다