Initial Commit

This commit is contained in:
2026-09-16 17:22:14 +09:00
commit 858ee9e9da
335 changed files with 123898 additions and 0 deletions
+297
View File
@@ -0,0 +1,297 @@
# Tasks: Tauri 기준 데스크톱 앱 전환
**Input**: `specs/004-tauri-shell/` 의 설계 문서 (spec.md, plan.md, research.md, data-model.md, contracts/, quickstart.md)
**Tests**: 포함한다. CLAUDE.md §1 이 TDD(RED→GREEN)를 파이프라인에 박아뒀고, research R12 가 "자동으로 될 것만 자동으로" 기준으로 대상을 이미 갈라놨다.
**Organization**: 유저스토리 우선순위대로 쌓는다. US1~US5는 전부 필수이며 중간 중단 경로는 없다.
## Format: `[ID] [P?] [Story] 설명`
- **[P]**: 병렬 가능 (파일 서로 안 겹치고 선행 task 에 안 물림)
- **[Story]**: 어느 유저스토리 소속인지 (US1~US5)
- 파일 경로는 repo 루트 기준
---
## Phase 1: Setup (환경·선행 문서)
**목적**: 첫 Rust 코드보다 먼저 있어야 하는 것들. US1 은 T004 만 있으면 시작 가능.
- [x] T001 rust 툴체인 설치·확인 — `rustup` + MSVC 타깃(`x86_64-pc-windows-msvc`) + VS Build Tools/Windows SDK. `cargo --version`·`rustc --version`·`cl.exe` 존재가 통과 조건 (research R1, quickstart §사전준비)
**2026-08-15 완료.** rustc/cargo 1.97.1, 기본 툴체인 `stable-x86_64-pc-windows-msvc`. 별도 Build Tools 를 새로 받지 않고 **이미 있던 VS 2026 Community 에 컴포넌트만 추가**(`VC.Tools.x86.x64` + `Windows11SDK.26100`) — MSVC 14.51.36231, SDK 10.0.26100.0. `rustc` 로 실제 링크까지 통과 확인
- [x] T002 [P] `4_rust_tauri/docs-lib/README.md` 신규 — 카탈로그 (CLAUDE.md §3 양식)
- [x] T003 [P] `4_rust_tauri/docs-lib/tauri-v2.md` 신규 — 실제 쓸 API 표면 박제: 플러그인 4종 init(`global-shortcut`/`single-instance`/`window-state`/`opener`), `TrayIconBuilder`, `Menu`/`CheckMenuItem`, `WebviewWindow`(show/hide/set_focus/set_always_on_top/start_dragging/is_visible), `#[tauri::command]`+`State`, `app.emit`, `app.path().app_local_data_dir()`, capabilities 권한 이름. **R11 의 미확정(Tauri v2 에서 PerMonitorV2 DPI 인지를 어디서 켜는가)도 여기서 확인해 적는다** (research R3)
**2026-08-15 완료.** 공식 가이드 예제를 안 믿고 `cargo fetch` 로 받은 **실제 crate 소스**에서 뽑음(가이드 안에 2인자/3인자 예제가 둘 다 있어서 근거로 못 씀). 버전 박제: tauri 2.11.5 / global-shortcut 2.3.2 / single-instance 2.4.3 / window-state 2.4.1 / tao 0.35.3. 원문은 `tauri-v2-llms-full.md`(2.4MB) 로 같이 받아둠
- [x] T004 [P] `2_frontend/docs-lib/tauri-api.md` 신규 — 프론트가 쓸 `invoke`/`listen` 표면만 박제 (+ `2_frontend/docs-lib/README.md` 카탈로그에 한 줄 추가)
**2026-08-15 완료.** `node_modules/@tauri-apps/api/` 의 실제 `.d.ts`·`.js` 에서 뽑음 (2.11.1)
- [x] T005 `2_frontend/package.json``@tauri-apps/api` v2 추가 후 `npm install` — 이 기능의 유일한 신규 프론트 의존성 (plan Complexity Tracking 1번)
**2026-08-15 완료.** `^2.11.1`
**Checkpoint**: T003 없이 Rust 코드를 쓰지 않는다. T005 없이 US1 을 시작하지 않는다.
### 📌 Phase 1 이 뒤 단계에 남긴 것 (docs-lib 만들며 새로 확인된 사실)
문서 만들다 **계획을 바꿔야 하는 것 3건**이 나왔다. 해당 task 본문에도 반영해뒀다.
| 무엇 | 어디에 영향 | 요약 |
|---|---|---|
| **DPI 인지는 이미 켜져 있다** | T049 | `tao` 가 이벤트 루프 만들 때 `SetProcessDpiAwarenessContext(PER_MONITOR_AWARE_V2)` 를 무조건 부름. R11 의 "매니페스트 넣기"는 **할 일이 없어졌다** — 확인만 하고 넘어감 |
| **호스트 판별식을 바꿔야 한다** | T012·T015 | `"__TAURI_INTERNALS__" in window` 는 틀린다. 공식 `clearMocks()`**속성만 지우고 빈 객체를 남겨서** 정리 후에도 계속 true → 브라우저 모드 테스트가 tauri 로 오판됨. `typeof window.__TAURI_INTERNALS__?.invoke === "function"` 으로 잰다 |
| **window-state 기본 플래그가 함정** | T030 | `StateFlags` 기본값이 `all()` 이라 `VISIBLE`·`DECORATIONS` 까지 저장·복원한다. 트레이 상주 + 프레임리스 앱엔 안 맞음 → `SIZE \| POSITION` 만 켠다 |
**공식 테스트 mock 이 있다는 것도 알아냈다**`@tauri-apps/api/mocks``mockIPC`/`clearMocks`, `shouldMockEvents: true``listen`/`emit` 까지 mock 됨. T012~T014 는 이걸 쓴다 (직접 흉내낼 필요 없음).
---
## Phase 2: Foundational (Tauri 빌드 베이스라인)
**목적**: `4_rust_tauri`가 컴파일되고 현재 `2_frontend` 화면을 띄우는 기준 앱 베이스라인 만들기.
**범위 주의**: 여기서 제품명·identifier·빌드 경로를 기준 앱 값으로 확정한다. 손으로 쓴 Rust와 설정은 컴파일 검증 0줄이므로 전부 다시 본다.
**⚠️ 전제**: 손으로 쓴 `src-tauri/src/**/*.rs`·`Cargo.toml`·`tauri.conf.json` 은 **컴파일 검증 0줄**이다. "있으니 맞겠지"로 넘기지 말고 전부 다시 본다 (research R2).
- [x] T006 `4_rust_tauri/src-tauri/src/main.rs`의 lib 이름이 `codeassist_tauri_lib::run()`으로 `[lib] name`과 일치하는지 확인
- [x] T007 `4_rust_tauri/src-tauri/Cargo.toml` 재검증 — Tauri 2의 `tray-icon`·`image-png`, global-shortcut·single-instance·window-state, serde·serde_json만 포함. `rusqlite`·`windows`는 필요한 스토리까지 미룸
- [x] T008 `4_rust_tauri/src-tauri/tauri.conf.json``productName`/창 제목=`CodeAssist`, `identifier`=`com.codeassist.app`, devUrl·frontendDist·프레임리스 설정 확인
- [x] T009 `4_rust_tauri/src-tauri/capabilities/default.json` — 프론트가 우리 command만 invoke하므로 `core:default`면 listen/emit까지 충분함을 docs-lib 기준으로 확인
- [x] T010 `4_rust_tauri/package.json` — Tauri CLI 스크립트만 있고 프론트 dev/build는 `tauri.conf.json``2_frontend`에서 실행함을 확인
- [x] T011 `cd 4_rust_tauri && npm run tauri dev` 첫 통과 — Rust dev 빌드 완료, 제목 `CodeAssist` 창에서 `2_frontend` 로그인 화면 렌더 확인
**Checkpoint**: 여기까지 되면 실제 Tauri bridge와 데스크톱 기능을 연결할 수 있다.
---
## Phase 3: User Story 1 - 프론트 한 벌로 Tauri와 브라우저에서 뜬다 (Priority: P1) 🎯 MVP
**Goal**: `2_frontend`가 실행 시점에 Tauri·legacy·브라우저를 판별해 맞는 통로를 고른다. 화면 소비자는 바꾸지 않는다.
**Independent Test**: Tauri 앱에서 실제 invoke/listen 왕복이 되고, 브라우저에서는 화면이 깨지지 않으며, legacy adapter 자동 검사가 통과하면 완료.
**위험**: 기존 브릿지 테스트의 WebView2 mock을 transport mock으로 바꾸면서 실제 Tauri 경로가 아니라 mock끼리만 맞을 수 있다. 자동 검사 뒤 실제 Tauri 앱을 반드시 실행한다.
### Tests for User Story 1 ⚠️ 먼저 쓰고 RED 확인
> transport는 사용할 때 호스트를 판별한다. 테스트 전용 reset API는 만들지 않는다. Windows Tauri도 WebView2를 쓸 수 있으므로 판별 순서는 `tauri` → `webview2` → `browser`다.
- [x] T012 [P] [US1] `2_frontend/src/lib/bridge/transport.test.ts` 신규 — 호스트 3종 판별(`tauri``webview2``browser`), 브라우저 단방향 no-op·응답 요청 즉시 reject를 먼저 작성하고 RED 확인. Tauri는 `@tauri-apps/api/mocks``mockIPC`/`clearMocks` 사용
- [x] T013 [P] [US1] `2_frontend/src/lib/bridge/bridgeNavigate.test.ts``chrome.webview` mock을 transport 경유 mock으로 교체. 기존 분기·CustomEvent 기대값은 유지
- [x] T014 [P] [US1] `2_frontend/src/lib/bridge/snippetBridge.test.ts``2_frontend/src/features/snippets/api/snippets.api.test.ts`의 mock을 transport 경유로 교체. 소비자 소스는 무변경
### Implementation for User Story 1
- [x] T015 [US1] `2_frontend/src/lib/bridge/transport.ts` 신규 — `HostKind` 판별 + 전송수단 3종(tauri: `invoke`+`listen`, webview2: `postMessage`+`addEventListener`, browser: no-op·reject). Tauri 판별식은 `typeof window.__TAURI_INTERNALS__?.invoke === "function"`이며 호출 시점에 판별
- [x] T016 [US1] `2_frontend/src/lib/bridge/webviewBridge.ts` 를 transport 위로 얇게 — `isWebView`/`hideWindow`/`pasteToApp`/`reportRoute`/`startWindowDrag` **export 시그니처 불변**, 속만 transport 호출로 교체 (`isWebView` 는 "데스크톱 껍데기 안인가"로 의미 확장)
- [x] T017 [US1] `2_frontend/src/lib/bridge/snippetBridge.ts` 축소 — `reqSeq`/`pending` Map/`ensureListener`**지우지 말고 `transport.ts` 의 webview2 구현 안으로 옮긴다**(기존 껍데기 경로엔 그대로 필요). 여기엔 `request(type, payload)` 만 남김 (research R6)
- [x] T018 [US1] `2_frontend/src/lib/bridge/bridgeNavigate.ts` — 리스너 부착만 transport 로 교체. `paste.target`/`capture.image`/`navigate` 분기와 `CustomEvent` dispatch **본문은 한 줄도 안 바꾼다** (research R5 — 이게 diff 를 가장 크게 줄이는 한 수).
**transport 가 흡수해야 하는 차이 2개** (`docs-lib/tauri-api.md` §2): ① Tauri 는 페이로드가 `Event<T>` 로 한 겹 싸여 오므로 **`e.payload` 를 벗겨서** 넘겨야 분기 본문이 그대로 산다 ② `listen``Promise<UnlistenFn>` 이라 **async**`initBridgeNavigate()` 를 async 로 바꾸면 호출부가 바뀌어 SC-001 위반이므로 transport 안에서 Promise 를 삼키고 밖은 동기 유지. 붙기 전 도착분은 기존 `lastPasteTarget` 스냅샷·`pendingCaptureImage` read-once 가 이미 막아줌
- [x] T019 [US1] `transport.ts` 에 타입명→커맨드명 매핑 반영 — `snippets.recordUse``snippets_record_use` 기계 변환 + **예외 1건** `route.changed``report_route` (contracts/transport-mapping.md §1)
- [x] T020 [US1] 미구현 응답 규칙 — tauri 경로에서 `invoke` reject 는 한글 메시지 그대로 `Error` 로 올라가 react-query `onError`→sonner 로 흐르는지 확인. 빈 값(`[]`,`null`)으로 성공을 흉내내지 않는다 (FR-023, transport-mapping §3)
### 검증 for User Story 1
- [x] T021 [US1] 소비자 diff 0줄 확인 — `2_frontend/src/lib/bridge/`와 관련 테스트 바깥의 화면 소비자 소스에 변경이 없는지 확인
- [x] T022 [US1] 자동 검사 — `cd 2_frontend && npm run format && npm run lint && npm run test && npm run build` 전부 통과
- [x] T023 [US1] 브라우저 — `npm run dev` 후 챗봇 화면, 콘솔 오류 0, 데스크톱 전용 붙여넣기 버튼 숨김, `/snippet`의 "데스크톱 전용" 오류 확인
- [x] T024 [US1] 실제 Tauri 앱 — `npm run tauri dev`에서 화면→Rust `invoke`와 Rust→화면 `bridge` 이벤트를 각각 한 번 이상 실제 동작으로 확인
- [x] T025 [US1] `specs/004-tauri-shell/stage-1.md` 기록 — 한 일 / 검증 결과 / 다음
**Checkpoint**: Tauri와 브라우저가 같은 화면 한 벌을 쓰고 실제 bridge 왕복이 된다.
---
## Phase 4: User Story 2 - Tauri 앱을 단축키와 트레이로 쓴다 (Priority: P2)
**Goal**: Tauri 앱이 표준 단축키·트레이·창 상태 복원·단일 인스턴스를 제공한다.
**Independent Test**: Tauri 앱 하나에서 `Ctrl+Shift+7/8/9`, 챗봇 토글, 트레이 메뉴, 창 상태 복원, 두 번 실행을 확인한다.
**의존**: Phase 2 + Phase 3. 챗봇 토글이 `route.changed` 보고에 물린다.
### Tests for User Story 2
- [x] T026 [P] [US2] `4_rust_tauri/src-tauri/src/lib.rs` 의 챗봇 토글 규칙을 순수 함수로 뽑고 `cargo test` 작성 — "창 보이는 중 AND current 가 `/snippet` 아님 → 숨김, 그 외 → 띄우고 `lastSnap` 으로" + `lastSnap` 갱신 규칙(`/snippet` 으로 시작 안 하면 같이 갱신) (data-model §4). 창·트레이·핫키는 자동 테스트 대상 아님 (research R12)
### Implementation for User Story 2
- [x] T027 [P] [US2] `4_rust_tauri/src-tauri/src/shell/window.rs` 재검증 — show/hide/set_focus/set_always_on_top/start_dragging/is_visible. CodeAssist 를 하나도 모르는 층으로 유지 (plan Structure Decision)
- [x] T028 [P] [US2] `4_rust_tauri/src-tauri/src/shell/hotkey.rs` 재검증 — `Ctrl+Shift+7/8/9` 등록. 등록 실패해도 앱을 죽이지 않고 어느 조합이 실패했는지 알림
- [x] T029 [P] [US2] `4_rust_tauri/src-tauri/src/shell/tray.rs` 재검증 — 트레이 상주 + 열기/항상 위에 고정/종료
- [x] T030 [US2] `4_rust_tauri/src-tauri/src/lib.rs`에 window-state·single-instance 배선 — `.with_state_flags(StateFlags::SIZE | StateFlags::POSITION)`만 사용. 저장 경로는 `%LocalAppData%\com.codeassist.app\`
- [x] T031 [US2] 핀(항상 위) 상태만 별도 저장/복원 — `app_local_data_dir()` 아래 단일 파일. window-state 플러그인이 always-on-top 은 안 봄 (research R8)
- [x] T032 [US2] `4_rust_tauri/src-tauri/src/lib.rs` 조립 — 어느 핫키가 무엇을 하는지(7=스니펫, 8=챗봇 토글, 9=캡쳐)와 `Routes{current,lastSnap}` 상태를 **여기에만** 모은다. `shell::init(config)` 통합 진입점은 **만들지 않는다** (plan Structure Decision — 구현 하나짜리 추상화 금지)
- [x] T033 [US2] `4_rust_tauri/src-tauri/src/bridge/commands.rs``window_hide`/`window_drag`/`report_route` 구현 (transport-mapping §1)
- [x] T034 [US2] `4_rust_tauri/src-tauri/src/bridge/mod.rs` — 푸시를 **단일 이벤트 `"bridge"` 에 `{type, ...}` 그대로** 실어 `app.emit`. 우선 `navigate` 부터 (research R5, transport-mapping §2)
- [x] T035 [US2] 아직 안 만든 커맨드는 한글 "아직 안 됨" 으로 **reject** — 빈 값으로 성공 흉내 금지 (FR-023). 이 시점엔 `paste_code`·`snippets_*` 가 대상
- [x] T036 [US2] 창은 제목표시줄 없이 뜨고 헤더 끌기로 이동 — 프론트의 `window.drag``start_dragging` 까지 도달하는지 (FR-012)
### 검증 for User Story 2
- [x] T037 [US2] quickstart C 기본 앱 — `CodeAssist` 프레임리스 창, 현재 챗봇 화면, 트레이, 두 번 실행 시 기존 창 소환 확인
- [x] T038 [US2] quickstart C 표준 단축키 — `Ctrl+Shift+7`=스니펫, `Ctrl+Shift+8`=챗봇 토글, `Ctrl+Shift+9`=캡쳐만 반응하는지 확인
- [x] T039 [US2] quickstart C 창 상태 — 창 위치·크기·핀을 바꾸고 재실행해 복원되는지 확인
- [x] T040 [US2] `specs/004-tauri-shell/stage-2.md` 기록 — 한 일 / 검증 결과 / 다음
**Checkpoint**: CodeAssist를 Tauri 기준 앱으로 상시 켜두고 단축키로 부를 수 있다.
---
## Phase 5: User Story 3 - 코드가 직전 앱에 붙는다 (Priority: P3)
**Goal**: 단축키로 창 불러 코드 고르면 **아까 쓰던 그 앱**에 들어간다.
**Independent Test**: 메모장·VS Code·창전환 느린 앱 각각에 여러 번 붙여넣어 성공률 세기.
- [ ] T041 [US3] `4_rust_tauri/src-tauri/Cargo.toml``windows` crate 추가 (Win32 직접 호출 — 플러그인 안 씀, research R10)
- [ ] T042 [US3] `4_rust_tauri/src-tauri/src/shell/paste.rs` 신규/재검증 — **순서를 그대로 지킨다**: ① 클립보드 적재 → ② **우리 창 숨기기 전에** `SetForegroundWindow` → ③ 짧게 대기 → ④ `Ctrl+V` 주입 → ⑤ 클립보드 **원복 안 함**. 참조 원본은 `3_windowsApp/CodeAssist.Shell/Platform/PasteService.cs` 의 "함정 박제" 주석 (research R10)
- [ ] T043 [US3] 대기시간을 **조정 가능한 값**으로 둔다 — .NET 의 80ms 로 시작. 물리 타이밍이라 환경 따라 다름 (research R10 "미해결로 남기는 것")
- [ ] T044 [US3] 붙여넣기 대상 스냅샷 — 창 소환 **직전**에 창 제목·프로세스명을 **값으로 복사**해 보관(창이 나중에 닫혀도 표시는 남아야 함, data-model §3)
- [ ] T045 [US3] `bridge/mod.rs``{type:"paste.target", name, app}` 푸시 추가 → 프론트 배지에 직전 앱 이름 표시 (FR-015)
- [ ] T046 [US3] `bridge/commands.rs``paste_code` 구현 — 실패해도 **코드는 클립보드에 남긴다**(사용자가 직접 `Ctrl+V`, FR-014). T035 의 "아직 안 됨" reject 제거
- [ ] T047 [US3] quickstart C 수동 검증 — 메모장/VS Code/창전환 느린 업무용 앱 3종. **엉뚱한 곳에 붙거나 절반만 붙지 않아야 함**. 배지에 앱 이름 보이는지, 실패 시 클립보드에 남는지. 느린 앱에서 어긋나면 T043 값을 올려본다
- [ ] T048 [US3] `specs/004-tauri-shell/stage-3.md` 기록
**Checkpoint**: SC-004 도달 — 평소 흐름(소환→코드 고름→직전 앱에 붙음)을 처음부터 끝까지 해볼 수 있다.
**2026-09-11 통합 상태**: T041~T046 관련 구현은 main에 보존했고 Rust 컴파일·단위 검사를 통과함. T047의 실제 대상 앱 검증과 단계 인수는 아직 미완료. 스니펫 DB 읽기 구현도 main에서 가져왔지만 전체 CRUD 완료를 뜻하지 않음. 상세: `stage-main-integration.md`.
---
## Phase 6: User Story 4 - 화면 일부를 잘라 챗에 붙인다 (Priority: P4)
**Goal**: 단축키 → 영역 드래그 → 챗 입력창에 그림 첨부. **멀티모니터·다른 배율에서도 고른 영역과 결과가 일치.**
**Independent Test**: 배율 다른 모니터 두 대에서 각각·걸친 영역을 여러 번 캡쳐해 눈으로 대조.
- [x] T049 [US4] **PerMonitorV2 DPI 인지 — 확인만 하고 넘어간다.** ~~켜기~~ **할 일 없음이 T003 에서 확인됐다**: `tao` 0.35.3 이 이벤트 루프 생성 시(`event_loop.rs:190`) `become_dpi_aware()``SetProcessDpiAwarenessContext(PER_MONITOR_AWARE_V2)`**무조건** 부른다. .NET 판이 `app.manifest` 를 따로 넣어야 했던 것과 다름 (`4_rust_tauri/docs-lib/tauri-v2.md` §8).
**그래서 T054 에서 좌표가 어긋나면 원인이 DPI 설정이 아니다** — 논리↔물리 좌표 변환(T051) 쪽을 본다. R11 의 미확정 항목은 이걸로 닫힘
- [x] T050 [US4] `4_rust_tauri/src-tauri/src/shell/capture.rs` 신규/재검증 — 전체 가상 화면을 덮는 **투명·항상위 오버레이** 창 + 드래그 영역 선택
- [x] T051 [US4] 네이티브 오버레이의 물리 픽셀 좌표로 그 영역 잘라내기 — `windows` crate 의 `BitBlt` 직접 호출(.NET 판과 같은 API). Tauri의 PerMonitorV2 프로세스에서 Win32 가 주는 client/가상화면 좌표는 이미 물리 픽셀이라 별도 배율 곱을 하지 않음
- [x] T052 [US4] 취소 경로 — Esc, 포커스 이탈, 그리고 드래그 거의 없이 클릭만 하면 **조용히 취소**하고 화면 원복 (FR-018)
- [x] T053 [US4] `bridge/mod.rs` 의 기존 `{type:"capture.image", dataUrl}` 계약을 실제 캡쳐 완료 경로에 연결 — 프론트의 read-once 소비 경로(`consumePendingCaptureImage`)에 그대로 물림
- [ ] T054 [US4] quickstart D 수동 검증 — 배율 100%/150% 모니터·두 모니터에 걸친 영역·Esc·클릭만. 캡쳐물을 원본과 나란히 놓고 눈으로 대조(어긋나면 보통 일정 비율로 밀림) (SC-005)
- [x] T055 [US4] `specs/004-tauri-shell/stage-4.md` 기록
---
## Phase 7: User Story 5 - 기존 스니펫을 그대로 쓴다 (Priority: P5)
**Goal**: Tauri가 기존 CodeAssist 스니펫 DB를 그대로 읽고 쓴다.
**Independent Test**: 기존 데이터가 Tauri 팔레트에 보이고, 생성·수정·사용기록이 재실행 뒤에도 유지되면 통과.
**데이터 주의**: `%LocalAppData%\CodeAssist\snippets.db`의 스키마와 저널 모드를 바꾸지 않는다.
- [x] T056 [US5] `4_rust_tauri/src-tauri/Cargo.toml``rusqlite`(bundled feature) 추가
- [x] T057 [US5] 기존 `4_rust_tauri/src-tauri/src/bridge/snippets.rs` 확장 — `%LocalAppData%\CodeAssist\snippets.db`를 열고 없으면 기존 형식으로 생성. 참고 원본은 legacy `SnippetRepository.cs`
- [x] T058 [P] [US5] `cargo test` — 이름 중복과 빈 필수 필드 거부 테스트를 먼저 작성하고 RED 확인
- [x] T059 [US5] `bridge/commands.rs``snippets_list`/`snippets_create`/`snippets_update`/`snippets_delete`/`snippets_record_use` 구현
- [x] T060 [US5] 오류를 한글 메시지로 reject — 중복 이름·빈 필드·저장 실패가 프론트 `Error`→sonner로 흐르는지 확인
- [x] T061 [US5] `usageCount` +1 / `lastUsed` 갱신 — 재실행 뒤 자주 쓰는 순서에 반영
- [ ] T062 [US5] quickstart F — 기존 목록 표시 / 생성·수정 / 사용 횟수·순서 / 재실행 후 유지 / 빈 DB 첫 저장 확인
- [x] T063 [US5] `specs/004-tauri-shell/stage-5.md` 기록
**Checkpoint**: 기존 데이터를 잃지 않고 Tauri 앱을 평소 업무에 쓸 수 있다.
---
## Phase 8: Polish & 마무리 (기준 앱 전환)
**목적**: 미구현 경로를 없애고 제품 정의·문서·release 결과물을 Tauri 기준으로 맞춘다.
- [ ] T064 quickstart G 확인 — US1~US5 필수 요청 중 "아직 안 됨" reject가 남아 있지 않은지 실제 흐름으로 확인
- [ ] T065 [P] 제품 정의 갱신 — `CLAUDE.md`, `4_rust_tauri/README.md`, `4_rust_tauri/src-tauri/Cargo.toml`, `tauri.conf.json`에서 Tauri를 기준 앱, .NET을 참고용 legacy, 제품명을 `CodeAssist`로 통일
- [ ] T066 최종 검증 — `2_frontend`에서 format+lint+test+build, `4_rust_tauri`에서 cargo test + `npm run tauri build`. 기본 검증에 `3_windowsApp`을 요구하지 않음
- [ ] T067 `/code-review` + `superpowers:verification-before-completion`
- [ ] T068 `specs/004-tauri-shell/report.md` 작성 — 계획 대비 구현 결과, 자동 검사, Tauri 실제 실행, 붙여넣기·캡쳐·기존 데이터 검증 증거
- [ ] T069 사용자 최종 승인 → merge
---
## Dependencies & Execution Order
### Phase 의존
```
Phase 1 (Setup)
└── Phase 2 (Tauri 빌드 베이스라인)
└── Phase 3 (US1 transport)
└── Phase 4 (US2 창·단축키)
├── Phase 5 (US3 붙여넣기)
├── Phase 6 (US4 캡쳐)
└── Phase 7 (US5 스니펫)
└── Phase 8 (기준 앱 전환 마무리)
```
- **Phase 1**: 완료
- **Phase 2**: 모든 구현의 실행 베이스라인
- **Phase 3**: Phase 2 필요. 실제 Tauri bridge 왕복까지 확인
- **Phase 4**: Phase 3 필요. route 보고 위에 창 토글을 연결
- **Phase 5~7**: Phase 4 필요. 세 기능 모두 완료
- **Phase 8**: US1~US5 전부 끝난 뒤
### 스토리 간 의존
- **US1**: Tauri 빌드 베이스라인 필요
- **US2**: US1 필요
- **US3·US4·US5**: US2 필요. 셋은 서로 파일 일부가 겹치므로 task 순서대로 합침
### 병렬 기회
- **Phase 2**: T009·T010은 서로 다른 설정 파일
- **Phase 3 테스트**: T012·T013·T014는 테스트 파일이 겹치지 않음
- **Phase 4**: T027·T028·T029는 `shell/` 아래 독립 파일
- **Phase 8**: T065 문서·메타데이터 정리와 T064 실제 흐름 확인은 독립
### 스토리 안에서
- 테스트 먼저 쓰고 **RED 확인** 후 구현 (CLAUDE.md §1, superpowers:test-driven-development)
- 검증 task 는 그 스토리 구현이 다 끝난 뒤
- 스토리 하나 끝날 때마다 `stage-N.md`**승인 대기 없이 계속** (CLAUDE.md §1 7단계)
---
## Parallel Example: Phase 1 / Phase 4
```bash
# Phase 1 — 문서 3개 동시
Task: "4_rust_tauri/docs-lib/README.md 카탈로그 작성"
Task: "4_rust_tauri/docs-lib/tauri-v2.md — 쓸 API 표면 박제 (+ R11 DPI 설정 위치 확인)"
Task: "2_frontend/docs-lib/tauri-api.md — invoke/listen 표면 박제"
# Phase 4 — shell 3모듈 동시 (서로 독립·콜백도 다름)
Task: "shell/window.rs 재검증 — show/hide/focus/always-on-top/start_dragging"
Task: "shell/hotkey.rs 재검증 — Ctrl+Shift+7/8/9 + 등록 실패 알림"
Task: "shell/tray.rs 재검증 — 열기/항상위/종료"
```
---
## Implementation Strategy
### 첫 실행 가능 상태
1. Phase 2 — Tauri 창에 현재 프론트가 뜸
2. Phase 3 — 화면과 Tauri bridge가 실제 왕복
3. Phase 4 — 표준 단축키·트레이·창 상태가 동작
### 기능 완성 순서
1. US3 — 직전 앱 붙여넣기
2. US4 — 멀티모니터 화면 캡쳐
3. US5 — 기존 스니펫 데이터 읽기·쓰기
4. Phase 8 — 제품 정의·release·완료 보고
US1~US5는 전부 필수다. 비교 결과에 따른 중간 중단은 없다.
---
## Notes
- `3_windowsApp`은 참고용 legacy라 새 기능·기본 배포·완료 검증 대상이 아니다
- Tauri v2 API는 T003의 docs-lib을 보고 작성
- 기존 메시지 계약을 Tauri 사정으로 몰래 바꾸지 않음
- 자동 계측 장치는 만들지 않음
- 편집 후 `npm run format`, 완료 선언 전 lint+test+build (CLAUDE.md §4)
- 작업 스텝마다 `python z-my-docs/work-log/gen_worklog.py add "<한 일>"` (CLAUDE.md §5)