# Claude Code 실행 명령어 — PKM 시스템 구축 > 작업 위치: MacBook Pro ~/Documents/code/DEVONThink_my server/ > 또는 Cowork 모드에서 마운트된 폴더 > 완성 후 Gitea에 push → Mac mini에서 pull ``` 개발/배포 흐름: MacBook Pro (Claude Code / Cowork) ~/Documents/code/DEVONThink_my server/ → 스크립트/설정 파일 작성 → git commit & push │ ▼ Gitea (Synology NAS) https://git.hyungi.net/hyungi/devonthink_home.git │ ▼ Mac mini (git pull → 실행) ``` --- # Phase 1: 초기 구축 (완료) > 2026-03-26 ~ 03-27 작업. 총 15 커밋. ## 0단계: 프로젝트 구조 생성 + credentials.env ✅ 완료 ```bash # Mac mini에서 mkdir -p ~/.config/pkm nano ~/.config/pkm/credentials.env chmod 600 ~/.config/pkm/credentials.env ``` ## 1단계: 프로젝트 구조 + requirements.txt ✅ 완료 생성된 파일: README.md, requirements.txt, .gitignore, credentials.env.example, 전체 디렉토리 구조 ## 2단계: AI 분류 프롬프트 ✅ 완료 - MLX 서버(localhost:8800) OpenAI 호환 API로 전환됨 - Qwen3.5 thinking 모드 대응 완료 (JSON 추출 후처리) - 프롬프트: scripts/prompts/classify_document.txt ## 3단계: AppleScript ✅ 완료 - applescript/auto_classify.scpt — Inbox 자동 분류 - applescript/omnifocus_sync.scpt — OmniFocus 작업 생성 ## 4단계: 법령 모니터링 ⚠️ 부분 완료 - scripts/law_monitor.py 작성 완료 - 외국 법령 (US OSHA 1건, JP 厚労省 10건, EU-OSHA 5건) 수집 성공 - ❌ 한국 법령 API: IP 등록 미완 → Phase 2에서 해결 ## 5단계: MailPlus 이메일 수집 ❌ 연결 실패 - scripts/mailplus_archive.py 코드 완성 - ❌ IMAP 접속 실패 (Connection refused) → Phase 2에서 해결 ## 6단계: Daily Digest ⚠️ 미테스트 - scripts/pkm_daily_digest.py 코드 완성 - 실행 테스트 미진행 → Phase 2 이후 테스트 ## 7단계: DEVONagent 가이드 ✅ 완료 - docs/devonagent-setup.md — 9개 검색 세트 설정 가이드 ## 8단계: 전체 테스트 ❌ 미진행 - tests/test_classify.py 작성 완료 - docs/test-report.md 미생성 → Phase 4에서 진행 ## 추가: PKM API 서버 (계획 외 생성) - scripts/pkm_api_server.py — Flask REST API (포트 9900) - DEVONthink + OmniFocus 상태 조회용 - 기본 동작 확인됨, 버그 있음 → Phase 2에서 수정 --- # Phase 1.5: GPU 서버 재구성 (Phase 2와 병행) > 상세 계획: docs/gpu-restructure.md 참조 > GPU 서버 SSH 작업 + PKM 프로젝트 코드 수정 ## GPU-1단계: GPU 서버 Ollama 모델 교체 ```bash # GPU 서버에서 실행 (ssh 192.168.1.186) # 1. 기존 LLM 모델 제거 ollama rm qwen3.5:9b-q8_0 ollama rm id-9b # 2. 임베딩/리랭킹 모델 설치 ollama pull bge-m3 ollama pull bge-reranker-v2-m3 # 3. no-think proxy 비활성화 sudo systemctl disable --now ollama-proxy # 4. Ollama systemd 환경 조정 sudo systemctl edit ollama # Environment="OLLAMA_MAX_LOADED_MODELS=2" # Environment="OLLAMA_KEEP_ALIVE=30m" sudo systemctl daemon-reload && sudo systemctl restart ollama # 5. 검증 ollama list # → bge-m3, bge-reranker만 존재 curl localhost:11434/api/embed -d '{"model":"bge-m3","input":["테스트"]}' # → 1024차원 벡터 ``` ## GPU-2단계: tk-ai-service 코드 수정 (Mac Mini) ``` tk-ai-service의 ollama_client.py를 OpenAI API 호환으로 리팩터링해줘. 변경 대상: ~/docker/tk-factory-services/ai-service/services/ollama_client.py → generate_text(): /api/chat → /v1/chat/completions → check_health(): /api/tags → /v1/models → generate_embedding(): 변경 없음 (GPU Ollama 유지) docker-compose.yml 환경변수: OLLAMA_BASE_URL=http://host.internal:8800 (MLX) OLLAMA_TEXT_MODEL=mlx-community/Qwen3.5-35B-A3B-4bit OLLAMA_EMBED_URL=http://192.168.1.186:11434 (GPU) 검증: docker compose build && docker compose up -d curl http://localhost:30400/health → 모두 connected ``` ## GPU-3단계: Docker + NFS + Komga 이전 ```bash # GPU 서버에서 실행 (ssh 192.168.1.186) # 1. Docker 설치 sudo apt-get update sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin sudo usermod -aG docker hyungi # 2. NFS 마운트 sudo apt install nfs-common sudo mkdir -p /mnt/comic echo '192.168.1.227:/volume1/Comic /mnt/comic nfs4 ro,nosuid,noexec,nodev,soft,timeo=15 0 0' | sudo tee -a /etc/fstab sudo mount -a ls /mnt/comic # 확인 # 3. Komga 컨테이너 시작 sudo mkdir -p /opt/komga && cd /opt/komga # docker-compose.yml 생성 (gpu-restructure.md Phase 1.5-3 참조) docker compose up -d # Mac Mini에서: docker stop komga && docker rm komga # nginx-ssl.conf: komga_backend upstream → 192.168.1.186:25600 docker restart home-service-proxy # 검증 curl https://komga.hyungi.net # → GPU 서버 경유 접근 ``` ## GPU-4단계: Surya OCR 설치 ```bash # GPU 서버에서 실행 (ssh 192.168.1.186) # 1. PyTorch CUDA 확인 python3 -c "import torch; print(torch.cuda.is_available())" # False면: pip install torch --index-url https://download.pytorch.org/whl/cu124 # 2. Surya OCR 설치 sudo mkdir -p /opt/surya-ocr && cd /opt/surya-ocr python3 -m venv venv source venv/bin/activate pip install surya-ocr fastapi uvicorn python-multipart # 3. server.py 작성 (FastAPI 래퍼, gpu-restructure.md Phase 2-2 참조) # 4. systemd 등록 # /etc/systemd/system/surya-ocr.service (gpu-restructure.md Phase 2-3 참조) sudo systemctl daemon-reload sudo systemctl enable --now surya-ocr # 검증 curl -F "file=@test.pdf" http://localhost:8400/ocr ``` ## GPU-5단계: Qdrant 통합 + PKM 코드 갱신 ``` PKM 프로젝트 코드를 GPU 서버 재구성에 맞게 갱신해줘. 1. scripts/embed_to_chroma.py → scripts/embed_to_qdrant.py 리라이트 - chromadb → qdrant-client - nomic-embed-text → bge-m3 (GPU 서버 192.168.1.186:11434) - /api/embed 사용 (배치 지원) - 텍스트 청킹 (500토큰, 50오버랩) - 기존 embed_to_chroma.py는 git rm 2. applescript/auto_classify.scpt 수정 - Step 0: OCR 감지 + Surya OCR 호출 추가 - Step 4: embed_to_qdrant.py 호출로 변경 - 버그 픽스: 73행 sourceChannel 이중 설정 삭제 - baseDir 변수 사용 (12단계와 합산) 3. requirements.txt 업데이트 (9단계와 합산) - chromadb, schedule 제거 + qdrant-client, flask, gunicorn 추가 4. credentials.env.example: GPU_SERVER_IP 추가 5. Qdrant에 pkm_documents 컬렉션 생성 (1024차원, cosine) 검증: python3 scripts/embed_to_qdrant.py <테스트UUID> → Qdrant 벡터 저장 ``` ## GPU-6단계: architecture.md 대규모 갱신 ``` docs/architecture.md를 GPU 서버 재구성에 맞게 전체 갱신해줘. 변경 규모: ChromaDB 28건, nomic-embed 12건, VL-7B 5건 — 문맥별 수정 필요 주요 변경: - Tier 3 모델: nomic-embed-text → bge-m3, Qwen2.5-VL-7B → Surya OCR - 벡터 DB: ChromaDB → Qdrant (모든 언급) - VRAM 다이어그램: ~11.3GB → ~7-8GB - Smart Rule 설계: embed_to_chroma → embed_to_qdrant, OCR 단계 추가 - 3-Tier AI 라우팅 전략 표 갱신 - 코드 예시 내 경로/모델명 ※ 단순 치환 불가, 전체 문서를 통독하며 문맥에 맞게 수정할 것 ※ 별도 커밋으로 분리 ``` ## GPU-7단계: RAG 파이프라인 구축 (후순위) ``` pkm_api_server.py에 RAG 엔드포인트를 추가해줘. 추가 엔드포인트: POST /rag/query — 질문 → bge-m3 임베딩 → Qdrant 검색 → 리랭킹 → MLX 답변 POST /devonthink/embed — 단일 문서 임베딩 트리거 POST /devonthink/embed-batch — 배치 임베딩 docstring 갱신: "범위: DEVONthink + OmniFocus + RAG 검색" scripts/ocr_preprocess.py 신규 작성: DEVONthink UUID → AppleScript로 파일 경로 추출 → Surya API(GPU:8400) 호출 검증: curl -X POST localhost:9900/rag/query -d '{"q":"산업안전 법령"}' ``` --- # Phase 2: 인프라 수정 + 버그 픽스 (Phase 1.5와 병행) > dev-roadmap.md Phase 2~3 해당 > ※ requirements.txt, AppleScript 경로, credentials.env는 GPU-5단계와 합산 진행 ## 9단계: requirements.txt 수정 ← GPU-5단계와 합산 ``` requirements.txt에 flask가 빠져있어. pkm_api_server.py에서 사용 중이니까 추가해줘. GPU 서버 재구성에 따라 chromadb→qdrant-client 교체도 함께 진행. gunicorn도 추가해 (프로덕션 WSGI 서버용). schedule 패키지는 현재 미사용 — 제거할지 유지할지 판단해줘. anthropic 패키지는 향후 Tier 2 연동용이니 유지. 수정할 파일: requirements.txt 추가: + flask>=3.0.0 + gunicorn>=21.2.0 확인: - schedule>=1.2.0 → 사용처 없으면 제거 ``` ## 10단계: JP 번역 thinking 오염 수정 ``` 법령 모니터링에서 일본어 번역 시 MLX Qwen3.5의 thinking 출력이 결과에 섞이는 문제를 수정해줘. 현재 문제: 로그에서 "Wait, I'll check if..." 같은 thinking 텍스트가 번역 결과에 포함됨. 위치: scripts/law_monitor.py의 JP 번역 호출부 수정 방향: 1. 번역 프롬프트에 /nothink 모드 명시 강화 2. llm_generate() 응답에서 thinking 패턴 필터링 추가 - "Wait,", "Let me", "I'll check", "Hmm," 등으로 시작하는 줄 제거 - "Final Output:" 이후 텍스트만 추출하는 로직 3. 또는 pkm_utils.py의 llm_generate()에 strip_thinking=True 옵션 추가 테스트: JP RSS 항목 하나로 번역 테스트하여 깨끗한 한글 출력 확인 ``` ## 11단계: API 서버 버그 수정 ``` PKM API 서버의 두 가지 버그를 수정해줘. 위치: scripts/pkm_api_server.py 버그 1: /devonthink/stats → 500 Internal Server Error - AppleScript 쿼리가 실패하는 것으로 추정 - 에러 로그 확인: logs/pkm-api.error.log - AppleScript에서 DB 이름이나 property 접근 방식 수정 필요 버그 2: 한글 쿼리 파라미터 인코딩 에러 - /devonthink/search?q=산업안전 → 400 Bad request syntax - Flask의 request.args는 UTF-8을 지원하므로, 클라이언트 측 문제일 가능성 - 서버 측에서도 방어 코드 추가: URL 디코딩 처리 추가 개선: - /omnifocus/overdue 엔드포인트가 404였다가 나중에 추가됨 — 코드 확인 - / (루트) 접근 시 404 → /health로 리다이렉트 또는 엔드포인트 목록 반환 ``` ## 12단계: AppleScript 경로 변수화 ← GPU-5단계와 합산 ``` AppleScript 파일들의 하드코딩된 경로를 변수로 교체해줘. GPU-5단계의 embed_to_qdrant.py 변경, OCR 단계 추가, sourceChannel 버그 픽스도 함께 진행. 현재 하드코딩: ~/Documents/code/DEVONThink_my server/scripts/prompts/classify_document.txt ~/Documents/code/DEVONThink_my server/venv/bin/python3 ~/Documents/code/DEVONThink_my server/scripts/embed_to_chroma.py 수정 대상: applescript/auto_classify.scpt applescript/omnifocus_sync.scpt 수정 방향: - 스크립트 상단에 property baseDir 정의 - 모든 경로를 baseDir 기반으로 조합 - 또는 환경변수 PKM_HOME을 읽어서 사용 ※ AppleScript에서 환경변수 읽기: set pkmHome to do shell script "echo $PKM_HOME" 또는 property로 직접 지정하는 게 안정적 ``` --- # Phase 3: API 서버 개선 ## 13단계: gunicorn 전환 + launchd 등록 ``` PKM API 서버를 Flask development server에서 gunicorn으로 전환하고, launchd plist를 만들어 Mac mini 로그인 시 자동 시작되도록 해줘. 1. gunicorn 설정: gunicorn -w 2 -b 127.0.0.1:9900 pkm_api_server:app ※ AppleScript 실행 때문에 GUI 세션에서 실행해야 함 ※ launchd의 LimitLoadToSessionType = Aqua 또는 LoginwindowUI 2. launchd plist 생성: launchd/net.hyungi.pkm.api-server.plist - 로그인 시 자동 시작 - KeepAlive: true (크래시 시 재시작) - WorkingDirectory: ~/Documents/code/DEVONThink_my server/ - StandardOutPath/StandardErrorPath: logs/pkm-api.log, logs/pkm-api.error.log 3. deploy.md에 API 서버 관련 내용 추가 ``` ## 14단계: API 엔드포인트 추가 ``` PKM API 서버에 모니터링/상태 확인용 엔드포인트를 추가해줘. 추가할 엔드포인트: 1. GET /law-monitor/status - data/law_last_check.json 읽어서 마지막 확인 시간 반환 - logs/law_monitor.log 최근 에러 건수 2. GET /digest/latest - DEVONthink 00_Note_BOX/Daily_Digest/에서 최신 다이제스트 조회 - 또는 data/ 아래에 최근 다이제스트 캐시 3. GET / → 전체 엔드포인트 목록 반환 (현재 404) 4. GET /health 확장 - MLX 서버 상태 (localhost:8800 연결 가능 여부) - DEVONthink 실행 상태 - 각 launchd job 상태 ``` --- # Phase 4: 테스트 ## 15단계: 모듈별 테스트 실행 ``` Mac mini에서 각 모듈의 동작을 확인해줘. 1. AI 분류 테스트 (tests/test_classify.py) cd ~/Documents/code/DEVONThink_my\ server/ source venv/bin/activate python tests/test_classify.py → 5종 문서 분류 정확도 확인 2. 법령 모니터링 (Phase 2 인프라 수정 후) python scripts/law_monitor.py → 한국 법령 API 정상 응답 확인 → 외국 법령 수집 재확인 3. MailPlus 이메일 수집 (Phase 2 연결 수정 후) python scripts/mailplus_archive.py → IMAP 접속 + 이메일 가져오기 확인 4. Daily Digest python scripts/pkm_daily_digest.py → 다이제스트 MD 파일 생성 확인 5. API 서버 (Phase 2 버그 수정 후) python scripts/pkm_api_server.py & curl http://localhost:9900/health curl http://localhost:9900/devonthink/stats curl http://localhost:9900/devonthink/inbox-count curl "http://localhost:9900/devonthink/search?q=safety&limit=3" curl http://localhost:9900/omnifocus/stats ``` ## 16단계: E2E 통합 테스트 ``` PKM 시스템 End-to-End 테스트를 진행해줘. 시나리오 1: Inbox → 자동분류 플로우 1. DEVONthink Inbox에 테스트 문서 추가 2. Smart Rule 트리거 → auto_classify.scpt 실행 확인 3. 태그, 커스텀 메타데이터(sourceChannel, dataOrigin, lastAIProcess) 확인 4. 올바른 도메인 DB + 하위 그룹으로 이동 확인 시나리오 2: 법령 → 다이제스트 플로우 1. law_monitor.py 수동 실행 2. data/laws/에 파일 생성 + DEVONthink 04_Industrial Safety 임포트 확인 3. pkm_daily_digest.py 실행 → 법령 변경 건 포함 확인 시나리오 3: OmniFocus 연동 1. Projects DB에 TODO 패턴 문서 추가 2. omnifocus_sync.scpt 트리거 확인 3. OmniFocus Inbox에 작업 생성 + DEVONthink 링크 확인 4. 커스텀 메타데이터 omnifocusTaskID 확인 시나리오 4: launchd 스케줄 확인 launchctl list | grep pkm → 3개(+API 서버) 등록 확인 각 항목 pass/fail 리포트 → docs/test-report.md ``` --- # Phase 5: 운영 안정화 (나중에) ## 17단계: 로그 로테이션 + 알림 ``` 운영 안정성을 위한 설정을 추가해줘. 1. Python 로그 로테이션 - pkm_utils.py의 setup_logger()에 RotatingFileHandler 적용 - maxBytes=10MB, backupCount=5 2. Synology Chat 알림 (CHAT_WEBHOOK_URL 설정 후) - 법령 변경 감지 시 알림 - 에러 발생 시 알림 - Daily Digest 요약 알림 3. 에러 모니터링 - pkm_daily_digest.py에 이미 에러 카운트 로직 있음 - 임계값 초과 시 Chat 알림 추가 ``` ## 18단계: 문서 보완 ``` 프로젝트 문서를 보완해줘. 1. README.md — 아키텍처 다이어그램, 기능 목록, 시작 가이드 확장 2. deploy.md — API 서버 배포, 트러블슈팅 섹션, macOS 요구사항 추가 3. docs/troubleshooting.md — 자주 발생하는 문제와 해결 방법 ``` --- ## 참고: 네트워크 환경 ``` Mac mini 접속: SSH (MacBook Pro → Mac mini) NAS 도메인: ds1525.hyungi.net (Tailscale: 100.101.79.37, 포트: 15001) MailPlus: mailplus.hyungi.net:993 (IMAP SSL) ← 현재 연결 불가, 확인 필요 WebDAV: webdav.hyungi.net/Document_Server/DEVONThink/ TKSafety: tksafety.technicalkorea.net (나중에 활성화) 내부 네트워크: Tailscale VPN 연결됨 Gitea: https://git.hyungi.net/hyungi/devonthink_home.git ``` ## 참고: Git 커밋 히스토리 ``` 3506214 fix(law_monitor): US 타입 필터 제거 + JP RDF 네임스페이스 수정 c8e30b5 fix: AppleScript POSIX path 변수 방식 + 단일 -e 실행으로 따옴표 문제 해결 f13b998 fix: AppleScript 행별 -e 분할 실행 — 파일 방식 인코딩 문제 회피 735c072 fix: AppleScript를 임시 파일로 실행 — osascript -e 이스케이프 문제 해결 446963c fix(law_monitor): AppleScript f-string 제거 + EU 파일명 고유화 0b950a4 fix(law_monitor): AppleScript 따옴표 이스케이프 수정 6a44b10 fix(law_monitor): JP/EU RSS URL 수정 — news.rdf + rss.xml, RDF 네임스페이스 대응 9dc0694 feat(law_monitor): 외국 법령 지원 추가 — US OSHA, JP 厚労省(MLX 번역), EU-OSHA ec6074d fix(law_monitor): API 에러 응답 로깅 추가 — 인증 실패 시 조용히 넘어가던 문제 aca4a02 fix: LLM thinking 허용 + 마지막 유효 JSON 추출 방식으로 변경 49c39a1 fix: LLM thinking 출력 대응 — max_tokens 증가 + JSON 추출 강화 948be16 fix: Qwen3.5 /nothink 모드 + json_mode 파라미터 추가 a774771 fix: MLX 서버(localhost:8800) 대응 — Ollama API → OpenAI 호환 변경 084d3a8 feat: 전체 PKM 스크립트 일괄 작성 — 분류/법령/메일/다이제스트/임베딩 bec9579 chore: 프로젝트 구조 + 설계 문서 초기 커밋 ```