diff --git a/src/main/services/CaptureService.ts b/src/main/services/CaptureService.ts index d42188a..63e0b76 100644 --- a/src/main/services/CaptureService.ts +++ b/src/main/services/CaptureService.ts @@ -67,6 +67,9 @@ export class CaptureService { async deleteNote(noteId: string): Promise { // v0.2.3 #4: hard delete → soft delete. media 보존 (restore 시 필요). + // 이미 trash 인 노트는 telemetry emit skip — restore/trash ratio 오염 방지. + const note = this.repo.findById(noteId); + if (!note || note.deletedAt !== null) return; this.repo.trash(noteId, new Date().toISOString()); if (this.deps.telemetry) { await this.deps.telemetry.emit({ kind: 'trash', payload: { noteId } }).catch(() => {}); @@ -74,6 +77,9 @@ export class CaptureService { } async restoreNote(noteId: string): Promise { + // 이미 active 인 노트는 telemetry emit skip — restore/trash ratio 오염 방지. + const note = this.repo.findById(noteId); + if (!note || note.deletedAt === null) return; this.repo.restore(noteId); if (this.deps.telemetry) { await this.deps.telemetry.emit({ kind: 'restore', payload: { noteId } }).catch(() => {}); @@ -81,8 +87,14 @@ export class CaptureService { } async permanentDeleteNote(noteId: string): Promise { + // 존재하지 않는 노트는 emit skip — 메트릭 오염 방지. + const note = this.repo.findById(noteId); + if (!note) return; this.repo.permanentDelete(noteId); - await this.store.deleteNoteDirectory(noteId); + // best-effort media cleanup — disk 실패해도 telemetry/IPC 흐름은 그대로 (orphan dir + // 은 future janitor 가 정리). emptyTrash 와 동일 패턴. + try { await this.store.deleteNoteDirectory(noteId); } + catch { /* best-effort */ } if (this.deps.telemetry) { await this.deps.telemetry.emit({ kind: 'permanent_delete', payload: { noteId } }).catch(() => {}); }