Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,11 @@ public List<CoverLetterResult> list(Long userId) {
public void delete(Long userId, Long coverLetterId) {
CoverLetter coverLetter = loadOwned(userId, coverLetterId);
coverLetter.markDeleted();
// 분석 결과 cascade — document 도메인 listener 가 받아 AnalyzedDocument soft delete (도메인 cycle 회피).
// 문항 원문 즉시 파기 — 자소서 본문은 S3 가 아니라 이 행 안에 살아서, cascade 파기
// (분석 마크다운·임베딩)만으로는 "지웠는데 남아 있는" 상태가 된다.
coverLetter.purgeItems();
// 분석 결과 cascade — document 도메인 listener 가 받아 AnalyzedDocument soft delete
// + 분석 내용물 파기 (도메인 cycle 회피).
events.publishEvent(new CoverLetterDeletedEvent(userId, coverLetterId));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,20 @@ public void markFailed() {
this.status = CoverLetterStatus.FAILED;
}

/**
* 문항 원문을 파기한다(빈 배열로).
*
* <p>자소서 본문은 지원동기·성장과정 같은 지극히 개인적인 서술이고, 다른 자료와 달리
* S3 가 아니라 <b>이 행 안에</b> 산다. 삭제 시 분석 마크다운·임베딩은 cascade 가
* 파기하지만(#219) 원문은 여기서 비워야 한다 — 삭제 후에는 아무도 읽지 않는다
* (분석은 생성 시점에 본문을 메시지에 인라인한다).
*
* <p>컬럼이 NOT NULL DEFAULT '[]' 라 제약 변경 없이 빈 배열로 비운다.
*/
public void purgeItems() {
this.items = "[]";
}

public void markDeleted() {
this.deleted = true;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
-- 자소서 원문(items)은 다른 자료와 달리 S3 가 아니라 행 안에 산다. 삭제 시 분석
-- 마크다운·임베딩은 파기되지만(#219 cascade) 원문은 남았다. 이 릴리스부터 삭제 시
-- 함께 비우는데, 그 전에 지운 자소서는 삭제 이벤트가 다시 나지 않으므로 백필한다
-- (V31 탈퇴자 토큰 · #223 과거 삭제분 S3 객체와 같은 종류 — 새 규칙의 소급 적용).
UPDATE cover_letters
SET items = '[]'::jsonb
WHERE is_deleted = TRUE
AND items <> '[]'::jsonb;
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,21 @@ private User user() {
ReflectionTestUtils.setField(u, "id", 1L);
return u;
}

// 자소서 본문은 S3 가 아니라 행 안에 산다 — 삭제 시 soft delete 만 하면 지원동기·
// 성장과정 원문이 그대로 남는다. cascade(분석물)와 별개로 원문 자체를 비워야 한다.
@Test
void delete_purgesInlineItemsAlongWithSoftDelete() {
User user = user();
CoverLetter coverLetter = CoverLetter.create(
user, "공채 자소서", "[{\"question\":\"지원동기\",\"answer\":\"개인적 서술\"}]");
ReflectionTestUtils.setField(coverLetter, "id", 7L);
when(coverLetterRepository.findByIdAndUser_IdAndDeletedFalse(7L, 1L))
.thenReturn(Optional.of(coverLetter));

service.delete(1L, 7L);

assertThat(coverLetter.isDeleted()).isTrue();
assertThat(coverLetter.getItems()).isEqualTo("[]");
}
}
3 changes: 3 additions & 0 deletions docs/security.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,9 @@ public class GithubTokenCipher {

임베딩 청크는 DB 안에서 끝나므로 과거 삭제분도 V32 가 한 번에 정리한다.

자소서는 원문이 S3 가 아니라 **행 안에**(`cover_letters.items`) 산다 — 삭제 시 원문을 같은
트랜잭션에서 빈 배열로 비우고(`CoverLetter.purgeItems`), 과거 삭제분은 V34 가 백필한다.

> 회원 탈퇴 시 사용자의 모든 자료를 일괄 파기하는 것은 별건이다(§5.3 의 hard delete, Phase 2).

### 5.2 민감정보
Expand Down
Loading