# InsuWiki TOC 편집모드 스크롤/하이라이트 동기화

## 작업 개요
편집 모드(isEditing=true)에서 TOC(목차)가 완벽하게 동작하도록 수정.
현재는 `{!isEditing && <TableOfContents>}` 조건으로 편집 시 TOC가 숨겨져 있음.

## 요구사항 (제이회장님 지시, 4가지)

### R1. 독립 스크롤
- 마우스가 **편집창(에디터)** 위에 있을 때 → 편집창만 스크롤
- 마우스가 **TOC 영역** 위에 있을 때 → TOC만 스크롤
- 각 영역이 독립적으로 스크롤되어야 함 (CSS `overflow-y: auto` + `overscroll-behavior: contain`)

### R2. 편집창 위치 → TOC 하이라이트 연동
- 편집창에서 커서/스크롤 위치에 맞춰 TOC의 해당 항목이 하이라이트
- TipTap 에디터의 현재 커서 위치(또는 스크롤 위치)를 감지하여 가장 가까운 heading을 찾고, TOC에서 해당 항목 활성화
- 기존 IntersectionObserver 방식은 뷰 모드용이므로, 편집 모드에서는 에디터 스크롤 이벤트 기반으로 구현

### R3. TOC 클릭 → 편집창 이동
- TOC 항목 클릭 시 편집창이 해당 heading 위치로 스크롤
- TipTap 에디터 내부에서 해당 heading 노드를 찾아 `scrollIntoView` 실행

### R4. 편집 모드에서 TOC 표시
- `DocumentClient.tsx` 567행의 `{!isEditing && ...}` 조건 제거/수정
- 편집 모드에서도 TOC 사이드바가 표시되도록 변경

## 대상 파일

### 1. `/home/jay/projects/insuwiki/nextapp/src/app/docs/[id]/DocumentClient.tsx`
- **567행**: `{!isEditing && <TableOfContents content={document.content} variant={docType} />}`
  - `!isEditing` 조건 제거하여 편집 모드에서도 TOC 표시
  - 편집 모드일 때 에디터 ref를 TOC에 전달

### 2. `/home/jay/projects/insuwiki/nextapp/src/components/TableOfContents.tsx` (272줄)
- 현재 IntersectionObserver 기반 (뷰 모드 전용)
- 편집 모드용 props 추가: `isEditing?: boolean`, `editorElement?: HTMLElement`
- 편집 모드 분기:
  - TOC 파싱: 에디터 DOM에서 heading 추출 (또는 에디터 content에서 파싱)
  - 스크롤 동기화: 에디터 스크롤 이벤트 리스닝 → 현재 보이는 heading 감지 → activeId 업데이트
  - 클릭: heading DOM 요소 찾아서 `scrollIntoView({ behavior: 'smooth', block: 'start' })`
- TOC 영역 자체 스크롤: `overflow-y: auto`, `overscroll-behavior: contain`으로 독립 스크롤

### 3. `/home/jay/projects/insuwiki/nextapp/src/components/ReflectEditor.tsx` (474줄)
- 에디터 DOM 요소(ref)를 상위 컴포넌트에 노출할 수 있도록 수정
- 또는 에디터 wrapper에 id 부여하여 TOC에서 querySelector로 접근

## 구현 가이드

### 편집 모드 TOC heading 감지 방법
TipTap 에디터는 ProseMirror 기반. heading이 `<h1>`, `<h2>`, `<h3>` 태그로 렌더링됨.
```typescript
// 에디터 DOM에서 heading 요소들 수집
const editorEl = document.querySelector('.ProseMirror');
const headings = editorEl?.querySelectorAll('h1, h2, h3');
```

### 스크롤 위치 기반 활성 heading 감지
```typescript
// 에디터 스크롤 컨테이너의 scrollTop 기준으로
// 각 heading의 offsetTop을 비교하여 현재 보이는 heading 판별
const scrollContainer = document.getElementById('scroll-container');
scrollContainer?.addEventListener('scroll', () => {
    const scrollTop = scrollContainer.scrollTop;
    let activeHeading = headings[0];
    for (const h of headings) {
        if (h.offsetTop - 160 <= scrollTop) {
            activeHeading = h;
        }
    }
    setActiveId(activeHeading.id || activeHeading.textContent);
});
```

### TOC 클릭 → 에디터 이동
```typescript
const handleClick = (headingId: string) => {
    const target = editorEl?.querySelector(`[data-toc-id="${headingId}"]`)
        || editorEl?.querySelector(`h1, h2, h3`); // fallback
    target?.scrollIntoView({ behavior: 'smooth', block: 'start' });
};
```

### heading에 안정적 ID 부여
TipTap StarterKit의 Heading 확장에 ID를 자동 부여하면 좋음:
```typescript
// heading 텍스트 기반 ID 생성 (뷰 모드와 동일한 로직 사용)
Heading.configure({
    HTMLAttributes: { /* id는 별도 extension으로 */ }
})
```
또는 간단하게 heading 순서(index) 기반 ID 매칭.

## 주의사항
- 뷰 모드 TOC 기존 동작 깨뜨리지 않을 것
- 편집 모드에서 내용 변경(heading 추가/삭제) 시 TOC 동적 업데이트
- 성능: 스크롤 이벤트에 throttle/debounce 적용 (16ms 또는 requestAnimationFrame)
- TOC 영역 스크롤과 편집창 스크롤이 서로 간섭하지 않도록 `overscroll-behavior: contain`

## 테스트 체크리스트
- [ ] 편집 모드 진입 시 TOC 사이드바가 표시되는지
- [ ] 편집창 스크롤 시 TOC 하이라이트가 따라오는지
- [ ] TOC 클릭 시 편집창이 해당 위치로 이동하는지
- [ ] 마우스가 TOC 위에 있을 때 TOC만 스크롤되는지
- [ ] 마우스가 편집창 위에 있을 때 편집창만 스크롤되는지
- [ ] heading 추가/삭제 시 TOC가 동적으로 업데이트되는지
- [ ] 뷰 모드 TOC 기존 동작이 정상인지 (regression 없음)
- [ ] 모바일에서 편집 모드 TOC 동작 확인

## 프로젝트 경로
- 프로젝트 루트: `/home/jay/projects/insuwiki/`
- Next.js 앱: `/home/jay/projects/insuwiki/nextapp/`
- 빌드 확인: `cd /home/jay/projects/insuwiki/nextapp && npx next build`
- 로컬 테스트: `npm run dev` (포트 3000)

## 기술 참고
- Next.js 15 (App Router)
- TipTap 에디터 (ProseMirror 기반)
- TypeScript + Tailwind CSS
- Vercel 배포 (git push → 자동 배포)
