Files
CODE_ASSISTANT/specs/004-tauri-shell/plan.md
T
2026-09-16 17:22:14 +09:00

11 KiB

Implementation Plan: Tauri 기준 데스크톱 앱 전환

Branch: 004-tauri-shell | Created: 2026-08-11 | Updated: 2026-09-09 | Spec: spec.md

Input: Feature specification from /specs/004-tauri-shell/spec.md

Summary

프론트(2_frontend)에 호스트 자동 감지 seam 하나를 두고, 기준 데스크톱 앱인 4_rust_tauri(Tauri v2)에 현재 화면·창 제어·붙여넣기·캡쳐·스니펫 저장을 전부 연결한다. 기존 3_windowsApp(.NET)은 삭제하지 않지만 참고용 legacy로만 남긴다.

핵심 설계는 "기존 브릿지 계약을 Tauri 수단으로 그대로 나른다"는 것. Rust→JS 푸시를 단일 이벤트 채널에 {type, ...} 그대로 실어보내면 프론트 bridgeNavigate.tstype 분기·CustomEvent dispatch 로직을 재사용할 수 있다. JS→Rust는 invoke의 Promise를 쓴다.

프론트 빌드·dist는 한 벌만 유지한다. Tauri 앱과 브라우저 개발 화면이 같은 결과물을 쓰고, 참고용 WebView2 adapter도 transport 안에 남긴다.

Technical Context

Language/Version: TypeScript 5.6 (프론트) / Rust 2021 edition (기준 데스크톱 앱)

Primary Dependencies:

  • 프론트 추가: @tauri-apps/api v2 — 유일한 신규 프론트 의존성
  • Rust: tauri 2 (tray-icon, image-png), tauri-plugin-global-shortcut, tauri-plugin-single-instance, tauri-plugin-window-state, rusqlite(bundled), windows(Win32 붙여넣기·캡쳐), serde
  • legacy .NET: 변경·새 의존성 없음

Storage:

  • 스니펫: %LocalAppData%\CodeAssist\snippets.db — 기존 사용자 데이터를 그대로 이어서 씀(FR-020)
  • 창 위치·크기: tauri-plugin-window-state 경로(%LocalAppData%\com.codeassist.app\)
  • 핀(항상 위) 상태: 위 폴더의 단일 파일. window-state 플러그인이 always-on-top은 저장 안 함

Testing:

  • 프론트: vitest — transport seam 단위 테스트 + 기존 브릿지 테스트 3개 mock 교체
  • Rust: cargo test — 순수 로직(챗봇 토글 규칙, 스니펫 검증)
  • 수동: Tauri 창·트레이·표준 단축키·붙여넣기·멀티모니터 캡쳐를 quickstart.md에서 실제 실행
  • 브라우저: 개발 화면과 데스크톱 기능 없는 경로를 실제 브라우저에서 확인

Target Platform: Windows 11. WebView2 런타임 사용

Project Type: Rust + Tauri 데스크톱 앱 + React SPA 프론트. .NET 앱은 참고용 legacy

Performance Goals: 별도 계측 목표 없음. 전역 단축키와 붙여넣기·캡쳐 흐름에서 사용자가 느끼는 멈춤이나 무반응이 없어야 함

Constraints:

  • Tauri가 표준 단축키 Ctrl+Shift+7/8/9를 소유함
  • legacy 앱과 동시 실행은 지원하지 않음
  • 프론트 소비자 코드 변경 0줄 (SC-001)
  • US1~US5 전부 완료하며 미구현 성공 응답을 남기지 않음
  • 기본 실행·배포·검증에서 .NET을 요구하지 않음 (SC-008)

Scale/Scope: 프론트 변경은 lib/bridge/ 4파일 + 관련 테스트로 국한. 데스크톱 기능은 4_rust_tauri 안에서 완성

Constitution Check

GATE: 구현 전에 통과했고 설계 갱신 후 다시 확인함.

.specify/memory/constitution.md는 빈 템플릿이다. CLAUDE.md 규칙을 게이트로 쓴다.

게이트 (출처) 판정 근거
재사용 우선 (CLAUDE.md 서두) 프론트는 기존 브릿지 계약·분기·소비자 코드를 재사용하고, Rust는 기존 스캐폴드와 검증된 .NET 동작 순서를 참고함
최소 diff / YAGNI (ponytail) 프론트 신규 파일은 transport 하나. 창 상태·단일 인스턴스·단축키는 공식 플러그인을 씀
API 호출은 @/lib/api/client (§4) 해당없음 서버 API를 건드리지 않음
서버 DTO는 src/types/api에만 (§4) 해당없음 브릿지 타입은 서버 DTO가 아님
주석·문서 한글 반말 (§0, §4) feature 문서와 새 주석을 한글로 유지
편집 후 format, 완료 전 lint+test+build (§4) 실행 시 tasks와 quickstart에 검증 순서를 둠
docs-lib 선참조 (§3) Tauri v2와 프론트 API 문서 박제 완료
plan 집은 하나 (§1) specs/004-tauri-shell/만 사용
버그는 systematic-debugging 먼저 (§1) 구현 중 실패가 나오면 적용

게이트 결과: 통과. 신규 프론트 의존성 1개는 Tauri 내부 프로토콜을 직접 흉내내지 않기 위한 정당한 편차다.

Project Structure

Documentation (this feature)

