# Page Clipping + Highlight Implementation Plan ## Goal - 사용자가 특정 페이지에서 선택한 텍스트를 클리핑(저장)한다. - 저장된 클립은 원문 위치에 하이라이트로 다시 표시된다. - 팝업에서 클립 목록을 보고 해당 위치로 다시 이동할 수 있다. ## Scope (v1) 1. 지원 대상 - 텍스트 기반 웹페이지 (`contenteditable` 제외, 일반 DOM 문서 우선) - 탭 단위 클립 저장/조회 2. 포함 기능 - 선택 텍스트 캡처 - 하이라이트 주입/복원 - 클립 목록 조회/삭제 - 클릭 시 원문 위치로 스크롤 3. 제외 기능(후속) - PDF/캔버스/이미지 OCR 하이라이트 - 협업 공유/서버 동기화 - 다중 색상 태깅, 폴더 분류 ## Data Model (Draft) ```ts type ClipItem = { id: string tabId?: number pageUrl: string pageTitle: string quote: string createdAt: string color: 'yellow' anchor: { textStart: string textEnd: string exact: string prefix?: string suffix?: string xpathStart?: string xpathEnd?: string startOffset?: number endOffset?: number } } ``` ## Architecture 1. Content Script - 사용자 선택(`window.getSelection`)에서 `Range` 추출 - `anchor` 생성(텍스트 인용 + DOM 포지션) - background에 `clip:create` 메시지 전송 - `clip:apply` 이벤트 수신 시 하이라이트 렌더링 2. Background (Service Worker) - `clip:create`, `clip:list`, `clip:delete`, `clip:reveal` 메시지 처리 - `storage.local` 기반 영속화 - 탭 활성화/페이지 완료 시 `clip:sync` 트리거 3. Popup/History UI - 현재 탭 URL 기준 클립 목록 요청 - 항목별 `위치로 이동`, `삭제` 버튼 - 상태 메시지(저장 성공/실패) 표시 ## Step-by-Step 1. Step 1: Selection Capture + Overlay - `src/lib/clipAnchor.ts` 생성 - `Range -> anchor` 변환 유틸 구현 - `src/content/index.ts`에 단축키/우클릭 기반 캡처 진입점 추가 - `span[data-gomdown-clip]` 하이라이트 렌더링/해제 로직 구현 2. Step 2: Store + Message Channel - `src/lib/clipStore.ts` 생성 (`list/upsert/delete/byUrl`) - background message router에 `clip:*` 타입 추가 - dedupe(`pageUrl + exact + createdAt window`) 정책 추가 3. Step 3: Popup UI - `src/popup/main.tsx`에 "Clips" 섹션 추가 - 현재 탭 URL 클립 조회 + 목록 렌더링 - `Reveal/Delete` 액션과 오류 상태 처리 4. Step 4: Re-anchoring - 페이지 로드 시 `clip:list` 후 순차 복원 - 우선순위: - `exact + prefix/suffix` 텍스트 매칭 - 실패 시 `xpath + offset` 복구 - 둘 다 실패 시 `broken anchor`로 표시 5. Step 5: Export/Import + QA - JSON export/import 메시지 추가 - 샘플 페이지(뉴스, 블로그, SPA) 수동 테스트 - 회귀 체크리스트 문서화 ## QA Checklist - 같은 페이지 새로고침 후 하이라이트가 유지된다. - SPA 라우팅(YouTube/블로그) 후에도 복원 시도가 동작한다. - 원문 DOM이 일부 바뀐 경우, 텍스트 매칭 fallback이 동작한다. - 클립 삭제 시 화면/저장소에서 모두 제거된다. - 확장 비활성화 상태에서 캡처가 차단된다. ## Risk & Mitigation 1. DOM 변형으로 앵커 붕괴 - 텍스트 인용 앵커 + XPath 이중 저장 2. 성능 저하(클립 다수) - URL 단위 lazy apply, viewport 근처 우선 렌더 3. 사이트 충돌(CSS/스크립트) - 고유 data-attribute와 최소 침습 스타일 사용 ## Definition of Done - 사용자는 텍스트 선택 후 1회 액션으로 클립 저장 가능 - 같은 URL 재방문 시 하이라이트 자동 복원 - 팝업에서 클립 조회/이동/삭제 가능 - 크롬 기준 수동 시나리오 10개 중 9개 이상 성공