CloudFront 기반 이미지 에셋 관리 방식 채택

2026. 5. 26. 22:13·IL/TIL

배경

Polaris는 캐릭터, 스킨, 아이템, 출석, 공유카드 등 여러 종류의 이미지 에셋을 사용한다.

초기 프론트엔드에서는 assets/ 디렉터리에 이미지를 두고 Vite 번들에서 직접 참조했다. 이 방식은 빠르게 화면을 구성하기에는 단순하지만, 캐릭터/스킨/아이템처럼 DB의 서비스 데이터와 연결되는 이미지를 계속 프론트 repo에 두면 운영상 문제가 생긴다.

특히 Polaris는 다음 이미지들을 여러 소비자가 함께 사용할 가능성이 있다.

  • 웹 프론트
  • Android 앱
  • 백엔드 공유 링크/OG 처리
  • 상점/보관함 API
  • 캐릭터 상태 API
  • 공유카드 이미지 생성/업로드 흐름

따라서 이미지 원본을 프론트나 백엔드 서버에 흩어두지 않고, 하나의 공통 출처로 관리할 필요가 있다.


논의한 문제

  1. 캐릭터/스킨/아이템 이미지를 프론트 repo에 둘 것인가?
  2. 백엔드 서버 디스크에 이미지를 저장할 것인가?
  3. S3와 CloudFront를 공통 이미지 출처로 사용할 것인가?
  4. DB에는 이미지 파일 자체가 아니라 무엇을 저장할 것인가?
  5. 프론트 전용 UI 에셋도 모두 S3/CloudFront로 옮겨야 하는가?
  6. 이미지 교체 시 CloudFront 캐시 문제를 어떻게 처리할 것인가?
  7. 장착 스킨처럼 캐릭터별/상태별로 여러 이미지가 필요한 에셋은 어떻게 모델링할 것인가?

검토한 선택지

선택지 1. 프론트 repo assets에 이미지 저장

장점:

  • 초기 구현이 빠르다.
  • React/Vite에서 바로 import하거나 new URL()로 참조할 수 있다.
  • 로고, 아이콘, placeholder 같은 고정 UI 이미지는 관리가 단순하다.

단점:

  • 캐릭터/스킨/아이템 이미지 변경 시 프론트 재배포가 필요하다.
  • DB의 imageUrl, assetUrl이 프론트 배포 산출물 경로에 의존할 수 있다.
  • 백엔드, 모바일 앱, 공유 링크가 같은 이미지를 쓰기 어렵다.
  • 서비스 데이터 이미지와 UI 이미지의 책임이 섞인다.

검토 결과:

프론트 전용 UI 에셋에는 적합하지만, 서비스 데이터와 연결된 이미지의 원본 저장소로는 부적절하다.

선택지 2. 백엔드 서버 디스크에 이미지 저장

장점:

  • 처음에는 단순해 보인다.
  • 백엔드에서 파일 경로를 직접 관리할 수 있다.

단점:

  • 백엔드 서버가 이미지 트래픽까지 처리한다.
  • 서버 재배포/교체 시 파일 누락 위험이 있다.
  • 서버가 여러 대가 되면 파일 동기화 문제가 생긴다.
  • 공유 링크/OG 이미지처럼 외부 플랫폼이 접근해야 하는 이미지 공개 처리가 번거롭다.

검토 결과:

운영 확장성과 배포 안정성 측면에서 적합하지 않다.

선택지 3. S3 + CloudFront 사용

장점:

  • S3를 이미지 원본 저장소로 사용할 수 있다.
  • CloudFront를 통해 빠른 공개 URL과 캐시를 제공할 수 있다.
  • 프론트, 백엔드, 모바일 앱이 같은 URL을 사용할 수 있다.
  • 백엔드 서버가 이미지 트래픽을 처리하지 않는다.
  • 서버 재배포/증설과 이미지 파일 관리가 분리된다.
  • DB에는 URL 또는 asset key만 저장하면 된다.

단점:

  • S3, CloudFront, CORS, 권한 설정이 필요하다.
  • 캐시 정책과 파일명 버전 전략이 필요하다.
  • 초기 설정이 프론트 repo 저장 방식보다 복잡하다.

검토 결과:

Polaris의 캐릭터/스킨/아이템/공유카드 이미지는 서비스 데이터와 연결되므로 S3 + CloudFront를 공통 이미지 출처로 사용하는 것이 가장 적합하다.


결정

Polaris는 서비스 데이터와 연결되는 이미지 에셋을 S3에 저장하고, CloudFront URL로 제공한다.

DB에는 이미지 파일 자체를 저장하지 않고, CloudFront URL 또는 asset key를 저장한다.

백엔드는 이미지 파일을 직접 보관하거나 서빙하지 않는다. 백엔드는 DB에 저장된 이미지 URL을 API 응답으로 내려준다.

프론트는 API가 내려준 이미지 URL을 우선 사용한다. 로컬 assets는 개발용 fixture 또는 fallback 용도로만 사용한다.


에셋 분류 정책

S3/CloudFront로 관리할 에셋

다음 에셋은 서비스 데이터와 연결되므로 S3/CloudFront 기준으로 관리한다.

  • 캐릭터 기본/상태 이미지
  • 스킨 썸네일
  • 장착 스킨의 캐릭터별/상태별 이미지
  • 아이템 이미지
  • 공유카드 배경/캐릭터/스탬프
  • 사용자가 생성한 공유카드 이미지
  • OG 이미지로 사용될 공유 이미지

프론트 repo에 남길 수 있는 에셋

다음 에셋은 프론트 UI의 일부이므로 프론트 repo에 남길 수 있다.

  • 로고
  • favicon
  • 기본 placeholder
  • 빈 상태 일러스트
  • 카테고리 아이콘
  • 별조각 아이콘
  • 출석 도장/배너
  • UI 장식용 패턴과 효과 이미지

