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

117 lines
4.7 KiB
Markdown

# 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).
---