728x90
2편. 이미지 상태 기반 도메인 설계: TEMP, CONFIRMED, 그리고 그 이후
도입
이미지 업로드는 단순한 파일 저장이 아니다.
사용자 행동에 따라 임시 업로드, 확정, 삭제 대기, 완전 삭제 등 상태 흐름을 갖는다.
Bind 프로젝트의 이미지 모듈은 이 흐름을 명확하게 표현할 수 있는 상태 기반 도메인 모델링으로 설계했다.
단순한 URL 저장이 아니라, 이미지 객체의 상태 전이에 기반한 명세 중심 설계를 소개한다.
설계 목표
- 명확한 상태 기반 모델링을 통해 추적 가능한 이미지 흐름을 보장한다.
- 단일 API가 아닌, 후속 행동(BFF 확정 요청 등)에 따라 확장 가능한 구조를 만든다.
- 서비스 레이어에 로직이 집중되지 않도록 검증 로직과 상태 전이 책임을 분리한다.
설계 고려사항
상태 전이 흐름은 이렇게 작동한다
| 행동 | 상태 흐름 |
|---|---|
| 유저가 프로필 사진 업로드 | TEMP |
| 회원가입 완료되면 → BFF가 확정 요청 | TEMP → CONFIRMED |
| 게시글 수정으로 이미지 제거 | CONFIRMED → PENDING_DELETE |
| 1시간 이상 삭제 대기된 파일 | PENDING_DELETE → 삭제 스케줄러가 제거 |
boolean isDeleted 같은 단순한 플래그가 아닌, 도메인 중심 상태 흐름이 요구되었다.
구현 설명
Image 엔티티
@Entity
public class Image {
private Long id;
private String uuidName;
private String storedPath;
private ImageStatus status;
private ResourceCategory category;
private String referenceId;
private String uploaderId;
...
}
→ 저장 위치, 용량, MIME 타입, URL 등 기본 메타정보 외에도 status, referenceId, uploaderId는 상태 흐름을 위한 핵심 필드다.
ImageStatus Enum
public enum ImageStatus {
TEMP,
CONFIRMED,
PENDING_DELETE,
REJECTED;
}
- TEMP: 업로드 직후, 사용 여부 확정 전 상태
- CONFIRMED: 게시글, 프로필 등 실제 데이터와 연결됨
- PENDING_DELETE: 삭제 요청은 되었지만 아직 삭제되지 않은 상태
- REJECTED: 필터링 실패(NSFW 등) 시 사용 가능
→ 추후 상태는 ARCHIVED, EXPIRED로 확장할 수 있도록 열어두었다.
상태 검증: ImageValidator
@Component
public class ImageValidator {
public void validateUser(Image image, String userId) {
if (!image.getUploaderId().equals(userId)) {
throw new ImageException(UNAUTHORIZED_ACCESS);
}
}
...
}
- 이미지가 현재 유저의 것인지
- TEMP 상태인지
- 요청한 category와 일치하는지
→ 비즈니스 흐름이 많아질수록 검증 조건이 늘어날 수 있는데, Validator로 분리해 응집도 있는 단위로 묶었다.
상태 변경 책임 분리: ImageStatusChanger
@Component
public class ImageStatusChanger {
public void changeStatus(Image image, ImageStatus expected, ImageStatus to, ImageErrorCode error) {
if (expected != null && image.getStatus() != expected) {
throw new ImageException(error);
}
image.setStatus(to);
}
}
- 상태 변경은 모두
changeStatus()를 거치도록 해 무분별한 상태 조작을 막는다. expected상태가 있으면 사전 검증, 없다면 무조건 전이.
→ 추후 이벤트 발행(ConfirmedEvent 등) 시점도 이 컴포넌트에서 분리 가능하다.
회고 및 확장 가능성
ImageStatus를 도입함으로써 서비스 흐름이 눈에 보이도록 바뀌었다.- 예전처럼
isDeleted == true같은 의미 모호한 필드가 아니라, 도메인 중심의 상태 전이가 가능해졌다. Validator,StatusChanger를 분리하면서 테스트 커버리지 확보가 쉬워졌고, Mocking 단위도 명확해졌다.- 확정 시점에 Kafka 이벤트 발행이 필요해질 경우,
changeStatus내부에서 트리거하거나ConfirmedEvent도메인 이벤트로 추상화할 수 있다.
다음 글 예고
3편. 이미지 서비스 흐름과 테스트 전략
- upload → confirm → delete 흐름을 하나의 유즈케이스로 설명하고
ImageService가 어떻게 작은 책임으로 나뉘는지- 단위 테스트는 어떤 케이스를 중심으로 작성하는지
- 스케줄러 삭제 흐름과 실패 대비 전략
을 깊게 다룬다. 실질적인 코드 흐름과 테스트 전략을 정리할 예정이다.
728x90
'BindProject' 카테고리의 다른 글
| [Backend] 유저 활동 로그 수집 모듈 개발기 1편 유저 활동 로그 수집기 구상하기 (0) | 2025.06.21 |
|---|---|
| [Backend] Image모듈 개발기 3편. 이미지 서비스 흐름과 테스트 전략 (0) | 2025.06.21 |
| [Backend] Image 모듈 개발기 1편: 왜 우리는 직접 이미지 업로드 모듈을 만들었는가? (0) | 2025.06.21 |
| [초안] 합주실 탐색 기능의 설계: 정렬에서 표기로, 현실적인 MVP를 위한 선택 (3) | 2025.06.20 |
| [회고] Refresh Token 전략과 Redis 기반 설계, 그리고 트러블슈팅 회고 (1) | 2025.06.20 |