# GPU 서버 재구성 + PKM 프로젝트 연계 계획 ## Context GPU 서버(RTX 4070Ti Super)에서 Mac Mini와 중복되는 LLM 모델(qwen3.5:9b, id-9b)을 제거하고, 대신 Surya OCR + bge-m3 임베딩 서비스를 배치하여 역할을 명확히 분리한다. 추가로 Komga(만화 서버)를 Mac Mini에서 GPU 서버로 이전하여 Surya OCR과 로컬 연동 가능하게 한다. 기존 PKM 프로젝트(`~/Documents/code/DEVONThink_my server/`)와 연계하여: - ChromaDB → Qdrant 마이그레이션 - nomic-embed-text → bge-m3 통일 - Qwen2.5-VL-7B 비전 OCR → Surya OCR 전용 대체 - architecture.md, embed 스크립트, AppleScript 등 관련 코드/문서 일괄 갱신 PKM 프로젝트는 현재 Phase 1 완료(90%), Phase 2(인프라 수정+버그 픽스) 착수 대기 상태. 이번 GPU 서버 재구성은 Phase 2와 병행하여 인프라 변경을 반영한다. --- ## 현재 상태 요약 ### GPU 서버 (192.168.1.186) - Ryzen 7 7800X3D / 30GB RAM / RTX 4070Ti Super 16GB VRAM - **서비스**: Ollama(11434) + no-think proxy(11435), Plex(32400) - **Ollama 모델**: qwen3.5:9b-q8_0(10GB), id-9b(10GB) ← **제거 확정** - CUDA 드라이버 580.x 설치됨, nvcc(CUDA toolkit) 미설치 - Docker 미설치, Python 3.12 - NAS SMB/NFS 마운트 미설정 ### Mac Mini (192.168.1.122) - M4 Pro / 64GB / MLX Qwen3.5-35B(8800), Ollama bge-m3(11434) - **Docker**: Qdrant(6333), Komga(25600), NanoClaw(9801), tk-ai-service(30400) 등 - **PKM 프로젝트**: `~/Documents/code/DEVONThink_my server/` - `embed_to_chroma.py` → GPU 서버 nomic-embed-text + ChromaDB ← **Qdrant + bge-m3로 변경** - `auto_classify.scpt` → MLX localhost:8800으로 분류, Step 4에서 embed_to_chroma.py 호출 - `pkm_api_server.py` → Flask 9900번 포트 (stats 500 에러, 한글 인코딩 버그 있음) - `architecture.md` → GPU Tier 3에 nomic-embed + VL-7B + reranker 계획 ← **갱신 필요** - **DEVONthink 4**: 13개 DB, Smart Rule 3개 설계 완료 ### 영향받는 외부 서비스 - `tk-ai-service` docker-compose.yml: `OLLAMA_TEXT_MODEL=qwen3.5:9b-q8_0` → **변경 필요** - `paperless-gpt`: `qwen3:8b` 참조 → docker-compose 존재하나 **현재 미실행** (docker ps에 없음), Phase 1에서 처리 방침 결정 필요 ### NAS IP 참고 - NAS LAN IP: `192.168.1.227` (nginx-ssl.conf upstream에서 확인됨) - NAS Tailscale IP: `100.101.79.37` - NFS 마운트는 **LAN 직결 (192.168.1.227)** 사용 (성능상 최적) --- ## 변경 계획 ### Phase 1: GPU 서버 정리 (선행) **1-1. Ollama 모델 제거** ```bash ssh 192.168.1.186 ollama rm qwen3.5:9b-q8_0 ollama rm id-9b ``` **1-2. 새 모델 설치** ```bash ollama pull bge-m3 # 임베딩 (1024차원, 한국어 우수) ollama pull bge-reranker-v2-m3 # RAG 리랭킹 ``` - 임베딩 모델: `nomic-embed-text`(768차원) 대신 `bge-m3`(1024차원)으로 통일 - 이유: Mac Mini Ollama에서 이미 bge-m3 사용 중, 한국어 성능 우수, Qdrant tk_qc_issues 컬렉션도 1024차원 **1-3. Ollama no-think proxy(11435) 비활성화** - LLM 모델 제거 후 think:false 주입이 불필요 - `sudo systemctl disable --now ollama-proxy` **1-4. Ollama systemd 환경 조정** ```ini # /etc/systemd/system/ollama.service [Service] 섹션에 추가 Environment="OLLAMA_MAX_LOADED_MODELS=2" Environment="OLLAMA_KEEP_ALIVE=30m" ``` **1-5. paperless-gpt 처리** - 현재 미실행 상태 (docker ps에 없음) - docker-compose.yml에 `qwen3:8b` 참조 → GPU 서버 모델 제거 시 사용 불가 - 옵션: (a) MLX 35B로 전환 (b) 당분간 비활성 유지 (c) 폐기 - Paperless-ngx 자체가 활발히 사용 중인지 확인 후 결정 **1-6. tk-ai-service 코드 + 설정 변경** (Mac Mini 유지, 코드 수정 필수) tk-ai-service는 Ollama 네이티브 API(`/api/chat`, `/api/embeddings`)를 사용 중. MLX 서버는 OpenAI API(`/v1/chat/completions`)만 지원하므로 코드 수정 필요. **a) `ollama_client.py` → `llm_client.py` 리팩터링** - `generate_text()`: `/api/chat` → `/v1/chat/completions` (OpenAI 형식) - 요청: `{"model":"...","messages":[...],"stream":false}` - 응답: `response.json()["choices"][0]["message"]["content"]` - `generate_embedding()`: 변경 없음 (GPU Ollama `/api/embeddings` 그대로) - `check_health()`: text URL `/api/tags` → `/v1/models` 또는 단순 GET 체크 - 클래스명/파일명 변경 고려 (OllamaClient → LLMClient) **b) docker-compose.yml 환경변수 변경** ```yaml # ~/docker/tk-ai-service/docker-compose.yml - OLLAMA_BASE_URL=http://host.internal:8800 # Mac Mini MLX 서버 (OpenAI API) - OLLAMA_TEXT_MODEL=mlx-community/Qwen3.5-35B-A3B-4bit - OLLAMA_EMBED_URL=http://192.168.1.186:11434 # GPU 서버 Ollama (임베딩) - OLLAMA_EMBED_MODEL=bge-m3 # 변경 없음 ``` **c) config.py 주석 갱신** ```python # Mac Mini MLX (텍스트 생성) — OpenAI 호환 API OLLAMA_BASE_URL: str = "http://host.internal:8800" # GPU 서버 Ollama (임베딩) OLLAMA_EMBED_URL: str = "http://192.168.1.186:11434" ``` ### Phase 1.5: GPU 서버 Docker + NFS + Komga 이전 **1.5-1. Docker 설치** (GPU 서버) ```bash # Docker Engine (Ubuntu) sudo apt-get update sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin sudo usermod -aG docker hyungi # nvidia-container-toolkit (Surya OCR Docker化 시 필요, 당장은 불필요) ``` **1.5-2. NAS NFS 마운트 설정** Synology NAS 측: - DSM → 제어판 → 파일 서비스 → NFS 활성화 (v4.1) - 공유 폴더(Comic) → NFS 권한: `192.168.1.186` 단일 IP, 읽기 전용, root_squash GPU 서버 측: ```bash sudo apt install nfs-common sudo mkdir -p /mnt/comic # /etc/fstab 추가: 192.168.1.227:/volume1/Comic /mnt/comic nfs4 ro,nosuid,noexec,nodev,soft,timeo=15 0 0 sudo mount -a ``` **1.5-3. Komga Docker 이전** GPU 서버에 docker-compose.yml 생성: ```yaml # /opt/komga/docker-compose.yml services: komga: image: gotson/komga container_name: komga ports: - "25600:25600" volumes: - /mnt/comic:/data/comics:ro # NFS 마운트 (읽기 전용) - ./config:/config # Komga 설정/DB environment: - TZ=Asia/Seoul restart: unless-stopped ``` **1.5-4. Mac Mini 측 변경** - Mac Mini Komga 컨테이너 중지: `docker stop komga && docker rm komga` - nginx upstream 변경: ``` # nginx-ssl.conf upstream komga_backend { server 192.168.1.186:25600; # GPU 서버로 변경 } ``` - nginx 재시작: `docker restart home-service-proxy` - Mac Mini Docker VM 메모리 **1.23GB 회수** **1.5-5. Komga 설정 마이그레이션** - Mac Mini의 Komga config/DB를 GPU 서버로 복사 (라이브러리 메타데이터, 사용자 설정 유지) - 경로: Mac Mini `~/docker/Komga/` → GPU `scp`로 전송 - **주의**: Komga 내부 DB(H2)에 라이브러리 절대경로가 저장되어 있음 - Mac Mini: `/data/comics` (Docker 내부 마운트 경로) - GPU 서버: `/data/comics` (동일하게 Docker 마운트하면 경로 변경 불필요) - Docker 내부 경로를 동일하게 맞추면 DB 마이그레이션 문제 없음 - 만약 경로가 달라지면 Komga UI에서 라이브러리 경로 재설정 또는 전체 재스캔 필요 ### Phase 2: Surya OCR 설치 **2-1. PyTorch CUDA 런타임 확인** (GPU 서버) - Surya OCR은 PyTorch에 의존 → PyTorch 설치 시 CUDA 런타임이 번들됨 - 별도 `nvidia-cuda-toolkit` 설치가 **불필요할 수 있음** (nvcc는 직접 CUDA 코드 컴파일 시만 필요) - GPU 서버에서 확인: ```bash # PyTorch CUDA 지원 확인 python3 -c "import torch; print(torch.cuda.is_available())" # 안 되면 CUDA 번들 포함 PyTorch 설치 pip install torch --index-url https://download.pytorch.org/whl/cu124 ``` **2-2. Surya OCR 서비스 구성** ``` /opt/surya-ocr/ venv/ # Python venv (surya-ocr, fastapi, uvicorn, python-multipart) server.py # FastAPI 래퍼 ``` 서버 엔드포인트: - `POST /ocr` — 파일 업로드 → OCR 텍스트 + 바운딩박스 반환 - `POST /ocr/layout` — 레이아웃 분석 포함 - `GET /health` — 상태 확인 **2-3. systemd 서비스 등록** ```ini # /etc/systemd/system/surya-ocr.service [Unit] Description=Surya OCR Service After=network-online.target [Service] ExecStart=/opt/surya-ocr/venv/bin/uvicorn server:app --host 0.0.0.0 --port 8400 WorkingDirectory=/opt/surya-ocr Restart=always RestartSec=5 [Install] WantedBy=multi-user.target ``` **VRAM 예산 (변경 후)** | 컴포넌트 | VRAM | 비고 | |----------|------|------| | Plex HW 트랜스코드 | ~1-2GB | 활성 시 | | Surya OCR | ~2-3GB | 활성 시 | | bge-m3 임베딩 | ~1.5GB | 상시 | | bge-reranker | ~1GB | 온디맨드 | | **합계 (피크)** | **~7-8GB / 16GB** | 여유 충분 | ### Phase 3: 벡터 DB 통합 (ChromaDB → Qdrant) + PKM 코드 갱신 **결정: Qdrant로 통일, ChromaDB 폐기** - Qdrant가 이미 Mac Mini Docker에서 운영 중 (tk_qc_issues 컬렉션) - ChromaDB는 embed_to_chroma.py에서만 계획/사용 - 2개 벡터 DB 운영은 불필요한 복잡성 **3-1. Qdrant에 pkm_documents 컬렉션 생성** ``` dimension: 1024 (bge-m3) distance: cosine payload 필드: uuid, title, database, tags, source_channel ``` **3-2. `scripts/embed_to_chroma.py` → `scripts/embed_to_qdrant.py` 리라이트** - `chromadb` → `qdrant-client` 교체 - GPU 서버 임베딩 모델: `nomic-embed-text` → `bge-m3` - Ollama API: `/api/embed` 사용 (배치 지원, `{"model":"bge-m3","input":["텍스트"]}`) - 현재 auto_classify.scpt에서 문서 단건 호출이므로 단일/배치 모두 가능 - 향후 embed-batch 엔드포인트에서 배치 활용 가능 - 텍스트 청킹 추가 (500토큰, 50토큰 오버랩) - `pkm_utils.load_credentials()`에서 GPU_SERVER_IP 로드 - **기존 `embed_to_chroma.py`는 `git rm`으로 삭제** (GPU_SERVER_IP 미설정으로 실행된 적 없음, 실 데이터 없음) **3-3. `applescript/auto_classify.scpt` Step 4 수정 + 버그 픽스** - 현재: `do shell script "python3 ~/scripts/embed_to_chroma.py " & docUUID & " &"` - 변경: `embed_to_qdrant.py` 호출로 교체 + baseDir 변수 사용 - **버그 픽스**: 73행 `add custom meta data "inbox_route" for "sourceChannel"` 삭제 - 70행에서 AI 분류 결과로 설정한 sourceChannel을 "inbox_route"로 덮어쓰는 버그 **3-4. requirements.txt 업데이트** (dev-roadmap 9단계와 합산, 단일 커밋) ``` - chromadb>=0.4.0 - schedule>=1.2.0 # 미사용 확인 후 제거 + qdrant-client>=1.7.0 + flask>=3.0.0 # dev-roadmap 9단계 + gunicorn>=21.2.0 # dev-roadmap 9단계 anthropic>=0.40.0 # 유지 (향후 Tier 2용) ``` **3-5. credentials.env + credentials.env.example 업데이트** ``` # credentials.env (Mac mini) GPU_SERVER_IP=192.168.1.186 # credentials.env.example (git 추적) GPU_SERVER_IP=192.168.1.xxx ``` **3-6. `docs/architecture.md` 대규모 갱신** (별도 커밋) - **변경 규모**: ChromaDB 28건, nomic-embed 12건, VL-7B 5건 — 문맥별 수정 필요 (단순 치환 불가) - 주요 변경 영역: - AI 통합 아키텍처 다이어그램 (Tier 3 모델 목록: nomic→bge-m3, VL-7B→Surya OCR) - VRAM 배분 다이어그램 (~11.3GB → ~7-8GB) - 자동화 파이프라인 / Smart Rule 설계 (ChromaDB→Qdrant, embed 스크립트 경로) - AI 결과물 저장 전략 표 (ChromaDB→Qdrant) - 임베딩 이전 근거 테이블 (nomic→bge-m3 반영) - 3-Tier AI 라우팅 전략 표 - 코드 예시 내 경로/모델명 - 이 작업은 **별도 시간을 잡아서** 전체 문서를 통독하며 진행 ### Phase 4: DEVONthink OCR 연동 **4-1. `scripts/ocr_preprocess.py` 신규 작성** - DEVONthink UUID → AppleScript로 파일 경로 추출 → Surya API(GPU:8400) 호출 → OCR 텍스트 반환 - `pkm_utils.run_applescript_inline()` 재사용 - 반환값: OCR 텍스트 (plain text) — DEVONthink 본문에 병합용 **4-2. `applescript/auto_classify.scpt` Smart Rule 수정** - architecture.md의 Rule 1 설계에 따라 Step 0(OCR) 추가: ``` 현재: Step 1(MLX 분류) → Step 2(태그 파싱) → Step 3(DB 이동) → Step 4(임베딩) → Step 5(메타) 변경: Step 0(OCR 감지+처리) → Step 1(MLX 분류) → ... → Step 4(Qdrant 임베딩) ``` - OCR 대상 감지 조건 (단순 텍스트 길이 < 50 대신 정교한 판별): - `type of theRecord` = PDF **AND** `plain text of theRecord` = "" (텍스트 레이어 없음) - 또는 `type of theRecord` ∈ {JPEG, PNG, TIFF} (이미지 파일) - DEVONthink 자체가 PDF 텍스트 레이어를 읽으므로, OCR이 필요한 건 **텍스트가 완전히 비어있는 경우**뿐 - Surya OCR 호출 → `set plain text of theRecord to ocrText` 로 본문 병합 - 기존 Qwen2.5-VL-7B 비전 OCR 계획 → Surya 전용 OCR로 대체 (정확도 + ABBYY 대체) **4-3. `docs/architecture.md` Rule 1 갱신** - "이미지/스캔 문서 → GPU 서버 VL-7B로 OCR" → "Surya OCR(:8400)으로 OCR" ### Phase 5: RAG 파이프라인 (PKM API 확장) **5-1. pkm_api_server.py에 RAG 엔드포인트 추가** - 현재 docstring(7행): "범위: DEVONthink + OmniFocus 전용. 이 이상 확장하지 않을 것." - RAG는 DEVONthink 문서 검색 기반이므로 동일 범위의 확장으로 간주 - docstring을 "범위: DEVONthink + OmniFocus + RAG 검색" 으로 갱신 ``` POST /rag/query # 질문 → 임베딩 → Qdrant 검색 → 리랭킹 → LLM 답변 POST /devonthink/embed # 단일 문서 임베딩 트리거 POST /devonthink/embed-batch # 배치 임베딩 ``` **5-2. RAG 쿼리 플로우** ``` 질문 텍스트 → GPU 서버 bge-m3로 쿼리 임베딩 (192.168.1.186:11434) → Mac Mini Qdrant에서 유사도 검색 (localhost:6333, top-20) → GPU 서버 bge-reranker로 리랭킹 (top-5) → Mac Mini MLX Qwen3.5-35B로 답변 생성 (localhost:8800) → DEVONthink 링크(x-devonthink-item://UUID) 포함 응답 ``` ### Phase 6: NanoClaw + Komga 연동 (후순위, 별도 계획) Phase 5 완료 후 별도 문서로 상세 계획 수립. 현재는 방향만 기록: - **NanoClaw RAG**: PKM API `/rag/query` 엔드포인트 호출 → 시놀로지 Chat에서 "@이드 [질문]" → 문서 기반 답변 - **Komga OCR**: Komga REST API → Surya OCR → Qdrant `komga_manga` 컬렉션 - dev-roadmap.md에는 "향후 계획" 수준으로만 언급 --- ## 변경 후 아키텍처 ``` ┌─ Mac Mini M4 Pro ─────────────────────┐ ┌─ GPU 서버 (4070Ti) ─────────┐ │ │ │ │ │ MLX Qwen3.5-35B (:8800) — LLM 추론 │ │ Ollama (:11434) │ │ MLX Proxy (:8801) — Synology 연동 │◄───►│ ├─ bge-m3 (임베딩) │ │ Ollama (:11434) — bge-m3 로컬 폴백 │ │ └─ bge-reranker (리랭킹) │ │ Qdrant (:6333) — 벡터 검색 │ │ │ │ PKM API (:9900) — RAG 오케스트레이션 │ │ Surya OCR (:8400) │ │ NanoClaw (:9801) — AI 어시스턴트 │ │ Plex (:32400) — HW 트랜스코드│ │ DEVONthink — 문서 허브 │ │ Komga (:25600) — 만화 서버 │ │ nginx proxy (:443) — 리버스 프록시 │ │ └─ NFS → NAS /Comic (ro) │ │ │ │ │ └────────────────────────────────────────┘ │ [제거됨] │ ▲ │ ├─ qwen3.5:9b-q8_0 │ │ ┌─ NAS ──────┐ │ ├─ id-9b │ └──────────────│ 문서/미디어 │────────│ └─ no-think proxy (:11435)│ └────────────┘ └──────────────────────────────┘ ``` ## 수정 대상 파일 목록 ### GPU 서버 | 파일 | 변경 | |------|------| | Ollama 모델 | `rm qwen3.5:9b-q8_0`, `rm id-9b` / `pull bge-m3`, `pull bge-reranker-v2-m3` | | `/etc/systemd/system/ollama.service` | 환경변수 추가 (MAX_LOADED_MODELS, KEEP_ALIVE) | | `/etc/systemd/system/ollama-proxy.service` | **비활성화** (disable --now) | | `/opt/surya-ocr/server.py` | **신규** — FastAPI OCR 서버 | | `/etc/systemd/system/surya-ocr.service` | **신규** — systemd 유닛 | | Docker Engine | **신규 설치** | | `/etc/fstab` | NFS 마운트 추가 (NAS Comic → /mnt/comic, ro) | | `/opt/komga/docker-compose.yml` | **신규** — Komga 컨테이너 | ### PKM 프로젝트 (`~/Documents/code/DEVONThink_my server/`) | 파일 | 변경 | |------|------| | `scripts/embed_to_chroma.py` | → `scripts/embed_to_qdrant.py` 리라이트 (chromadb→qdrant-client, nomic→bge-m3) | | `scripts/ocr_preprocess.py` | **신규** — Surya OCR 호출 헬퍼 | | `scripts/pkm_api_server.py` | RAG 엔드포인트 추가 (/rag/query, /devonthink/embed) | | `scripts/pkm_utils.py` | 변경 없음 (`load_credentials()`에 이미 GPU_SERVER_IP 지원, 74행) | | `applescript/auto_classify.scpt` | Step 0(OCR 감지) 추가 + Step 4 embed_to_qdrant.py로 변경 | | `requirements.txt` | `chromadb` → `qdrant-client`, `flask` 추가 (dev-roadmap 9단계 합산) | | `docs/architecture.md` | Tier 3 모델, VRAM 다이어그램, ChromaDB→Qdrant, Smart Rule 전체 갱신 | | `docs/dev-roadmap.md` | GPU 서버 재구성 Phase 반영 | | `docs/claude-code-commands.md` | GPU 서버 관련 단계 추가 | | `credentials.env` (Mac mini) | `GPU_SERVER_IP=192.168.1.186` 추가 | | `credentials.env.example` | GPU_SERVER_IP 항목 추가 | ### Mac Mini 기타 | 파일 | 변경 | |------|------| | `~/docker/tk-ai-service/docker-compose.yml` | BASE_URL → MLX :8800, EMBED_URL → GPU :11434 | | `~/docker/tk-factory-services/ai-service/services/ollama_client.py` | Ollama API → OpenAI API 전환 (generate_text, check_health) | | `~/docker/tk-factory-services/ai-service/config.py` | 주석 갱신 | | `~/docker/home-service-proxy/nginx-ssl.conf` | `komga_backend` upstream → `192.168.1.186:25600` | | Mac Mini Komga 컨테이너 | **중지 및 제거** (1.23GB Docker VM 메모리 회수) | ## 검증 방법 1. **Phase 1.5 검증**: - `ssh GPU "docker ps"` → komga 컨테이너 실행 중 - `ssh GPU "ls /mnt/comic"` → NAS 만화 파일 목록 확인 - `curl http://192.168.1.186:25600` → Komga 웹 UI 접근 - `curl https://komga.hyungi.net` → nginx 프록시 경유 접근 확인 - Mac Mini: `docker ps | grep komga` → 없음 (제거 완료) 2. **Phase 1 검증**: - `ssh GPU "ollama list"` → bge-m3, bge-reranker만 존재 - `ssh GPU "systemctl status ollama-proxy"` → inactive - `ssh GPU "curl localhost:11434/api/embed -d '{\"model\":\"bge-m3\",\"input\":[\"test\"]}'` → 1024차원 벡터 반환 - Qdrant 차원 확인: `curl localhost:6333/collections/tk_qc_issues` → vector size=1024 확인 (bge-m3와 일치) - tk-ai-service 코드 수정 후: `docker compose build && docker compose up -d` - `curl http://localhost:30400/health` → ollama_text(MLX), ollama_embed(GPU) 모두 connected - `curl -X POST http://localhost:30400/api/chat -d '{"message":"테스트"}'` → MLX 35B 응답 확인 2. **Phase 2 검증**: `curl -F "file=@test.pdf" http://192.168.1.186:8400/ocr` → OCR 텍스트 반환 3. **Phase 3 검증**: - `curl http://localhost:6333/collections/pkm_documents` → 컬렉션 존재 - `python3 scripts/embed_to_qdrant.py <테스트UUID>` → Qdrant에 벡터 저장 확인 - `git diff` → embed_to_chroma.py 삭제, embed_to_qdrant.py 생성 확인 4. **Phase 4 검증**: DEVONthink Inbox에 스캔 PDF(텍스트 없는) 추가 → Smart Rule → OCR 텍스트 병합 → 분류 완료 5. **Phase 5 검증**: `curl -X POST localhost:9900/rag/query -d '{"q":"산업안전 법령"}'` → 관련 문서 + 답변 반환 6. **Phase 6**: 후순위, 별도 계획 시 검증 방법 수립 ## 실행 순서 ``` Phase 1 (GPU 정리 + 모델 교체) ──┐ Phase 1.5(Docker + NFS + Komga) ──┼── GPU 서버 작업 (SSH) Phase 2 (Surya OCR 설치) ────────┘ Phase 3 (Qdrant 통합 + PKM 코드) ──┐── PKM 프로젝트 코드 수정 Phase 4 (DEVONthink OCR 연동) ─────┘ → git commit & push → Mac mini에서 git pull Phase 5 (RAG 파이프라인) ──────── PKM API 확장 Phase 6 (NanoClaw/Komga OCR) ─── 후순위 ``` Phase 1~2는 GPU 서버 SSH 작업, Phase 3~4는 PKM 프로젝트 코드 수정. Phase 1 완료 시점에 tk-ai-service docker-compose도 함께 변경. 각 Phase는 독립적으로 검증 가능. **PKM dev-roadmap과의 관계:** - 이 계획의 Phase 3~4 = dev-roadmap Phase 2의 일부 (인프라 수정) - requirements.txt, AppleScript 경로, credentials.env 변경이 겹침 → 합쳐서 진행 **문서 통합 전략:** - `docs/dev-roadmap.md`: GPU 서버 재구성 Phase를 기존 Phase 2 앞에 "Phase 1.5: GPU 서버 재구성" 으로 삽입, Phase 2 항목에서 겹치는 변경(requirements.txt, credentials.env) 연결 - `docs/claude-code-commands.md`: Phase 2 섹션에 GPU 서버 관련 실행 단계 추가 (SSH 명령, Surya 설치, Qdrant 컬렉션 생성 등) - 이 계획서는 `docs/gpu-restructure.md`로 정식 문서화 (아키텍처 결정 근거 기록으로 보존)