## 2026-05-25 — Files 탭: Obsidian-style Vault 시스템 + 마크다운 미리보기 안정화 + 트리 상태 영속화

### 배경

Wiki 탭은 DB-backed 노드 편집기로 큐레이션엔 좋지만, 프로젝트 루트의 `.md` 파일을 직접 활용하기엔 별도 인제스트가 필요했다. Obsidian처럼 디스크의 `.md` 파일 자체를 vault로 인식하고 `[[wikilink]]`를 파싱해 그래프를 그리면 큐레이션 없이도 프로젝트 문서를 바로 LLM에 주입할 수 있다. 이에 더해 Files 탭의 마크다운 미리보기가 렌더 오류 시 전체 React 트리를 날리는 문제, 상대 링크가 새 탭으로 열리는 문제, 탭 전환마다 트리 상태가 초기화되는 문제를 함께 수정했다.

### 주요 변경

#### 1. Obsidian-style Vault 시스템 (`9d343aa`)

프로젝트 루트의 모든 `.md` 파일을 스캔해 frontmatter(tags, title)와 `[[wikilink]]`를 파싱하고, ReactFlow 기반 그래프로 시각화. 기존 Wiki 탭을 제거하고 그래프 뷰를 Files 탭 우측 패널에 토글로 통합.

- **서버 — `src/server/services/file-scanner.ts`** (신규, 268줄): 재귀 `.md` 파일 스캔 + frontmatter 파싱 + `[[wikilink]]` 추출로 그래프 엣지 구성. `scanVault()` / `buildVaultGraph()` / `readVaultFile()` / `writeVaultFile()` / `deleteVaultFile()` / `renameVaultFile()` / `searchVault()` 제공
- **서버 — `src/server/services/vault-injector.ts`** (신규, 125줄): 파일 경로 기반 `<long_term_memory>` 블록 빌드. DB 노드 기반 `memory-injector` 대신 파일 내용을 직접 직렬화
- **서버 — `src/server/services/vault-retriever.ts`** (신규, 116줄): auto 모드에서 vault 파일 중 태스크 텍스트와 매칭되는 파일 자동 선택
- **서버 — `src/server/routes/vault.ts`** (신규, 191줄): 9개 REST 엔드포인트 — `files` (스캔), `graph` (그래프), `file` (읽기/쓰기/생성/삭제), `rename`, `preview` (주입 미리보기), `search` (텍스트 검색). path-traversal 보호 + `.md` 확장자 검증
- **서버 — `src/server/services/memory-inject-hook.ts`**: 듀얼 패스 — `vaultFilePaths`가 있으면 vault-injector, 없으면 기존 DB 노드 인젝터로 폴백
- **서버 — orchestrator / session-manager / discussion-orchestrator**: `vaultFilePaths` 컨텍스트 전파
- **클라이언트 — `src/client/src/components/VaultGraph.tsx`** (신규, 245줄): ReactFlow + force-directed 레이아웃. 노드 클릭 시 해당 파일을 미리보기에서 열기
- **클라이언트 — `src/client/src/components/VaultExplorer.tsx`** (신규, 478줄): 파일 트리 사이드바 + 에디터 + 그래프 토글
- **클라이언트 — `src/client/src/components/VaultInjectControl.tsx`** (신규, 203줄): task/session/discussion 폼용 파일 기반 주입 선택 (mode: none/auto/all/selected)
- **클라이언트 — `src/client/src/api/vault.ts`** (신규): vault REST 클라이언트 API
- **클라이언트 — `src/client/src/components/FileExplorer.tsx`**: 우측 패널에 GitBranch 아이콘 그래프 토글 추가. 그래프 노드 클릭 시 파일 미리보기로 전환
- **클라이언트 — `src/client/src/components/ProjectDetail.tsx`**: Wiki 탭 제거 (그래프가 Files 탭에 통합)
- **i18n**: vault 관련 EN/KO 키 58개 추가

#### 2. 마크다운 미리보기 블랙 스크린 수정 (`dd61f99`)

ReactMarkdown 렌더링 오류가 error boundary 없이 전체 React 트리를 크래시시켜 다크 모드에서 검은 화면만 남는 문제.

