fix(v026): #10 restoreNote 가 failed 노트 시 pending_jobs 재생성

restore 가 deleted_at = NULL 만 했음 → ai_status='failed' 인 노트는
영구 fail 상태로 복구. atomic transaction 안에서 ai_status='pending' reset
+ INSERT OR IGNORE INTO pending_jobs.

- failed → pending + pending_jobs 재처리 path 복구
- done 은 영향 X (이미 결과 있음)
- pending 은 pending_jobs 재생성 (defensive — trash 도중 jobs 미정상 상태 가능)
- 단위 +3 cases (failed/done/pending 각 케이스)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
altair823
2026-05-05 01:15:23 +09:00
parent 6fdb72101f
commit df27a9637e
2 changed files with 68 additions and 0 deletions

View File

@@ -410,6 +410,31 @@ export class NoteRepository {
.run(now, id);
}
restoreNote(id: string): void {
const tx = this.db.transaction(() => {
const before = this.db.prepare(`SELECT ai_status FROM notes WHERE id = ?`).get(id) as { ai_status: string } | undefined;
const now = new Date().toISOString();
this.db.prepare(`UPDATE notes SET deleted_at = NULL, updated_at = ? WHERE id = ?`).run(now, id);
// v0.2.6 #10 — failed 노트 restore 시 pending 으로 reset + pending_jobs 재생성
if (before?.ai_status === 'failed') {
this.db.prepare(
`UPDATE notes SET ai_status='pending', ai_error=NULL, updated_at=? WHERE id=?`
).run(now, id);
this.db.prepare(
`INSERT OR IGNORE INTO pending_jobs (note_id, attempts, next_run_at) VALUES (?, 0, ?)`
).run(id, now);
} else if (before?.ai_status === 'pending') {
// pending 인 채로 trash 됐다면 pending_jobs 도 미정상 상태일 수 있음 — 재생성 (idempotent)
this.db.prepare(
`INSERT OR IGNORE INTO pending_jobs (note_id, attempts, next_run_at) VALUES (?, 0, ?)`
).run(id, now);
}
// done 노트는 재처리 안 함 (이미 결과 있음)
});
tx();
}
permanentDelete(id: string): void {
this.db.prepare('DELETE FROM notes WHERE id=?').run(id);
}