# Phase 1: Data Model — Tauri 기준 데스크톱 앱 **Created**: 2026-08-11 | **Updated**: 2026-09-09 | **Plan**: [plan.md](./plan.md) 이 기능은 **새 데이터를 거의 안 만든다.** 기존 스니펫을 보존하고 Tauri의 창·화면 상태만 관리한다. --- ## 1. Snippet — 기존 데이터 유지 **저장소**: `%LocalAppData%\CodeAssist\snippets.db` (SQLite) **출처**: `3_windowsApp/CodeAssist.Shell/Storage/SnippetRepository.cs`가 현재 형식의 참고 원본이다. Tauri는 **스키마를 바꾸지 않고** 기존 파일을 직접 쓴다. | 필드 | 타입 | 규칙 | |---|---|---| | `name` | string | **키**. 중복 생성 거부 | | `desc` | string | 설명 | | `body` | string | 본문. 붙여넣을 때 **원문 그대로** (FR-013) | | `category` | string | 분류 | | `usageCount` | int | 사용할 때마다 +1 | | `lastUsed` | timestamp | 사용 시각 | **검증 규칙**: - `name` 중복 생성 → 거부, 한글 오류 메시지 - 빈 필수 필드 → 거부, 한글 오류 메시지 - 오류는 화면에 토스트로 뜬다 (FR-022) **상태 변화**: 생성 → (수정)\* → (사용 시 `usageCount`+1, `lastUsed` 갱신)\* → 삭제 **보존 규칙**: - 스키마 변경 금지 - SQLite 저널 모드 변경 금지 - 기존 파일이 없으면 같은 형식의 빈 저장소를 만든다 --- ## 2. WindowState — Tauri 앱 상태 | 필드 | 의미 | |---|---| | 위치 (x, y) | 마지막 창 자리 | | 크기 (w, h) | 마지막 창 크기 | | `pinned` | 항상 위 고정 여부 | **저장 위치**: `%LocalAppData%\com.codeassist.app\`. 위치·크기는 window-state 플러그인, `pinned`는 별도 단일 파일로 저장한다. **복원 규칙**: 화면 밖 자리로는 복원하지 않는다. 모니터 구성이 바뀌어 저장된 자리가 화면 밖이면 보이는 자리로 되돌린다. --- ## 3. PasteTarget — 기존, 휘발성 창을 부르기 **직전**에 한 번 찍는 스냅샷. 저장 안 함(앱 종료 시 사라짐). | 필드 | 의미 | |---|---| | 창 핸들 | 붙여넣을 대상 | | `name` | 창 제목 | | `app` | 프로그램 이름 (예: `Code`, `notepad`) | **왜 스냅샷인가**: 나중에 그 창이 닫혀도 "어디에 붙는지" 표시는 남아야 한다(FR-015). 그래서 소환 시점에 제목·프로그램명을 **값으로 복사**해 둔다. **생명주기**: 창 소환 시 갱신 → 화면에 배지로 표시 → 다음 소환 때 덮어씀 --- ## 4. Routes — 기존, 껍데기 메모리 화면이 이동할 때마다 껍데기에 보고하는 값. 챗봇 단축키 토글 규칙(FR-011)에 쓴다. | 필드 | 의미 | 초기값 | |---|---|---| | `current` | 화면이 지금 있는 자리 | `/snap` | | `lastSnap` | 마지막으로 있던 **비-스니펫** 자리 | `/snap` | **갱신 규칙**: 보고받은 경로가 `/snippet` 으로 시작하지 **않으면** `lastSnap` 도 같이 갱신. `current` 는 항상 갱신. **토글 판정**: ``` 창이 보이는 중 AND current 가 /snippet 이 아님 → 숨긴다 그 외 → 띄우고 lastSnap 으로 이동 ``` --- ## 5. BridgeMessage — 기존 계약 **진실원천은 여기가 아니다.** 아래 두 문서가 원본: - `specs/001-snippet-palette/contracts/bridge-messages.md` - `specs/002-capture-to-chat/contracts/bridge-capture.md` 환경별 전달 수단 매핑만 [contracts/transport-mapping.md](./contracts/transport-mapping.md)에 있다. **이 기능이 계약에 더하는 제약 1개**: > Tauri에서 아직 안 만든 메시지는 성공 응답을 흉내내지 않는다. 사람이 읽을 수 있는 "아직 안 됨" 오류로 답하고, 화면은 그걸 토스트로 띄운다. (FR-023) **왜 이게 데이터 규칙인가**: 빈 목록(`[]`)으로 답하면 "스니펫이 0개"와 "기능이 없음"이 구분되지 않는다. 구현 중 빠진 기능을 성공으로 오판하지 않게 한다. --- ## 6. HostKind — 프론트 내부 프론트가 bridge 사용 시점에 판별하는 값. 저장하지 않는다. | 값 | 판별 조건 | 동작 | |---|---|---| | `tauri` | `typeof window.__TAURI_INTERNALS__?.invoke === "function"` | 기준 데스크톱 앱 방식 | | `webview2` | `window.chrome?.webview` 있음 | 참고용 legacy 방식 | | `browser` | 둘 다 없음 | 데스크톱 기능 없음 | **판별 순서 고정**: `tauri` → `webview2` → `browser`. Windows Tauri가 WebView2를 사용해도 Tauri invoke 통로를 먼저 고른다. **노출 범위**: `isWebView()` 같은 기존 함수의 속만 바뀐다. 화면 코드는 `HostKind`를 몰라야 한다(FR-002, SC-001). ---