altair823
e3f6c711a7
feat(v030): SyncTimer — 자동 주기 sync (settings 변경 시 reconfigure)
...
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-10 03:59:52 +09:00
altair823
87c18a4c2d
feat(v030): SyncSection + ConflictModal — Configure UI + 충돌 해결 UI
...
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-10 03:56:00 +09:00
altair823
9e48624495
feat(v030): sync IPC + preload (configure / test / list-conflicts / resolve / status)
...
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-10 03:49:10 +09:00
altair823
62e68dcfe7
feat(v030): settings.sync_repo_url + sync_auto_enabled + sync_interval_min
...
- zod schema 확장: sync_repo_url (nullable), sync_auto_enabled (default true), sync_interval_min (int >= 5, default 30)
- getter/setter 6개 추가 (기존 ai_enabled / onboarding_completed 패턴)
- setSyncIntervalMin 은 non-integer / < 5 reject
2026-05-10 03:44:09 +09:00
altair823
8436846657
feat(v030): SyncService.resolveConflict — local/remote 2 choice (both deferred)
2026-05-10 03:42:50 +09:00
altair823
33588b09df
feat(v030): SyncService.sync — 양방향 6단계 (export/commit/fetch/rebase/re-import/push) + conflict 반환
...
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-10 03:40:09 +09:00
altair823
9a1f0e269a
feat(v030): ImportService.applySyncFromDir + frontmatter status/dueDate/moveReason round-trip
...
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-10 03:33:48 +09:00
altair823
bbfd0cccda
feat(v030): NoteRepository.upsertFromSync — sync 전용 3 분기 upsert + single write path
...
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-10 03:27:49 +09:00
altair823
dba64c546f
feat(v030): GitClient — fetch/rebaseOnto/rebaseAbort/hasUncommittedChanges/listConflicts
...
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-10 03:23:00 +09:00
altair823
735d5494f2
fix(v0211): importNote 가 rebuildFtsTagsForNote 호출 (final review fix)
...
final code review 발견: F5 import path 가 note_tags INSERT 후 notes_fts.tags 갱신
안 해서 import 한 노트의 tag 가 keyword 검색에서 매칭 안 되는 회귀.
Cut C 의 importNote capture revision 누락 패턴과 동일 — single write path
정책 (Cut D 도입) 의 강제 검사 누락. importNote transaction 끝에서 호출하도록
fix + 회귀 test 2건 (insert path / fork path) 추가.
NoteRepository 안 note_tags INSERT path 는 updateAiResult / updateUserAiFields /
importNote 3곳, 셋 다 rebuildFtsTagsForNote 호출 보장 — invariant 회복.
2026-05-10 00:46:58 +09:00
altair823
9feb712c60
feat(v0211): ReviewView — 일/주/월 회고 + 헤더 dropdown 진입점
2026-05-10 00:39:36 +09:00
altair823
be125b8ace
feat(v0211): SearchBox + 헤더 mount + inbox 결과 렌더 분기
...
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-10 00:35:34 +09:00
altair823
f5e43133be
feat(v0211): store — search + reviewData state + actions + view enum 확장
...
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-10 00:31:53 +09:00
altair823
143684ce8a
feat(v0211): InboxApi.search + reviewAggregate (types + IPC + preload)
2026-05-10 00:27:43 +09:00
altair823
e60a2a23c8
feat(v0211): ftsHelpers + NoteRepository.search + reviewAggregate
...
- ftsHelpers: sanitizeFtsQuery (FTS5 special char escape) + computeCutoff (period → KST 자정)
- search: notes_fts MATCH + status filter + rank order + sanitize + 빈 query → []
- reviewAggregate: period 별 totalCount/recentNotes(50)/tagCounts(DESC)/dueProgress(passed/pending)
2026-05-10 00:24:24 +09:00
altair823
726d155d04
feat(v0211): rebuildFtsTagsForNote 헬퍼 + tags 변경 path 통합 (single write)
...
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-10 00:19:14 +09:00
altair823
19edeab7b1
feat(v0211): m007 migration — notes_fts FTS5 + trigger 3 + backfill
2026-05-10 00:16:35 +09:00
altair823
39b8d1e728
fix(v0210): importNote 가 capture revision 을 함께 INSERT (final review fix)
...
final code review 발견: F5 import 후 first user edit 시 import 시점 본문이
note_revisions 에 없어 history 에서 사라지는 회귀. importNote transaction 안
INSERT 추가 (createdAt = edited_at).
부수 작업: ImportNoteInput / importNote 의 "raw_text invariant guard" 주석을
v0.2.10 의 'fork-on-id-collision (sync determinism)' 정확한 의미로 갱신.
테스트 +2 — insert path / fork path 모두 capture revision 검증.
2026-05-09 20:59:37 +09:00
altair823
81fbacb21e
feat(v0210): RevisionHistoryModal — 이력 목록 + 회수 confirm + chain 보존
...
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-09 20:51:13 +09:00
altair823
ff1a015226
feat(v0210): NoteCard 원문 영역 편집 UI (textarea + 저장/취소 + updateRawText)
...
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-09 20:47:51 +09:00
altair823
b4c2d85b26
feat(v0210): inbox:{update-raw-text,list-revisions,restore-revision} IPC
2026-05-09 20:44:52 +09:00
altair823
7541d3c9e4
feat(v0210): NoteRepository revision API + NoteRevision type + InboxApi 시그니처
...
- updateRawText: raw_text 갱신 + user revision INSERT (atomic)
- listRevisions: edited_at DESC 순 hydrate
- restoreRevision: 옛 raw_text 를 새 user revision 으로 복원 (chain 보존)
- shared/types: NoteRevision + InboxApi 3 메서드 (updateRawText/listRevisions/restoreRevision)
- preload: 3 IPC stub 추가 (inbox:update-raw-text / inbox:list-revisions / inbox:restore-revision)
2026-05-09 20:41:17 +09:00
altair823
18deee5900
feat(v0210): NoteRepository.create 가 capture revision 을 함께 INSERT
...
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-09 20:36:09 +09:00
altair823
76c23457ee
feat(v0210): m006 migration — note_revisions 테이블 + capture backfill
...
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-09 20:32:32 +09:00
altair823
3fab44b466
chore(v029): final review minor cleanup — statusLabelWithParticle + initialTarget drop
...
- 한국어 조사 분기: '보관로/휴지통로/활성로' → '보관으로/휴지통으로/활성으로'
('완료로' 만 받침 X). 받침 jongseong 검사 helper.
- MoveStatusModal 의 unused initialTarget prop 제거 + caller (NoteCard) 정리
548/548 + typecheck 0 유지.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-09 16:46:55 +09:00
altair823
f42d03f70c
fix(v029): e2e smoke test 가 OnboardingWizard dismiss 후 inbox 진입
...
Task 11-12 의 wizard 가 첫 launch e2e 환경 차단 — "나중에 설정" 클릭으로
wizard dismiss 후 inbox 헤더/empty state 검증. 회귀 1/1 pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-09 16:42:14 +09:00
altair823
6070562358
feat(v029): NoteRepository.requeueDisabled + countByAiStatus + AiProviderSection 처리 버튼
2026-05-09 16:35:53 +09:00
altair823
c21fca57dd
feat(v029): AiProviderSection AI 자동 처리 토글 + OFF 시 안내문
2026-05-09 16:31:24 +09:00
altair823
49fbed050a
feat(v029): Banner + HealthChecker ai_enabled=false 시 비활성 (store ai_enabled field)
2026-05-09 16:25:24 +09:00
altair823
bc67dea2c8
feat(v029): NoteCard ai_status='disabled' fallback (raw_text 첫 줄 + summary/tags hide)
2026-05-09 16:25:17 +09:00
altair823
c65d6c810e
feat(v029): settings:* IPC (ai-enabled/onboarding-completed/get) + App.tsx 첫 launch 분기
2026-05-09 16:18:27 +09:00
altair823
d2c7bf1b39
feat(v029): OnboardingWizard 3 옵션 + 설치 가이드 link
2026-05-09 16:18:19 +09:00
altair823
d3150976d4
feat(v029): classifyStatus AI prompt + ai:classify-status 정식 구현 (Task 8 stub 대체)
...
- src/main/ai/classifyStatus.ts: prompt + JSON parse + 안전 fallback (archived).
- InferenceProvider.generateRaw 추가 (optional) + LocalOllamaProvider 구현
(Ollama /api/generate format:'json' 으로 raw JSON 응답 반환).
- inboxApi 의 ai:classify-status 핸들러를 stub 에서 정식 호출로 교체
(deps.repo.findById + deps.providerHolder.get + classifyStatus()).
- 신규 테스트 7건 (classifyStatus 단위) + IPC 3건 (note 없음 / AI throw / 정상).
- 회귀: 513 → 522 통과.
2026-05-09 16:09:33 +09:00
altair823
495c3d12a2
feat(v029): NoteCard 이동 메뉴 (status 4분기 dropdown)
...
Cut B Task 6 — 모든 view 공통 "이동 ▾" dropdown.
- 기존 휴지통/삭제 버튼 위치에 dropdown 추가 (모든 mode 공통)
- 현재 status 외 3개 목적지만 표시 (active 노트 → 완료/보관/휴지통)
- 메뉴 항목 클릭 → MoveStatusModal(initialTarget) 열기
- onMoved → local 상태 갱신 + onUpdated + (status 변경 시) onDeleted (list 제거)
- trash mode 의 영구 삭제/복구 버튼은 보존 (휴지통 단독 액션)
- 사용되지 않게 된 handleDelete 제거 (deleteNote 는 capture path 만)
- NoteCard 메뉴 단위 테스트 2건 (메뉴 표시 / 클릭 → modal → setStatus)
2026-05-09 16:03:40 +09:00
altair823
9eb7abc831
feat(v029): MoveStatusModal — 사유 입력 + 4 status 버튼 + AI 자동 분류 placeholder
...
Cut B Task 7 — NoteCard 메뉴가 여는 modal.
- 사유 textarea (선택) + 활성/완료/보관/휴지통 버튼 (옮기기 즉시 setStatus + onMoved)
- 빈 사유 → null reason 전달 (trim 처리)
- AI 자동 분류 버튼 → classifyStatus(stub) 호출 + 추천 표시 + 확정 버튼
- statusLabel helper export (NoteCard 메뉴에서 재사용)
- 4 단위 테스트 (render / 버튼 클릭 / AI 추천 흐름 / 빈 사유 null)
2026-05-09 16:00:51 +09:00
altair823
d4dce9bf34
feat(v029): inbox:set-status + ai:classify-status (stub) IPC
...
Cut B Task 8 — Modal/NoteCard 메뉴 path 의 IPC backbone.
- inbox:set-status: id + status + reason → repo.setStatus, invalid status 거부
- ai:classify-status: stub (Task 9 에서 Ollama provider 호출로 정식 구현)
- types.ts InboxApi.setStatus / classifyStatus 시그니처 + preload wire-up
- 4 단위 테스트 (valid/null reason/invalid status/stub shape)
2026-05-09 15:59:43 +09:00
altair823
92375edc31
feat(v029): 헤더 4탭 (Inbox/완료/보관/휴지통) + count badge
...
- App.tsx: 기존 2탭 (Inbox/휴지통) → 4탭. setView/counts 사용.
- onNavigate 도 setView 로 위임 (mirror state 동기 갱신).
- App.test: 4탭 렌더 + 클릭 → setView('completed') + aria-pressed (3 cases).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-09 15:51:59 +09:00
altair823
606ac94976
feat(v029): useInbox view enum + counts + setView + listByStatus/countsByStatus IPC
...
- store.ts: view enum ('inbox'|'completed'|'archived'|'trash'|'settings') + counts +
setView + loadByView. setShowSettings delegates to setView (mirror).
- types.ts + preload + ipc/inboxApi: listByStatus + countsByStatus IPC.
- NoteRepository.countByStatus 신규.
- store.view.test (5) + NoteRepository.countByStatus test (1).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-09 15:51:51 +09:00
altair823
fd839f6afe
feat(v029): ai_status 'disabled' enum + CaptureService ai_enabled 분기 (skip pending_jobs)
...
- AiStatus enum 'disabled' 추가 — settings.ai_enabled=false 일 때 새 노트의 초기 status.
- m005 migration: ai_status CHECK 제약을 ('pending','done','failed','disabled') 로 relax.
SQLite 가 ALTER COLUMN CHECK 미지원 → table recreate (notes_new INSERT SELECT DROP RENAME).
기존 인덱스 (idx_notes_created_at, idx_notes_ai_status, idx_notes_deleted_at) 재생성.
- SettingsService schema 에 ai_enabled / onboarding_completed (optional) 추가 +
isAiEnabled / setAiEnabled / isOnboardingCompleted / setOnboardingCompleted accessor.
기본 fallback (ai_enabled=true, onboarding_completed=false) — 기존 settings.json 무영향.
- NoteRepository.create 가 optional aiStatus 받도록 — 'pending' 외 값일 때 pending_jobs skip.
기존 caller (rawText 만 전달) 무영향.
- CaptureService deps 에 settings (좁은 AiEnabledSource 인터페이스) 추가.
submit() 가 ai_enabled 조회 → false 면 ai_status='disabled' insert + enqueue skip.
settings 미주입 시 기존 동작 (항상 enabled) 보존 — 테스트 케이스 무영향.
- main/index.ts wiring: settings: settingsSvc 주입.
Tests: 489 → 494 (CaptureService ai_enabled 2건 + m005 migration 3건). typecheck 0.
2026-05-09 15:43:01 +09:00
altair823
facbf54025
feat(v029): NoteRepository.setStatus + listByStatus + restoreNote 재구현
...
- NoteStatus 타입 추가 ('active'/'completed'/'archived'/'trashed')
- Note interface 에 status / statusChangedAt / moveReason 필드 추가
- setStatus(id, status, reason, now?) — 단일 transaction 으로 status + move_reason +
status_changed_at + updated_at 갱신. status='trashed' ↔ deleted_at 동기화
(backward compat). 그 외 status 는 deleted_at NULL.
- listByStatus(status, opts) — status 별 필터 + ORDER BY COALESCE(status_changed_at,
created_at) DESC. limit cap 200.
- hydrate 에 status / statusChangedAt / moveReason 매핑 추가. 미설정 row 는 'active' fallback.
- restoreNote 재구현 — setStatus('active', null) 로 status + deleted_at 동기화 +
v0.2.6 #10 round 1 fix (ai_status='failed'/'pending' → pending_jobs 재투입) 보존.
- 기존 테스트 fixture 5건에 새 필드 추가 (NoteCard, store.expired/recall/tagFilter/trash).
- 신규 테스트 11건 (setStatus + listByStatus + restoreNote 회귀).
2026-05-09 15:33:49 +09:00
altair823
06a1caf2bd
feat(v029): m004 마이그레이션 — status/status_changed_at/move_reason 컬럼
...
- notes 테이블 ADD COLUMN status (DEFAULT 'active'), status_changed_at, move_reason
- deleted_at != NULL 노트 → status='trashed' + status_changed_at=deleted_at 로 backfill
- index.ts registry 에 m004 추가 (runMigrations 자동 적용)
- migrations.test.ts user_version assertion 4 로 갱신
2026-05-09 15:27:15 +09:00
altair823
9cdea1531c
feat(v028): IPC inbox:open-media + path traversal + NoteCard cast 정리
2026-05-09 14:10:57 +09:00
altair823
f6bea623bf
feat(v028): NoteCard 이미지 <img> 렌더링 + onClick (openMedia 시그니처는 Task 3)
...
- 회색 placeholder div → <img src=inkling-media://...> 로 교체
- onClick 으로 inboxApi.openMedia(relPath) 호출 (현재는 InboxApi 인터페이스에 부재 → unknown cast 사용; Task 3 에서 정식 시그니처 추가 후 cast 제거 예정)
- alt='' 로 decorative 처리 (role=presentation), title 에 relPath 유지
- flex-wrap 추가 — 다수 이미지 시 줄바꿈
Tests: tests/unit/NoteCard.test.tsx 신규 2건 (img src 검증, click → openMedia 호출)
회귀: 468 → 470 pass
2026-05-09 14:06:21 +09:00
altair823
470384bf80
feat(v028): inkling-media:// custom protocol + path traversal 검사
...
- registerSchemesAsPrivileged: inkling-media 스킴을 secure + supportFetchAPI + stream 으로 등록 (whenReady 이전 호출 필수).
- registerInklingMediaProtocol: profileDir/media 하위 파일을 raw URL traversal (.., %2e%2e) 검사 + normalize 후 mediaRoot 봉쇄로 이중 검증 후 readFile.
- inferMime: png/jpg/jpeg/gif/webp → image/*, 그 외 → application/octet-stream.
- src/main/index.ts: 모듈 import 직후 registerSchemesAsPrivileged(), whenReady 안 paths 결정 직후 registerInklingMediaProtocol(paths.profileDir).
- tests/unit/inklingMedia.test.ts: 8 unit (5 inferMime + 3 handler — valid/403/404). vitest 의 new Request() 가 url 을 normalize 하므로 raw url 보존을 위해 minimal mock req 사용.
2026-05-09 14:00:50 +09:00
altair823
cffd1cec90
refactor(v027): OllamaSettingsModal 제거 + onOpenOllamaSettings 채널 cleanup
2026-05-07 02:35:43 +09:00
altair823
c5f2b8337a
test(v027): App/SettingsPage 테스트 mock 을 새 AutostartResponse 형태로 갱신
2026-05-07 02:32:06 +09:00
altair823
836828636c
feat(v027): AutostartSection 재등록 버튼
2026-05-07 02:30:29 +09:00
altair823
8a8652e87a
feat(v027): AutostartSection 진단 패널 + mismatch 경고
2026-05-07 02:29:17 +09:00
altair823
ce6c5ea756
feat(v027): settings:autostart-set 정식 + 채널 이름 통일
2026-05-07 02:28:17 +09:00
altair823
39bbf8f443
feat(v027): settings:autostart-state IPC 핸들러
2026-05-07 02:26:18 +09:00