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
+68
View File
@@ -0,0 +1,68 @@
# 완료 보고: 스니펫 팔레트 (001-snippet-palette)
**브랜치**: `feat/snippet-palette` · **작성**: 2026-08-05 · **상태**: 최종 승인 대기
003(파이썬 winkit-snippet)의 스니펫 검색·붙여넣기 기능을 이 앱(React SPA + .NET WebView2)에 재개발 이식. 전역 핫키 `Ctrl+1` → Raycast 결 팔레트 → 검색 → 앞 창에 붙여넣기. 저장은 C# 호스트 소유 로컬 SQLite.
## 계획 vs 결과
| Phase / Story | 계획 | 결과 |
|---|---|---|
| Foundational (T001-T011) | 멀티핫키·Ctrl+1·SendToWeb/navigate·SnippetRepository+스키마·시드·브릿지 왕복·라우트 | ✅ 전부. C# 10→17 테스트, 프론트 브릿지 왕복 테스트 |
| US1 / MVP (T012-T024) | 검색(키워드 AND, name+desc)·usage 랭킹·Enter/Alt 붙여넣기·프리뷰·Raycast 팔레트 | ✅ 전부. 검색/랭킹 순수함수 + api 테스트 |
| US2 / CRUD (T025-T031) | 생성/편집/삭제·EditDialog(클립보드 프리필)·검증(중복·빈값 거부) | ✅ 전부. repo CRUD xUnit + api 테스트 |
| US3 / category (T032-T034) | category 칩 필터 + Ctrl+←/→ | ✅ 전부. (검색 category 필터는 US1때 이미 구현돼 있어 칩 UI만 추가) |
| Polish (T035-T037) | 최종 검증·quickstart·report | T035 ✅ / T036 데스크톱 수동확인(사용자) / T037 이 문서 |
## 신규 vs 재사용 (재사용 우선 원칙)
**신규(핵심 3곳만):**
- C# 2번째 전역 핫키(멀티핫키로 `HotKeyService` 확장) + Ctrl+1
- C#→JS `navigate` 푸시(`SendToWeb`/`PostWebMessageAsJson`)
- React↔SQLite reqId 요청-응답 브릿지 + C# `SnippetRepository`/`SnippetBridge`/`SnippetSeed`
**재사용:**
- 팔레트 UI: snap `SessionListPage`(키보드 nav·IME 안전·Esc 단계) 복제 후 Raycast 리스킨
- 붙여넣기: 기존 `pasteToApp``PasteService`(앞 창 Ctrl+V) 그대로
- 핫키/트레이/단일실행/앞창 캡처, memos feature/react-query 패턴
## 문서화한 정당 편차
1. 데이터가 `@/lib/api/client`(HTTP) 미경유 — 로컬 SQLite라 브릿지 백엔드. react-query는 유지.
2. `Snippet` 타입이 `types/api.ts`(서버 DTO) 아닌 feature-local — 로컬 엔티티(snap 방식과 동일).
## 계획과 달라진 점 / 겪은 문제
- **시드 소스 부재**: 003의 `snippets.db`가 이 머신에 실제로 없음(포터블/미실행) → 첫 실행 시 빈 DB로 시작(설계상 fallback). 003 데이터 이어받기는 그 파일이 생기면 자동 동작.
- **git index 레이스**(Foundational): 프론트·C# implementer를 병렬로 돌렸다가 같은 git index 충돌로 커밋이 섞이고 일부 미커밋됨. working tree(진실원천)로 검증·복구(30159d2). 이후 **implementer 순차 원칙** 확립.
- **클릭 모델 정리**(US2 리뷰): US1이 행 단일클릭=붙여넣기로 만들어 더블클릭 편집이 죽어있었음 → 단일클릭=선택, Enter/Alt=붙여넣기, 더블클릭/F2=편집(003·spec 정합).
- **콜드스타트 navigate 드롭**(Foundational 리뷰): 앱 시작 직후 첫 Ctrl+1이 유실될 수 있어 pending 버퍼+NavigationCompleted flush로 방어.
## 검증
- 프론트: **233/233** 통과, build OK. 스니펫 feature lint **0문제**. (repo 전체 20 lint 문제는 무관 feature의 pre-existing 빚.)
- C#: **17/17** 통과, build 0 경고/에러.
- 런타임 E2E(Ctrl+1→검색→붙여넣기, 시드, 붙여넣기 대상 정확성): **데스크톱 앱 실행 필요 — 헤드리스 불가. 사용자 수동 확인 권장**(quickstart.md 시나리오 1~11).
## 남은 것 / 이월(deferred)
- **[수동확인]** quickstart 시나리오 — 실제 데스크톱에서.
- **[deferred]** 붙여넣기 실패해도 recordUse 됨(기존 `paste.code` fire-and-forget 프로토콜 한계, ack 추가는 별개 작업).
- **[deferred]** list-fetch 에러가 빈상태와 동일 표시(에러 UI 없음).
- **[deferred]** `HotKeyService.Dispose` 단일 `_hwnd` 가정(현재 두 핫키 같은 hwnd라 무해).
- **[deferred]** `SnippetBridge` reqId 빈값 시 promise 영구 대기(정상 caller는 항상 reqId 세팅).
## 최종 리뷰 (whole-branch, opus)
**APPROVE** — 보안(전 쿼리 파라미터화, body는 `<pre>` escape)·정합성(delete가 usage까지·name 정규화 일관)·브릿지 상관(reqId 유일·리스너 멱등)·동시성(WebView2 UI 스레드 단일) 다 클린. Critical/Important 신규 없음.
리뷰서 나온 신규 Minor 4개는 **1회 fix wave로 처리 완료**(재리뷰 ALL ADDRESSED):
- **M1/M2**: `/snippet``SnapLayout``ProtectedRoute` 직속 `h-screen` 풀스크린으로 이동 → snap 헤더 없이 Raycast 풀윈도 룩 복구 + Ctrl+N 이탈 차단. auth 유지(routes.test.tsx 회귀가드).
- **M3**: navigate 버퍼는 pre-ready일 때만 → reload 시 stale 재전송 방지.
- **M4**: 비도메인 예외는 raw 메시지 대신 generic 한글 토스트(SQLite 영어 내부 노출 차단).
**런타임 미검(헤드리스 한계 — 사용자 확인 필요):** 실제 데스크톱에서 Ctrl+1 → 팔레트 풀윈도 중앙 표시(snap 헤더 없음)·검색·앞 창 붙여넣기·Ctrl+N 비이탈. quickstart.md 시나리오로 눈확인 권장.
**최종 검증:** 프론트 **234/234**, C# **17/17**, 빌드 클린. 스니펫 코드 lint 0문제.
**결론:** 문서화된 deferral(위 "남은 것") 제외하고 **merge 준비 완료**.