Files
hyungi_document_server/docs/claude-code-commands.md
hyungi 45cabc9aea refactor: GPU 서버 재구성 + ChromaDB→Qdrant 마이그레이션
- embed_to_chroma.py → embed_to_qdrant.py 리라이트 (bge-m3 + Qdrant REST API)
- auto_classify.scpt: embed_to_qdrant.py 경로 변경 + sourceChannel 덮어쓰기 버그 수정
- requirements.txt: chromadb/schedule 제거, qdrant-client/flask/gunicorn 추가
- credentials.env.example: GPU_SERVER_IP 항목 추가
- GPU 서버 재구성 계획서 (docs/gpu-restructure.md) + dev-roadmap/commands 통합
- CLAUDE.md, README.md, deploy.md 현행화

GPU 서버 변경사항 (이미 적용됨):
  - Ollama: qwen3.5:9b, id-9b 제거 → bge-m3 + bge-reranker-v2-m3
  - Surya OCR 서비스 (:8400, systemd)
  - Docker + NFS + Komga 이전 (:25600)
  - tk-ai-service: Ollama API → OpenAI API 전환 (MLX 35B)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 13:19:31 +09:00

531 lines
17 KiB
Markdown

# 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: 프로젝트 구조 + 설계 문서 초기 커밋
```