🌱 새싹막 심은 생각. 거칠고 바뀔 수 있어요.
지워지지 않는 이미지들: 게시글 수정 API와 클라이언트를 믿는다는 것
문제
디스크 용량을 확보해야 했는데, 어느 게시글에서도 쓰이지 않는 고아(Orphan) 이미지들이 쌓여 있었습니다. 어떤 이미지가 정말 안 쓰이는지 확신할 수 없으니 함부로 지울 수도 없는 상황이었습니다.
원인: 본문에서 빠졌지만, 저장소에서는 빠지지 않았다
WYSIWYG 에디터에서 이미지를 올리면 업로드와 동시에 저장됩니다. 그런데 사용자가 게시글을 수정하면서 본문에서 이미지를 지워도, 서버의 이미지 파일과 레코드는 그대로 남아 있었습니다. 게시글 수정 흐름에 삭제 처리가 누락되어 있었던 것입니다.
해결
게시글 수정 API에서 본문에서 빠진 이미지를 실제로 삭제하도록 개선하고, 기존에 쌓인 고아 이미지를 정리해 디스크 용량을 확보했습니다.
회고: 삭제할 id를 누가 판단해야 했나
당시에는 프론트엔드에서 본문을 비교해 삭제할 이미지 id를 추출하고, API는 그 목록을 받아 지우는 방식으로 구현했습니다.
지금 돌아보면 판단 로직은 서버에 있어야 했습니다.
- 클라이언트가 보낸 “삭제할 id 목록”은 조작될 수 있습니다. 다른 사람 게시글의 이미지 id가 섞여 들어와도 서버는 알 수 없습니다.
- 서버는 수정 전 본문과 수정 후 본문을 모두 알고 있습니다. 스스로 차이를 계산할 수 있는 쪽이 판단하는 게 맞습니다.
// 지금이라면 이렇게: 서버가 직접 차이를 계산 (단순화한 예시)
Set<Long> before = extractImageIds(post.getContent());
Set<Long> after = extractImageIds(request.content());
before.removeAll(after); // 본문에서 빠진 이미지
imageRepository.deleteAllByIdInAndPostId(before, post.getId());
이 일을 계기로 client side의 신뢰성에 대해 더 깊게 고민하게 됐습니다. 클라이언트가 보낸 값은 “요청”일 뿐, 서버가 검증 없이 따를 “사실”이 아니라는 것.
판단 로직을 어디에 두는지가 확장성과 신뢰성을 가른다는 점은 차량 판별 노트의 교훈과도 닮았어요.