# Project Map Incremental Update System — 구현 Spec

## 1. 개요

기존 `project-map.py`에 incremental update 기능을 추가한다.
- 전체 재스캔(full) 모드: 기존 동작 유지
- 증분 업데이트(incremental) 모드: 변경/삭제된 파일만 처리

## 2. 데이터 구조

### 2.1 JSON 캐시 파일
위치: `{output_dir}/.project-map-cache-{project_id}.json`

```json
{
  "version": 1,
  "generated_at": "2026-03-03T15:00:00",
  "project_name": "insuwiki",
  "project_path": "/home/jay/projects/insuwiki",
  "depth": 3,
  "include_tests": false,
  "files": {
    "src/types/firestore.ts": {
      "hash": "sha256hex...",
      "section": "types",
      "data": {"types": ["UserRole", "User"]},
      "updated_at": "2026-03-03T15:00:00"
    },
    "src/app/api/ai/query/route.ts": {
      "hash": "sha256hex...",
      "section": "routes",
      "data": {"methods": ["POST"], "url": "/api/ai/query"},
      "updated_at": "2026-03-03T15:00:00"
    },
    "src/components/SearchModal.tsx": {
      "hash": "sha256hex...",
      "section": "components",
      "data": {"name": "SearchModal"},
      "updated_at": "2026-03-03T15:00:00"
    }
  },
  "tree_lines": ["insuwiki/", "├── src/", ...],
  "config": {
    "packages": [...],
    "tsconfig": [...]
  },
  "recent_files": [...]
}
```

### 2.2 Markdown 출력 파일
위치: `{output_path}` (기존과 동일)
JSON 캐시에서 렌더링하여 생성.

### 2.3 백업 파일
위치: `{output_path}.bak`
업데이트 직전 기존 Markdown 복사.

## 3. CLI 인터페이스

### 3.1 기존 (변경 없음)
```bash
python3 project-map.py <PROJECT_PATH> --output <OUTPUT_PATH> [--depth 3] [--include-tests]
```

### 3.2 신규 Incremental 모드
```bash
python3 project-map.py <PROJECT_PATH> --output <OUTPUT_PATH> \
  --incremental \
  --changed-files "file1.ts,file2.tsx" \
  --deleted-files "old-file.ts"
```

- `--incremental`: incremental 모드 활성화
- `--changed-files`: 변경/생성된 파일 목록 (쉼표 구분, 프로젝트 상대 경로)
- `--deleted-files`: 삭제된 파일 목록 (쉼표 구분, 프로젝트 상대 경로)

### 3.3 롤백
```bash
python3 project-map.py <PROJECT_PATH> --output <OUTPUT_PATH> --rollback
```
`.bak` 파일에서 복원.

## 4. Incremental Update 알고리즘

```
1. Lock 획득 (fcntl.LOCK_EX, timeout 30s)
2. JSON 캐시 로드 (없으면 full scan 수행 후 캐시 생성)
3. 각 changed_file:
   a. validate_path() — 경로 검증
   b. 파일 존재 확인
   c. SHA-256 hash 계산
   d. 기존 hash와 비교 → 동일하면 skip
   e. 파일 분류 (types/routes/components/config)
   f. 해당 섹션 데이터 재추출
   g. JSON 캐시 노드 업데이트
4. 각 deleted_file:
   a. JSON 캐시에서 해당 노드 삭제
5. Directory Tree 재생성
6. recent_files 업데이트
7. version += 1
8. JSON 캐시 저장 (atomic write: temp → rename)
9. Markdown 재렌더링 (JSON → Markdown)
10. .bak 백업 후 Markdown 저장 (atomic write)
11. Lock 해제
```

## 5. 핵심 클래스/함수

### 5.1 IncrementalUpdater 클래스
```python
class IncrementalUpdater:
    def __init__(self, project_root: Path, output_path: Path, depth: int, include_tests: bool):
        self.project_root = project_root
        self.output_path = output_path
        self.cache_path = self._get_cache_path()
        self.lock_path = self._get_lock_path()
        self.depth = depth
        self.include_tests = include_tests

    def update(self, changed_files: list[str], deleted_files: list[str]) -> None:
        """변경/삭제 파일 기반 incremental 업데이트"""

    def full_scan_to_cache(self) -> dict:
        """전체 스캔 → JSON 캐시 생성"""

    def load_cache(self) -> dict | None:
        """JSON 캐시 로드"""

    def save_cache(self, cache: dict) -> None:
        """JSON 캐시 저장 (atomic write)"""

    def render_markdown(self, cache: dict) -> str:
        """JSON 캐시 → Markdown 렌더링"""

    def _classify_file(self, rel_path: str) -> str:
        """파일을 섹션으로 분류 (types/routes/components/config/other)"""

    def _extract_file_data(self, rel_path: str, section: str) -> dict:
        """파일에서 해당 섹션 데이터 추출"""

    def _compute_hash(self, file_path: Path) -> str:
        """SHA-256 해시 계산"""

    def _validate_path(self, rel_path: str) -> Path:
        """경로 검증 (Path Traversal 방지)"""

    def _acquire_lock(self) -> file:
        """flock 획득"""

    def _release_lock(self, lock_fd) -> None:
        """flock 해제"""
```

### 5.2 보안 함수
```python
def validate_path(path: str, base_dir: str) -> str:
    """경로 정규화 + 범위 검증"""

SENSITIVE_PATTERNS = [".env", "*.pem", "*credentials*", "*.key", "*.secret"]
```

## 6. 파일 분류 규칙

| 파일 패턴 | 섹션 | 추출 함수 |
|-----------|------|-----------|
| *.ts (not .d.ts) | types | extract_types_interfaces (단일 파일) |
| route.ts/route.js in app/api/ | routes | extract_api_routes (단일 파일) |
| *.tsx in components/ | components | extract_components (단일 파일) |
| package.json | config | summarize_package_json |
| tsconfig.json | config | summarize_tsconfig |
| 기타 | tree_only | tree 반영만 |

## 7. 동시성 보장

- fcntl.LOCK_EX: 한 번에 하나의 프로세스만 구조맵 수정
- Timeout 30초: 초과 시 에러 반환 (블로킹 방지)
- Atomic write: tempfile → os.rename()
- Version counter: 캐시에 version 필드 관리

## 8. 테스트 계획

### 8.1 Unit Tests
- test_validate_path: 정상/비정상 경로 검증
- test_compute_hash: hash 계산 정확성
- test_classify_file: 파일 분류 정확성
- test_extract_file_data: 각 섹션별 데이터 추출
- test_render_markdown: JSON → Markdown 렌더링

### 8.2 Integration Tests
- test_incremental_vs_full: incremental 결과 == full scan 결과 (shadow comparison)
- test_file_deletion: 삭제 후 구조맵에서 제거 확인
- test_rollback: 롤백 후 이전 상태 복원 확인

### 8.3 Edge Case Tests
- test_empty_changed_files: 빈 변경 목록
- test_nonexistent_file: 존재하지 않는 파일 처리
- test_path_traversal: ../../ 경로 차단
- test_sensitive_file_exclusion: .env 등 제외 확인
- test_concurrent_access: 동시 접근 시 데이터 무결성

## 9. 수정 파일 목록
- scripts/project-map.py (주 수정 대상)
- memory/project-maps/ (캐시 파일 자동 생성)

## 10. 수정 금지 파일
- dispatch.py, chain.py, memory/task-timer.py
- team_prompts.py의 _build_glm_prompt
