Skip to content

fix/#150: 네컷사진 삭제 시 Soft Delete 로 변경#151

Merged
Darren4641 merged 1 commit intostagingfrom
fix/#150
Feb 24, 2026
Merged

fix/#150: 네컷사진 삭제 시 Soft Delete 로 변경#151
Darren4641 merged 1 commit intostagingfrom
fix/#150

Conversation

@Darren4641
Copy link
Member

Description

  • 데이터보존 및 추적을 위해 Hard Delete -> Soft Delete로 변경 작업

Action Item

  • 이미지 삭제 시 photo_image 테이블에 삭제할 row에 folder_id를 null로 변경 후 delete_at 값을 현재시간으로 변경
  • photo_image 테이블에 @SQLRestriction("deleted_at IS NULL") 을 추가하여 조회 시 기본으로 where deleted_at is null 조건 추가
  • media 테이블의 경우도 status를 DELETED로 변경 (기존에는 삭제였음) S3 스토리지의 값도 삭제 안하도록 수정

@Darren4641 Darren4641 self-assigned this Feb 23, 2026
@Darren4641 Darren4641 linked an issue Feb 23, 2026 that may be closed by this pull request
@gemini-code-assist
Copy link

Summary of Changes

Hello @Darren4641, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

이 Pull Request는 데이터 보존 및 추적의 필요성에 따라 애플리케이션의 삭제 로직을 Hard Delete에서 Soft Delete 방식으로 전환합니다. PhotoImage와 Media 엔티티 모두에 대해 삭제 시 실제 데이터를 제거하는 대신, 특정 필드(예: deleted_at, status)를 업데이트하여 논리적으로 삭제된 상태를 표시하도록 변경되었습니다. 이는 데이터 복구 가능성을 높이고, 삭제 이력을 관리하며, S3 스토리지의 미디어 파일이 실수로 삭제되는 것을 방지하는 데 기여합니다.

Highlights

  • 네컷사진 Soft Delete 구현: photo_image 테이블에서 사진 삭제 시 folder_id를 null로 설정하고 deleted_at 필드에 현재 시간을 기록하여 Soft Delete를 수행하도록 변경되었습니다.
  • 미디어 Soft Delete 전환: media 테이블의 삭제 로직도 status를 DELETED로 변경하는 Soft Delete 방식으로 전환되었으며, S3 스토리지에서 실제 파일을 삭제하는 작업은 더 이상 수행되지 않습니다.
  • 자동 조회 필터링 추가: PhotoImage 엔티티에 @SQLRestriction("deleted_at IS NULL") 어노테이션을 추가하여, 조회 시 deleted_at 값이 NULL인 레코드만 기본적으로 가져오도록 설정되었습니다.
  • 데이터베이스 스키마 변경: TB_PHOTO_IMAGE 테이블에 deleted_at 컬럼이 추가되었고, 기존 uk_photo_image_media_id 유니크 제약조건이 삭제되었으며, deleted_at IS NULL인 레코드에 대해서만 유니크를 보장하는 부분 유니크 인덱스로 대체되었습니다.
  • MediaRepositoryPort 확장: 여러 미디어를 한 번에 저장할 수 있는 saveAll 메서드가 MediaRepositoryPort 인터페이스에 추가되었습니다.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • src/main/kotlin/com/neki/media/application/port/MediaRepositoryPort.kt
    • saveAll(medias: List): List 메서드가 추가되었습니다.
  • src/main/kotlin/com/neki/media/application/usecase/DeleteMediaUseCase.kt
    • MediaStoragePort 의존성이 제거되었습니다.
    • 단건 및 벌크 미디어 삭제 로직이 Soft Delete 방식으로 변경되어, Media 엔티티의 상태를 DELETED로 업데이트하고 저장하도록 수정되었습니다.
    • S3 스토리지에서 실제 파일을 삭제하는 로직이 제거되었습니다.
  • src/main/kotlin/com/neki/media/infra/persist/MediaRepositoryAdapter.kt
    • MediaRepositoryPort 인터페이스의 saveAll 메서드 구현이 추가되었습니다.
  • src/main/kotlin/com/neki/photo/domain/entity/PhotoImage.kt
    • deletedAt 필드(LocalDateTime?)가 추가되었습니다.
    • @SQLRestriction("deleted_at IS NULL") 어노테이션이 추가되어 기본 조회 시 삭제되지 않은 레코드만 가져오도록 설정되었습니다.
    • softDelete() 메서드가 추가되어 folderId를 null로, deletedAt을 현재 시간으로 설정합니다.
  • src/main/kotlin/com/neki/photo/infra/persist/PhotoImageRepositoryAdapter.kt
    • deleteAll 메서드가 PhotoImage 엔티티들을 순회하며 softDelete()를 호출하고 saveAll을 통해 업데이트하도록 변경되었습니다.
  • src/main/kotlin/com/neki/photo/infra/persist/jpa/PhotoImageQueryRepository.kt
    • updateFolderIdToNull 및 updatePhotoMemoToNull 쿼리에 photoImage.deletedAt.isNull 조건이 추가되어, 삭제되지 않은 사진에 대해서만 업데이트가 적용되도록 수정되었습니다.
  • src/main/resources/db/migration/V12__add_soft_delete_to_photo_image.sql
    • TB_PHOTO_IMAGE 테이블에 deleted_at 컬럼이 추가되었습니다.
    • 기존 uk_photo_image_media_id 유니크 제약조건이 제거되었습니다.
    • deleted_at IS NULL인 레코드에 대해서만 media_id의 유니크를 보장하는 부분 유니크 인덱스 uk_photo_image_media_id가 생성되었습니다.
