5.3 KiB
5.3 KiB
완료 보고: 스니펫 팔레트 (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 패턴
문서화한 정당 편차
- 데이터가
@/lib/api/client(HTTP) 미경유 — 로컬 SQLite라 브릿지 백엔드. react-query는 유지. 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.codefire-and-forget 프로토콜 한계, ack 추가는 별개 작업). - [deferred] list-fetch 에러가 빈상태와 동일 표시(에러 UI 없음).
- [deferred]
HotKeyService.Dispose단일_hwnd가정(현재 두 핫키 같은 hwnd라 무해). - [deferred]
SnippetBridgereqId 빈값 시 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 준비 완료.