specs/004-tauri-shell/
├── plan.md              # 이 파일
├── research.md          # Phase 0 — 기술 결정 12건
├── data-model.md        # Phase 1 — 엔티티·상태
├── quickstart.md        # Phase 1 — Tauri 단독 실행·검증 시나리오
├── contracts/
│   └── transport-mapping.md   # Phase 1 — 기존 계약 → Tauri·legacy·브라우저 수단 매핑
├── checklists/
│   └── requirements.md  # spec 품질 체크리스트 (완료)
└── tasks.md             # Phase 2 — /speckit-tasks 가 만듦 (여기선 안 만듦)

기존 계약 문서는 여기 복사하지 않는다. 진실원천은 그대로 아래 둘이고, contracts/transport-mapping.md 는 그걸 가리키면서 껍데기별 수단만 대응시킨다.

  • specs/001-snippet-palette/contracts/bridge-messages.md
  • specs/002-capture-to-chat/contracts/bridge-capture.md

Source Code (repository root)

2_frontend/                              # Tauri와 브라우저가 공유. 빌드 한 벌
├── src/lib/bridge/
│   ├── transport.ts                     # [신규] 호스트 감지 + 전송수단 3종
│   ├── webviewBridge.ts                 # [수정] transport 위로 얇게. export 시그니처 불변
│   ├── snippetBridge.ts                 # [축소] 요청 표면만 남김
│   ├── bridgeNavigate.ts                # [수정] 리스너 부착만 교체, 분기 로직 그대로
│   └── *.test.ts                        # [수정] transport mock 사용
├── src/features/**                      # [무변경] 소비자 8곳 — SC-001
└── docs-lib/                            # Tauri 프론트 API 박제

3_windowsApp/                            # [무변경] 참고용 legacy
└── ...

4_rust_tauri/                            # 기준 데스크톱 앱
├── docs-lib/
│   ├── README.md                        # [신규] 카탈로그
│   └── tauri-v2.md                      # [신규] API 박제 — 첫 Rust 코드보다 먼저 (R8)
├── package.json                         # tauri CLI 만
└── src-tauri/
    ├── Cargo.toml
    ├── tauri.conf.json                  # 제품명 CodeAssist, devUrl → 2_frontend:15173, frontendDist → dist
    ├── capabilities/default.json
    ├── icons/                           # 생성기 산출물 — 유지
    └── src/
        ├── main.rs                      # 진입점
        ├── lib.rs                       # 조립부  ← .NET App.xaml.cs 대응
        ├── shell/                       # 프로젝트 무관 재사용 층  ← .NET CodeAssist.Shell 대응
        │   ├── mod.rs
        │   ├── hotkey.rs                # US2
        │   ├── tray.rs                  # US2
        │   ├── window.rs                # US2
        │   ├── paste.rs                 # US3
        │   └── capture.rs               # US4
        ├── bridge/                      # 계약 층
        │   ├── mod.rs                   # 푸시 타입 + emit
        │   └── commands.rs              # #[tauri::command] 모음
        └── storage/
            └── snippets.rs              # US5 — rusqlite, .NET 과 같은 DB 파일

Structure Decision:

기준 데스크톱 앱은 4_rust_tauri다. 그 안에서는 기존 .NET 구현에서 검증된 책임 경계를 참고하되 Tauri 플러그인과 Rust 코드에 맞게 최소로 유지한다.

  • shell/ = CodeAssist를 모르는 Windows/Tauri 동작 층
  • lib.rs = 어느 단축키가 무엇을 하는지와 화면 이동 규칙을 모으는 조립부
  • bridge/ = 기존 메시지 계약을 Tauri invoke/emit으로 나르는 층

통합 진입점(shell::init(config))은 만들지 않는다. 세 모듈이 서로 독립이고 콜백도 달라서 감싸면 넘겨주기만 하는 코드가 늘어난다.

Constitution Check — 설계 후 재확인 (Phase 1 완료 시점)

게이트 판정 설계로 확인된 것
재사용 우선 bridgeNavigate.ts의 분기·dispatch와 기존 메시지 계약을 그대로 쓰고, WebView2 요청 짝맞춤은 legacy adapter 안으로 이동함
최소 diff / YAGNI 프론트 신규 파일 1개. 구현 하나짜리 통합 진입점과 자동 계측 장치를 만들지 않음
docs-lib 선참조 Tauri v2·프론트 invoke/listen 표면과 DPI 동작 확인 완료
주석·문서 한글 반말 산출물 전부 한글
plan 집은 하나 specs/004-tauri-shell/만 사용하고 기존 계약 문서는 링크함
완료 전 lint+test+build quickstart와 tasks에 프론트·Rust·Tauri release 검증을 둠

설계가 드러낸 위험 1건:

2_frontend의 브릿지 테스트 3개가 chrome.webview mock에 의존한다. transport mock으로 바꾸면서 실제 Tauri 경로가 아니라 mock끼리만 맞는 상태가 생길 수 있다.

완화: 자동 검사 뒤 브라우저와 실제 Tauri 앱을 각각 실행한다. 기존 WebView2 경로는 adapter 단위 테스트로 남기되 legacy 앱 수동 회귀를 완료 게이트로 두지 않는다.

게이트 결과: 통과. 아래 Complexity Tracking의 2건은 근거 있는 편차다.

Complexity Tracking

Constitution Check 위반 중 정당화가 필요한 것만

Violation Why Needed Simpler Alternative Rejected Because
프론트 신규 의존성 @tauri-apps/api invoke/listen은 Tauri 내부 프로토콜이라 공식 API를 쓰는 편이 작고 안전함 직접 구현은 버전마다 깨질 내부 표면을 소유하게 됨
4_rust_tauri의 미완성 스캐폴드 유지 아이콘·build.rs·capabilities는 생성기가 만든 유효한 산출물 통째 재생성해도 같은 파일만 다시 생김. 손으로 쓴 소스만 컴파일하며 재검증함