Activity
  • 이 Pull Request에 대한 활동 내역은 제공되지 않았습니다.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@github-actions
Copy link

Code Format Check ✅ PASSED

Spotless Check: success

✨ All code formatting checks passed!


Pushed by: @Darren4641, Action: pull_request

@github-actions
Copy link

Test ✅ PASSED

Test Result: success

✨ All tests passed!


Pushed by: @Darren4641, Action: pull_request

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

데이터 보존 및 추적을 위해 Hard Delete에서 Soft Delete로 전환하는 작업을 전반적으로 잘 수행하셨습니다. 특히 Hibernate의 @SQLRestriction을 활용하여 조회 시 삭제된 데이터를 자동으로 필터링하고, DB 레벨에서 Partial Unique Index를 통해 Soft Delete된 레코드와의 충돌을 방지한 점이 인상적입니다. 다만, QueryDSL의 update 쿼리에서 수동으로 필터를 추가한 것과 달리 일부 select 쿼리나 로거 사용 부분에서 개선의 여지가 보입니다.

.update(photoImage)
.setNull(photoImage.folderId)
.where(photoImage.userId.eq(userId), photoImage.folderId.`in`(folderIds))
.where(photoImage.userId.eq(userId), photoImage.folderId.`in`(folderIds), photoImage.deletedAt.isNull)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

QueryDSL의 update 쿼리는 Hibernate의 @SQLRestriction 필터를 자동으로 적용하지 않으므로, 여기서 deletedAt.isNull 조건을 명시적으로 추가하신 것은 매우 적절합니다. 다만, folderIdnull로 변경되는 Soft Delete 특성상 photoImage.folderId.in(folderIds) 조건만으로도 이미 삭제된 데이터는 제외될 것으로 보입니다. 하지만 안전성을 위해 유지하는 것도 나쁘지 않습니다.

@Darren4641 Darren4641 merged commit e4f804f into staging Feb 24, 2026
2 checks passed
@Darren4641 Darren4641 deleted the fix/#150 branch February 24, 2026 13:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix: media 삭제 시 Soft Delete 로 변경

1 participant