- **`src/client/src/components/FileExplorer.tsx`**: `RenderErrorBoundary` class 컴포넌트 추가 — 렌더 오류 시 raw 소스 텍스트(`<pre>`)로 폴백, 다른 파일 선택 시 자동 리셋. 미리보기 body에서 정의되지 않은 `--color-bg-page` CSS 변수 참조 제거

#### 3. 마크다운 상대 링크 인앱 내비게이션 + 선택 파일 영속화 (`af25d29`)

Files 탭의 마크다운 미리보기에서 `[label](./sibling.md)` 같은 상대 링크가 새 브라우저 탭에서 열리는 문제.

- **`src/client/src/components/MarkdownContent.tsx`**: `onLinkClick` prop 추가 — 상대 경로(`./`, `../`)는 현재 파일 기준 해석 후 인앱 버튼으로 렌더, 외부 URL은 `target="_blank"` 유지. fragment/query 스트리핑 + URL 디코드 처리
- **`src/client/src/components/FileExplorer.tsx`**: `selectedPath`를 프로젝트별 localStorage에 영속화. 프로젝트 전환 왕복 시 마지막 열람 파일 복원. dirty-check 확인 가드

#### 4. 트리 확장/숨김 파일/선택 파일 상태 영속화 (`430c112`)

탭 전환마다 FileExplorer의 트리 상태(확장된 디렉토리, 숨김 파일 토글, 선택 파일)가 초기화되는 문제.

- **`src/client/src/components/FileExplorer.tsx`**: 확장된 디렉토리 경로를 프로젝트별 localStorage에 영속화. 마운트 시 depth별 그룹화 후 각 레벨을 병렬 fetch로 복원. `showHidden` 토글도 localStorage 영속화. `loadedRef` 게이트로 초기 마운트 중 빈 상태가 저장 상태를 덮어쓰는 레이스 방지

### 수정된 주요 파일

| 파일 | 변경 내용 |
|------|----------|
| `src/server/services/file-scanner.ts` | 신규 — 재귀 `.md` 스캔 + frontmatter/wikilink 파싱 + 그래프 빌드 |
| `src/server/services/vault-injector.ts` | 신규 — 파일 기반 `<long_term_memory>` 블록 직렬화 |
| `src/server/services/vault-retriever.ts` | 신규 — auto 모드 vault 파일 매칭 |
| `src/server/routes/vault.ts` | 신규 — vault REST API 9개 엔드포인트 |
| `src/server/services/memory-inject-hook.ts` | 듀얼 패스 — vault 파일 경로 우선, DB 노드 폴백 |
| `src/client/src/components/VaultGraph.tsx` | 신규 — ReactFlow force-directed `.md` wikilink 그래프 |
| `src/client/src/components/VaultExplorer.tsx` | 신규 — vault 파일 트리 + 에디터 + 그래프 토글 |
| `src/client/src/components/VaultInjectControl.tsx` | 신규 — 파일 기반 주입 모드 선택 UI |
| `src/client/src/components/FileExplorer.tsx` | 그래프 토글 + error boundary + 링크 내비 + 상태 영속화 |
| `src/client/src/components/MarkdownContent.tsx` | 상대 링크 인앱 내비게이션 |
| `src/client/src/components/ProjectDetail.tsx` | Wiki 탭 제거 (그래프 Files 탭 통합) |

### 아키텍처 결정

1. **파일 기반 vs DB 기반 이중 경로**: vault(파일)와 기존 wiki(DB 노드)를 양립시킨 이유는 기존 DB 노드 데이터를 날리지 않으면서 파일 기반 워크플로를 점진적으로 도입하기 위함. `memory-inject-hook`이 `vaultFilePaths` 유무로 경로를 분기하고, 폼 UI는 `VaultInjectControl`로 교체해 새 프로젝트는 자연스럽게 vault를 사용하게 됨
2. **그래프를 Files 탭에 통합**: 별도 Wiki 탭을 유지하면 파일 탐색과 문서 그래프가 분리되어 컨텍스트 전환이 필요. Files 탭 우측 패널에 토글로 넣으면 파일 미리보기 ↔ 관계 그래프를 한 화면에서 전환 가능
3. **트리 상태 영속화는 depth-grouped 병렬 fetch**: 확장된 10개 디렉토리를 순차 fetch하면 복원이 느림. depth별로 그룹화해 같은 깊이의 디렉토리를 동시에 fetch하면 트리 깊이만큼의 라운드트립으로 줄어듦
