Files
2026-09-16 17:22:14 +09:00

15 KiB
Raw Permalink Blame History

description
description
Task list for 스니펫 팔레트 (Snippet Palette)

Tasks: 스니펫 팔레트 (Snippet Palette)

Input: specs/001-snippet-palette/ (plan.md, spec.md, research.md, data-model.md, contracts/, quickstart.md)

Tests: 포함(이 프로젝트는 superpowers TDD RED→GREEN + npm run test/dotnet test 통과가 완료 기준 — CLAUDE.md §4).

Organization: user story별 phase. US1(P1)만 해도 MVP(스니펫 있으면 검색→붙여넣기 됨).

Format: [ID] [P?] [Story] Description (파일경로)

  • [P]: 다른 파일·의존 없음 → 병렬 가능
  • [US#]: 해당 user story
  • 핸드오프: 여기서부터 superpowers 뒷단(executing-plans/subagent-driven-development + test-driven-development). 단계(phase) 하나 끝날 때마다 specs/001-snippet-palette/stage-N.md 기록.

Phase 1: Setup (공용 기반)

  • T001 Microsoft.Data.Sqlite 패키지 추가 (3_windowsApp/CodeAssist.Shell/CodeAssist.Shell.csproj)
  • T002 [P] PATHS.SNIPPET = "/snippet" 추가 (2_frontend/src/config/routes.ts)
  • T003 [P] feature 폴더 뼈대 + 타입 생성: Snippet/SnippetInput (2_frontend/src/features/snippets/types.ts, data-model.md 준용)

Phase 2: Foundational (모든 story 선행 — 반드시 먼저)

목표 체크포인트: Ctrl+1 → 팔레트가 /snippet(빈 화면)로 뜨고, snippets.api.list()가 시드된 데이터를 왕복으로 돌려준다.

  • T004 HotKeyService 멀티 핫키로 확장 — Register(int id, mods, vk)·HashSet<int> 추적·event Action<int> HotKeyPressed·ProcessMessage(int msg, IntPtr wParam) (3_windowsApp/CodeAssist.Shell/Platform/HotKeyService.cs) + App.WndProc가 wParam 전달하도록 수정 (3_windowsApp/CodeAssist.App/App.xaml.cs)
  • T005 Ctrl+1(id 0x1001, MOD_CONTROL|VK_1) 등록 + 눌리면 ShowPalette() 후 navigate 신호 송신. 핫키 조합 상수는 한 곳에 모음 (3_windowsApp/CodeAssist.App/App.xaml.cs) — depends T004
  • T006 WebHostViewSendToWeb(object)(=PostWebMessageAsJson) 추가 + OnWebMessageReceivedsnippets.*SnippetBridge로 위임 + navigate 푸시 경로 (3_windowsApp/CodeAssist.App/Views/WebHostView.xaml.cs) — depends T004/T005 (navigate 대상)
  • T007 [P] SnippetRepository 뼈대 + 스키마 초기화(CREATE TABLE snippets/usage) + DB 경로 %LOCALAPPDATA%\CodeAssist\snippets.db (3_windowsApp/CodeAssist.Shell/Storage/SnippetRepository.cs, data-model.md 스키마)
  • T008 [P] SnippetSeed — 첫 실행 시 대상 DB 없고 003 snippets.db 있으면 1회 복사, 없으면 빈 DB. App 시작 시 repo 사용 전 호출 (3_windowsApp/CodeAssist.Shell/Storage/SnippetSeed.cs) — 003 경로는 구현 시 확인(research R5)
  • T009 [P] 프론트 브릿지 왕복 인프라 — reqId Map + chrome.webview 메시지 리스너(snippets.result 매칭 resolve/reject), 순수 브라우저면 비활성 (2_frontend/src/lib/bridge/snippetBridge.ts, contracts/bridge-messages.md)
  • T010 [P] bridgeNavigate.tsnavigate 메시지 수신 → 등록된 react-router navigate 콜백 호출. 앱 최상위에서 mount 시 콜백 등록 (2_frontend/src/lib/bridge/bridgeNavigate.ts + 등록 지점)
  • T011 /snippet 라우트 + 임시 placeholder 페이지를 SnapLayout 그룹에 추가 (2_frontend/src/routes.tsx) — depends T002

Checkpoint: Ctrl+1 → /snippet 빈 화면 뜨고 list 왕복 확인.


Phase 3: User Story 1 - 핫키로 검색→앞 창 붙여넣기 (P1) 🎯 MVP

Goal: 스니펫 검색·프리뷰·usage랭킹 + Enter/Alt로 앞 창에 붙여넣기.

Independent Test: 시드된 스니펫 상태에서 에디터 포커스 → Ctrl+1 → 검색 → Enter → 에디터에 body 원문 삽입 + usage 상승.

Tests (RED 먼저)

  • T012 [P] [US1] core/search 단위테스트 — 키워드 AND, name+desc 대문자, body 제외, 빈쿼리 (2_frontend/src/features/snippets/core/search.test.ts)
  • T013 [P] [US1] core/ranking 단위테스트 — (-count,-lastUsed,name) 정렬 (2_frontend/src/features/snippets/core/ranking.test.ts)
  • T014 [P] [US1] SnippetRepository.List/RecordUse xUnit (temp sqlite, usage 조인·upsert) (3_windowsApp/CodeAssist.Tests/SnippetRepositoryTests.cs)
  • T015 [P] [US1] snippets.api list/recordUse — 브릿지 mock 테스트 (2_frontend/src/features/snippets/api/snippets.api.test.ts)

Impl

  • T016 [P] [US1] core/search.ts (검색 순수함수, category 파라미터 포함) (2_frontend/src/features/snippets/core/search.ts)
  • T017 [P] [US1] core/ranking.ts (usage 정렬) (2_frontend/src/features/snippets/core/ranking.ts)
  • T018 [US1] SnippetRepository.List(snippets⨝usage) + RecordUse(count+1,last_used=now) (3_windowsApp/CodeAssist.Shell/Storage/SnippetRepository.cs)
  • T019 [US1] SnippetBridge 핸들러 snippets.list·snippets.recordUse → repo 호출 후 snippets.result 응답 (3_windowsApp/CodeAssist.App/Views/WebHostView.xaml.cs 또는 신규 SnippetBridge.cs)
  • T020 [US1] snippets.api.ts(list, recordUse) + useSnippets/useRecordUse (SNIPPETS_KEY·invalidate, memos 패턴) (2_frontend/src/features/snippets/api/snippets.api.ts, hooks/useSnippets.ts)
  • T021 [US1] SnippetPalettePage — snap SessionListPage 복제 → 검색입력 + 결과리스트 + 우측 프리뷰, Raycast 룩 리스킨 (2_frontend/src/features/snippets/pages/SnippetPalettePage.tsx)
  • T022 [US1] 키 조작 — ↑↓ nav(프리뷰 갱신), Enter→pasteToApp(body)+recordUse+hideWindow, Alt+1~9 즉시 붙여넣기, Esc 단계(비움→숨김), IME 안전 (SnippetPalettePage.tsx)
  • T023 [P] [US1] SnippetRow(제목/부제/우측 번호 액세서리) + PreviewPane(<pre> 고정폭·원문보존, react-markdown 안 씀) Raycast 결 (2_frontend/src/features/snippets/components/)
  • T024 [US1] 빈 상태 안내 + 상위 9개 1~9 번호 표시 (SnippetPalettePage.tsx)

Checkpoint: US1 단독으로 완전 동작(MVP). STOP & VALIDATE — quickstart 1~6,10,11.


Phase 4: User Story 2 - 생성/편집/삭제 (P2)

Goal: 팔레트에서 스니펫 CRUD. 생성 시 body는 클립보드로 프리필.

Independent Test: 생성→검색에 뜸 / 빈 이름·내용 거부 / 중복 이름 거부 / F2 편집(이름 읽기전용) / 편집창 삭제.

Tests (RED 먼저)

  • T025 [P] [US2] SnippetRepository.Create/Update/Delete xUnit — 중복 거부·정규화·검증 (3_windowsApp/CodeAssist.Tests/SnippetRepositoryTests.cs)
  • T026 [P] [US2] snippets.api create/update/remove — 브릿지 mock(성공/ok:false reject) (2_frontend/src/features/snippets/api/snippets.api.test.ts)

Impl

  • T027 [US2] SnippetRepository.Create/Update/Delete — name 정규화·유일성·body 비어있지않음(위반 시 에러) (3_windowsApp/CodeAssist.Shell/Storage/SnippetRepository.cs)
  • T028 [US2] SnippetBridge 핸들러 create/update/delete (ok:false+한글 에러 계약) (WebHostView.xaml.cs/SnippetBridge.cs)
  • T029 [US2] snippets.api create/update/remove + useCreateSnippet/useUpdateSnippet/useDeleteSnippet(invalidate + sonner 한글 토스트, ApiError 형태) (api/snippets.api.ts, hooks/useSnippets.ts)
  • T030 [US2] EditDialog — 생성/편집 공용, 편집 시 name 읽기전용, 생성 시 body=클립보드(navigator.clipboard.readText(), 실패 시 빈값), 검증 (2_frontend/src/features/snippets/components/EditDialog.tsx)
  • T031 [US2] 팔레트 배선 — 생성 액션(Ctrl+N/버튼), F2·더블클릭 편집, 다이얼로그 삭제+확인, 완료 후 목록 새로고침 (SnippetPalettePage.tsx)

Checkpoint: US1+US2 동작. quickstart 7~8.


Phase 5: User Story 3 - category 칩 필터 (P3)

Goal: category 칩으로 분류별 필터.

Independent Test: 다른 category 스니펫 있을 때 칩 선택 → 그 분류만.

Tests (RED 먼저)

  • T032 [P] [US3] core/search category 필터 케이스 추가 (core/search.test.ts)

Impl

  • T033 [US3] category 필터 확정(core/search.ts 파라미터 활용) + 목록에서 존재하는 category 도출 (core/search.ts, SnippetPalettePage.tsx)
  • T034 [US3] CategoryChips — "전체" + categories, Ctrl+←/→ 칩 이동, 페이지 배선 (2_frontend/src/features/snippets/components/CategoryChips.tsx, SnippetPalettePage.tsx)

Checkpoint: 전 story 동작. quickstart 9.


Phase 6: Polish & 검증

  • T035 npm run formatnpm run lint + npm run test + npm run build 통과 + dotnet test 3_windowsApp/CodeAssist.Tests 통과
  • T036 quickstart.md 수동 시나리오 1~11 전체 확인(붙여넣기 대상 정확성·영속·시드)
  • T037 [P] specs/001-snippet-palette/report.md(계획 vs 결과) 작성 → 최종 승인용

Dependencies & Execution Order

  • Phase 1 SetupPhase 2 Foundational(전 story 차단) → US1 → US2 → US3Polish.
  • Foundational 안: T004→T005→T006 순(같은 C# App/WebHostView 계열). T007/T008/T009/T010은 서로 [P]. T011은 T002 이후.
  • US 간: US1은 read/paste, US2는 write(같은 repo/api/page 파일 확장이라 US1 뒤가 안전 — 병렬 시 파일 충돌 주의), US3은 category(대부분 독립).
  • Story 내: 테스트(RED) → 순수함수/모델 → repo/bridge → api/hooks → 페이지/컴포넌트.

Parallel Opportunities

  • Setup: T002·T003 [P].
  • Foundational: T007·T008·T009·T010 [P](C# 저장소 vs 프론트 브릿지 서로 다른 파일).
  • US1 테스트: T012·T013·T014·T015 [P]. US1 순수함수: T016·T017 [P]. 컴포넌트 T023 [P].
  • 주의: SnippetRepository.cs·snippets.api.ts·SnippetPalettePage.tsx는 여러 태스크가 손대므로 같은 story 안에선 [P] 안 붙임(파일 충돌).

Implementation Strategy

  1. Setup + Foundational → "Ctrl+1로 /snippet 뜨고 데이터 왕복" 체크포인트.
  2. US1(MVP) → 독립 검증(붙여넣기 되면 도구로서 완성) → 데모.
  3. US2(CRUD) → US3(category) 순 증분.
  4. 각 단계 끝 stage-N.md, 완료 전 superpowers:verification-before-completion + /code-review, 최종 report.md → 승인 → merge(/cmp).

Notes

  • [P] = 다른 파일·무의존. [US#] = 추적용.
  • 정당 편차(plan §Constitution): 데이터는 @/lib/api/client 아닌 브릿지, Snippet 타입은 feature-local.
  • 붙여넣기·핫키·앞창캡처·팔레트 nav는 기존 재사용 — 새로 만들지 말 것.

2026-09-11: 단계별 런처와 실제 창 크기

spec.md의 2026-09-11 사용자 승인 범위만 완료함. 위 초기 .NET 이식·CRUD·사용기록의 미완료 항목을 완료로 바꾸지 않음.

  • 검색창만 시작하고 검색 후 결과를 표시. 미선택 Enter는 아무것도 복사하지 않음.
  • 화살표·클릭으로 직접 선택할 때만 프리뷰를 열고 검색·분류 변경 시 선택 해제.
  • 결과 행을 간결하게 바꾸고 하단 키 안내 추가. 기존 코드뷰어·분할 크기 조절 유지.
  • Tauri window_snippet_layout으로 검색 640×84 / 결과 640×440 / 프리뷰·편집 960×600 적용. DPI·작업 영역·창 테두리 보정.
  • 챗봇 복귀·최대화 복원·종료 저장에서 원래 배치 보존. CloseRequested 캐시 순서 문제를 실제로 재현하고 명시적 저장으로 수정.
  • Esc 포커스 복원과 재소환 시 삭제 확인창 닫힘을 실패하는 회귀 검사로 재현 후 수정.
  • npm run format, lint(오류 0·기존 경고 9), 프론트 46파일·259검사, build 통과. Rust fmt·6검사 통과·로컬 DB 전용 1검사 기본 제외, clippy -D warnings 통과.
  • 실제 저장된 스니펫 SELECT 검색 7개, 키보드 선택·코드 프리뷰·빈 결과·편집·재소환을 Tauri에서 확인. 데이터 저장·삭제는 실행하지 않음.
  • 실제 Windows 크기 전환·화면 우하단 확장·최대화 전 일반 배치 복원·축소 종료 후 960×680 재시작 확인.

2026-09-11: 코드 프리뷰 군더더기 제거

  • 프리뷰 이름·설명·분류, 장식 점과 코드 헤더, 박스 테두리·그림자를 제거. 문법 강조와 줄 번호 유지.
  • CodeBlock의 plain 표시를 재사용해 프리뷰 안쪽 스크롤을 하나로 합침. 챗봇 카드의 기본 모양은 유지.
  • 기존 복사·붙여넣기 버튼을 CodeActions로 공유하고 스니펫 하단에 배치. 버튼 Enter를 전역 즉시 복사가 가로채지 않도록 수정.
  • 실제 Tauri 프리뷰의 헤더·버튼 0개, 세로 스크롤 1개, 하단 액션 2개와 문법 강조를 확인. 클릭·키보드 복사 원문과 창 유지 회귀 검사 통과.
  • format·lint(오류 0, 기존 경고 9)·46파일 260검사·build 통과.

별도 관찰

  • 최소화된 앱을 검사 도중 종료한 뒤 /snap이 640×84로 시작하는 현상을 관찰함. 최소화 종료 경로의 배치 저장은 별도로 재현·확인할 것. 이번 프리뷰 UI 변경에는 Rust 수정을 포함하지 않음.

2026-09-11: 프리뷰 전체 창 축소

  • 사용자 추가 요청에 따라 코드 프리뷰만 960×600에서 840×520으로 축소. 검색 640×84·결과 640×440·편집 960×600은 유지.
  • 실제 Tauri에서 840×520 화면, 하단 액션 표시, 세로 스크롤 1개를 확인. F2 편집 960×600 → 닫기 후 프리뷰 840×520 복귀 확인.
  • Rust fmt 검사와 6개 검사 통과. 프론트는 직전 UI 변경 검증 46파일·260개 검사 및 build 통과 상태를 유지함.

2026-09-11: Ctrl+Enter 앱에 붙여넣기

  • 기존 pasteToApp을 Ctrl+Enter에서도 사용. 일반 Enter·복사 버튼 동작은 유지하고, 미선택·IME·편집·브라우저·반복키·추가 modifier는 차단.
  • 네이티브 붙여넣기를 비동기 작업으로 실행. 키 해제는 최대 2초 대기하고, 중복 요청·대상 HWND/PID/thread 변경·포커스 이탈·재입력은 취소.
  • SetForegroundWindow 직후 정상 활성화를 실패로 오판하는 경합을 실제로 재현. 80ms 구간에서 첫 활성화 전 팔레트·NULL만 기다리고, 대상 활성화 이후 이탈은 취소하도록 수정.
  • SendInput 전송 개수를 확인하고 성공 때만 창 숨김. 실패하면 창과 오류 안내 유지, 이미 복사된 원문은 클립보드에 보존.
  • 저장하지 않는 별도 Windows 입력창에서 실제 Ctrl+Enter 누름·반복·해제 → 1,420자 원문 1회 입력·창 숨김 확인. 기존 붙여넣기 버튼도 같은 원문 입력 확인.
  • 실제 네이티브 입력으로 한글·CRLF·탭·앞뒤 공백 보존 확인. 대상 없음·닫힌 대상·중복 요청·2초 키 대기 초과·대기 중 포커스 이탈에서 입력 취소·오류·클립보드 보존 확인.
  • 프론트 format·lint(오류 0, 기존 경고 9)·46파일 264검사·build 통과. Rust fmt·6검사(로컬 DB 검사 1개 기본 제외)·clippy -D warnings 통과.
  • 검증 범위: 별도 WinForms 입력창을 사용했고 사용자 문서·원본 스니펫 DB를 바꾸지 않음. VS Code·SAP·관리자 권한 앱 각각의 실제 수신 검사는 별도이며, 키 전송 성공이 모든 앱의 붙여넣기 수신을 보장하지는 않음.