단, 모바일 앱이나 백엔드 공유카드 생성에서도 같은 에셋을 사용해야 하는 경우에는 CDN으로 옮길 수 있다.


데이터 모델링 규칙

아이템 이미지

items.image_url은 상점/보관함에서 보여줄 대표 이미지 또는 썸네일로 사용한다.

items.image_url
→ 스킨 대표 썸네일
→ 소모품 대표 이미지

캐릭터 이미지

캐릭터 기본 이미지는 character_assets에 저장한다.

권장 asset type:

idle
happy
sleepy
hungry
lowEnergy
lonely

장착 스킨 이미지

items.image_url 하나로는 장착 스킨의 캐릭터별/상태별 이미지를 표현할 수 없다.

따라서 장착 스킨 이미지는 별도 테이블로 분리한다.

skin_assets
- id
- item_id
- character_type_id
- asset_type
- asset_url

예시:

item_id: 말랑 별빛 스킨
character_type_id: MUMU
asset_type: idle
asset_url: https://.../assets/skins/starlight/equipped/mumu/core/skin-starlight-mumu-idle-v1.png

API 응답 규칙

프론트가 파일명 규칙을 추론하지 않도록, 백엔드는 필요한 이미지 URL을 API 응답에 포함한다.

홈 API의 캐릭터 응답은 기존 currentAssetUrl을 유지하되, 상태별 URL을 추가할 수 있다.

{
  "character": {
    "id": 10,
    "name": "작은무무",
    "characterTypeCode": "MUMU",
    "currentAssetUrl": "https://.../character-mumu-idle-v1.png",
    "assetUrls": {
      "idle": "https://...",
      "happy": "https://...",
      "sleepy": "https://...",
      "hungry": "https://...",
      "lowEnergy": "https://...",
      "lonely": "https://..."
    }
  }
}

장착 스킨이 있으면 assetUrls는 장착 스킨 기준 URL을 내려준다. 장착 스킨이 없으면 기본 캐릭터 기준 URL을 내려준다.


캐시 정책

CloudFront 캐시 무효화를 자주 사용하지 않기 위해 파일명 버전 전략을 우선한다.

권장:

character-mumu-idle-v1.png
character-mumu-idle-v2.png
skin-starlight-thumbnail-v1.png

비권장:

idle.png 파일을 같은 이름으로 계속 덮어쓰기

이미지 교체 시에는 새 파일명으로 업로드하고, DB의 URL을 새 URL로 변경한다.


결과

  • 이미지 원본 위치는 S3로 통일한다.
  • 공개 URL과 캐시는 CloudFront가 담당한다.
  • 백엔드는 이미지 파일을 직접 보관하지 않는다.
  • 프론트는 API가 내려준 URL을 우선 사용한다.
  • 프론트 전용 UI 에셋은 repo에 남길 수 있다.
  • 캐릭터/스킨/아이템처럼 서비스 데이터와 연결되는 이미지는 DB/API 기준으로 관리한다.
  • 이미지 교체는 파일명 버전 전략을 우선한다.

검증 계획

기능 검증

  • items.image_url이 실제 CloudFront URL로 내려오는지 확인한다.
  • character_assets.asset_url이 실제 CloudFront URL로 내려오는지 확인한다.
  • 홈/캐릭터 API가 currentAssetUrl 또는 assetUrls를 정상 반환하는지 확인한다.
  • 프론트가 API URL을 우선 사용하고 로컬 asset은 fallback으로만 사용하는지 확인한다.

운영 검증

  • CloudFront URL로 이미지가 정상 로딩되는지 확인한다.
  • 같은 이미지가 웹, 모바일 앱, 공유 링크에서 동일하게 보이는지 확인한다.
  • 이미지 교체 시 새 파일명과 DB URL 변경만으로 최신 이미지가 반영되는지 확인한다.

후속 과제

  • 실제 CloudFront URL 기준으로 item seed 수정
  • character_assets에 상태별 asset URL 추가
  • skin_assets 테이블 추가 검토 및 migration 작성
  • 홈/캐릭터 API에 assetUrls 응답 추가
  • 프론트 resolver를 API URL 우선, 로컬 fallback 후순위로 변경
  • 프론트 assets에서 서비스 데이터 이미지 제거 여부 검토
저작자표시 비영리 (새창열림)

'IL > TIL' 카테고리의 다른 글

최종프로젝트 인프라 모니터링 설계  (0) 2026.05.28
사용자/제품 로그 설계  (0) 2026.05.27
20260522 [TIL] - 채팅 문의 인덱싱 정리  (0) 2026.05.22
최종프로젝트에서 flyway 쓰는 이유  (0) 2026.05.21
외부 AI Provider 호출 보호를 위한 Redis 기반 Rate Limit 적용  (0) 2026.05.20
'IL/TIL' 카테고리의 다른 글
  • 최종프로젝트 인프라 모니터링 설계
  • 사용자/제품 로그 설계
  • 20260522 [TIL] - 채팅 문의 인덱싱 정리
  • 최종프로젝트에서 flyway 쓰는 이유
견지
견지
개발로 개발하는지 새발로 개발하는지 내가 개인 건지 새인 건지 사람인 건지
  • 견지
    개발새발
    견지
  • 전체
    오늘
    어제
    • 분류 전체보기 (33)
      • ... (0)
      • IL (33)
        • TIL (29)
        • WIL (4)
        • MIL (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

    • Github
  • 공지사항

  • 인기 글

  • 태그

    git
    java
    CSS
    JavaScript
    oracle
    HTML
    DB
    JSP
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.6
견지
CloudFront 기반 이미지 에셋 관리 방식 채택
상단으로

티스토리툴바