feat(expiry): #5 만료 추천 (v0.2.3 3/7) #15

Merged
altair823 merged 12 commits from feat/v023-expiry into main 2026-05-01 15:52:40 +00:00

12 Commits

Author SHA1 Message Date
altair823
d672ec3afa fix(expiry): review round 1 — minor/nit 6건 일괄 (#5 v0.2.3)
m1 — spec §5.3 dialog 버튼 순서를 impl 패턴 (`['옮기기','취소'], defaultId=1, cancelId=1`) 으로 보정. project 의 permanentDelete/emptyTrash 와 일관 (위험 액션은 default focus = 취소).

m2 — telemetryEvents.test.ts 에 `expired_batch_trash` 의 extra-field 회귀 가드 추가. `expired_banner_shown` 과 대칭 (privacy invariant).

m3 — ExpiryBanner.InnerProps.candidates 타입을 narrow subset → `Note` 로 통일. v0.2.4 에서 Note 타입 진화 시 silent drift 방지.

m4 — onTrash 의 `void trashExpiredBatch(ids)` → `.catch((e) => console.warn(...))` 로 Promise rejection 가시화. (project-wide error toast 도입은 v0.2.4 backlog 유지)

n1 — 24h+ 앱 켜둔 상태에서 snooze 자동 만료. `setTimeout(snoozeUntilMs - now)` 으로 자정 KST 시점에 force re-render. (refreshMeta trigger 의존 제거)

n2 — CaptureService.listExpired 의 dedup signature reset on empty 의도 주석 1줄. future maintainer 위해.

n3 (`as any[]`) 은 repo 전체 hydrate 패턴 — 단독 fix 시 inconsistency. v0.2.4 backlog #22 로 합산.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 00:47:58 +09:00
altair823
8a96d5279d chore(expiry): #5 closure — gates verified + roadmap mark complete
- typecheck 0 errors
- 단위 326/326 (T1~T7 누적 26 신규)
- e2e 1/1
- spec §3 IPC 채널명 inbox:trashBatch → inbox:trashExpiredBatch 보정 (의미 명확화)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 00:25:15 +09:00
altair823
7cbbd4dc97 feat(expiry): ExpiryBanner component + App.tsx mount (#5 v0.2.3) 2026-05-02 00:22:38 +09:00
altair823
b7205597db feat(expiry): zustand store extension — expiredCandidates + snooze (#5 v0.2.3)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 00:18:11 +09:00
altair823
749235f65d feat(expiry): CaptureService listExpired/trashExpiredBatch + IPC 2 channels (#5 v0.2.3) 2026-05-02 00:13:49 +09:00
altair823
f76ca06d9e feat(expiry): telemetry 2 events — expired_banner_shown / expired_batch_trash (#5 v0.2.3) 2026-05-02 00:08:44 +09:00
altair823
fec80361dd feat(expiry): NoteRepository.trashBatch atomic (#5 v0.2.3) 2026-05-02 00:01:03 +09:00
altair823
00423fb235 feat(expiry): NoteRepository.findExpiredCandidates (#5 v0.2.3) 2026-05-01 23:57:53 +09:00
altair823
0a9dab4a7f feat(expiry): KST util — todayInKstString + nextKstMidnightMs (#5 v0.2.3) 2026-05-01 23:53:20 +09:00
altair823
a5e6859ac9 docs(plan): v0.2.3 #5 만료 추천 구현 계획
8 task TDD 분할 + 단위 26개 (spec §8 의 16개 충족 + 6 over):
- T1 KST util (todayInKstString + nextKstMidnightMs)
- T2 NoteRepository.findExpiredCandidates
- T3 NoteRepository.trashBatch (atomic)
- T4 telemetry 2 events + stats.md 만료 trash ratio
- T5 CaptureService listExpired/trashExpiredBatch + IPC 2채널 + preload
- T6 zustand store 확장
- T7 ExpiryBanner 컴포넌트 + App.tsx mount
- T8 closure

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 23:30:48 +09:00
altair823
c45e613b31 docs(spec): #5 expiry — move dedup to main, keep IPC at 2 channels
§6.2 의 expired_banner_shown signature dedup 위치를 zustand store(renderer)
→ CaptureService(main) 로 변경. 결과: 신규 IPC 채널 1개 추가 회피.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 23:25:12 +09:00
altair823
4c2769fd82 docs(spec): v0.2.3 #5 만료 추천 design
mini-brainstorm 결과 5개 결정 박힘:
- Q1=B due_date_edited_by_user 필터 없음 (AI + 수동 모두)
- Q2=A 만료만 (D-7 임박 v0.2.4)
- Q3=C unchecked default + 전체선택 토글 (데이터 안전)
- Q4=B PendingBanner 아래 (system → progress → actionable)
- Q5=A 후보 0건 / snooze 시 collapse (PendingBanner 패턴)

T1-T10 작업 순서 + 단위 ≥ 16개 + IPC 2채널 + telemetry 2이벤트.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 23:22:38 +09:00