이미지를 교체해도 엔티티 ID는 그대로다
아바타 이미지를 교체할 때 같은 DB 행을 갱신하면 이미지 ID와 미리보기 경로가 유지된다. 파일은 새것이어도 클라이언트의 src가 같으면 재조회 계기가 생기지 않고, 캐시된 이전 이미지가 보일 수 있다. 엔티티를 식별하는 주소만으로 파일의 교체까지 표현하지 못하는 경우다.
AI Commons에서는 기본 경로를 유지하면서 내부 저장 키 fileKey에서 계산한 버전을 ?v=로 붙였다. 행 ID를 새로 만들지 않고 파일 교체를 URL 변화로 표현한다. 같은 파일을 조회할 때마다 임의 값을 붙이는 방식과 달리 fileKey가 같으면 URL도 유지된다.
짧은 해시는 캐시를 구분하는 값이다
응답 mapper는 SHA-1 결과의 앞 8자리로 버전을 만든다. 다음은 헬퍼와 URL 조립을 합친 축약이다.
const version = createHash('sha1').update(image.fileKey).digest('hex').slice(0, 8);
const previewUrl = '/avatars/' + image.avatarId + '/images/' + image.id
+ '/preview?v=' + version; mapper 입력의 ImageLike에 fileKey를 필수로 두어 조회에서 빠뜨리면 타입으로 확인할 수 있게 한다. 응답은 허용한 필드만 조립하므로 fileKey 원문을 내리지 않는다. 이 값은 파일 바이트의 무결성 검증이나 인증 수단이 아니다. 앞 8자리는 32비트의 짧은 구분 값이며 충돌이 수학적으로 불가능하지도 않다.
교체마다 새 fileKey를 받는 것이 이 방식의 전제다. 같은 저장 키의 바이트를 덮어쓰면 버전은 변하지 않는다. URL의 query까지 캐시 키에 포함하는 중간 캐시도 필요하다. URL이 바뀌면 새 바이트를 요청할 수 있지만 옛 캐시 객체를 직접 지우는 방식은 아니므로 이전 객체는 쓰이지 않은 채 남을 수 있다.
같은 ID와 다른 파일을 입력으로 비교한다
DTO 회귀 테스트는 같은 아바타·이미지 ID에 다른 fileKey를 넣어 기본 경로는 같고 전체 미리보기 URL은 달라지는지 확인한다. 응답에 fileKey 원문이 없는지도 검사하고, 컨트롤러 테스트는 응답 경계의 mapper 사용을 다룬다. 해시 기대값 일부는 구현과 같은 산식을 사용하므로 가장 의미 있는 조건은 다른 저장 키가 다른 URL을 만들고 ID는 유지한다는 관계다.
실제 브라우저나 CDN의 캐시 갱신을 실행한 검증은 아니다. AI Commons의 이 수정은 엔티티의 안정적인 식별자를 유지하면서 파일 버전 변화를 응답 주소에 전달하는 작은 계약으로 볼 수 있다.