Files
hyungi_document_server/docs/dev-roadmap.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

13 KiB

PKM 시스템 개발 로드맵

작성일: 2026-03-29 (GPU 서버 재구성 계획 통합: 2026-03-29) 현재 상태: Phase 1 코드 작성 완료(90%), 인프라 일부 미해결 → Phase 1.5(GPU 재구성) + Phase 2 진행 중


현재 완료된 것

단계 항목 상태 비고
1 프로젝트 구조 완료 README, deploy.md, .gitignore
2 AI 분류 프롬프트 완료 MLX(Qwen3.5) OpenAI 호환 API 전환 완료
3 AppleScript 완료 auto_classify + omnifocus_sync
4 법령 모니터링 ⚠️ 부분 외국(US/JP/EU) OK, 한국 API 인증 실패
5 MailPlus 수집 연결 실패 IMAP Connection refused
6 Daily Digest ⚠️ 미테스트 코드 완성, 실행 기록 없음
7 DEVONagent 가이드 완료 docs/devonagent-setup.md
8 전체 테스트 미진행 test_classify.py만 존재
추가 PKM API 서버 ⚠️ 부분 한글 인코딩, stats 500 에러

Phase 1.5: GPU 서버 재구성 (Phase 2와 병행)

상세 계획: docs/gpu-restructure.md 참조

GPU 서버(RTX 4070Ti Super)의 역할을 LLM 추론에서 임베딩/OCR 특화로 전환한다. Mac Mini와 중복되는 LLM 모델을 제거하고, Surya OCR + bge-m3를 배치한다.

1.5-A. GPU 서버 정리 (SSH 작업)

작업 내용:
1. Ollama 모델 제거: qwen3.5:9b-q8_0, id-9b
2. 새 모델 설치: bge-m3 (임베딩), bge-reranker-v2-m3 (리랭킹)
3. no-think proxy(11435) 비활성화
4. paperless-gpt 처리 방침 결정
5. tk-ai-service 코드 수정 (Ollama API → OpenAI API 전환)

검증: ollama list → bge-m3, bge-reranker만 존재
검증: tk-ai-service /health → MLX(text), GPU(embed) 모두 connected

1.5-B. Docker + NFS + Komga 이전

작업 내용:
1. GPU 서버에 Docker Engine 설치
2. NAS NFS 마운트 설정 (192.168.1.227:/volume1/Comic → /mnt/comic, ro)
3. Komga Docker 컨테이너를 GPU 서버로 이전 (포트 25600 유지)
4. Mac Mini nginx upstream 변경 → GPU 서버
5. Mac Mini Komga 제거 (Docker VM 메모리 1.23GB 회수)

검증: curl https://komga.hyungi.net → GPU 서버 경유 접근 확인

1.5-C. Surya OCR 설치

작업 내용:
1. PyTorch CUDA 런타임 확인/설치
2. Surya OCR FastAPI 서버 구성 (/opt/surya-ocr/, 포트 8400)
3. systemd 서비스 등록

검증: curl -F "file=@test.pdf" http://192.168.1.186:8400/ocr → OCR 텍스트 반환

1.5-D. PKM 코드 갱신 (Phase 2와 겹치는 항목 포함)

작업 내용:
1. embed_to_chroma.py → embed_to_qdrant.py 리라이트 (Qdrant + bge-m3)
2. auto_classify.scpt: Step 0(OCR) 추가 + Step 4 Qdrant + sourceChannel 버그 픽스
3. requirements.txt: chromadb→qdrant-client, flask/gunicorn 추가 ← Phase 2 1-1과 합산
4. credentials.env: GPU_SERVER_IP=192.168.1.186 추가
5. architecture.md 대규모 갱신 (ChromaDB 28건, nomic 12건, VL-7B 5건)

검증: python3 scripts/embed_to_qdrant.py <테스트UUID> → Qdrant 벡터 저장 확인

1.5-E. RAG 파이프라인 + OCR 연동 (후순위)

작업 내용:
1. pkm_api_server.py에 RAG 엔드포인트 추가 (/rag/query, /devonthink/embed)
2. DEVONthink Smart Rule에 OCR 전처리 단계 추가
3. ocr_preprocess.py 신규 작성

검증: curl -X POST localhost:9900/rag/query -d '{"q":"산업안전 법령"}' → 답변 반환

Phase 2: 인프라 수정 (Phase 1.5와 병행)

Mac mini에서 직접 확인/수정이 필요한 항목들. ※ Phase 1.5(GPU 재구성)과 병행하여 진행. 겹치는 항목(requirements.txt, credentials.env, AppleScript)은 합산.

1-1. requirements.txt 수정 ← Phase 1.5-D와 합산 진행

현재 문제:
- flask 누락 (pkm_api_server.py에서 사용 중)
- schedule 패키지 미사용 (제거 고려)
- chromadb → qdrant-client 교체 (GPU 재구성에 따라)

수정 내용:
+ flask>=3.0.0
+ gunicorn>=21.2.0  (프로덕션 WSGI)
+ qdrant-client>=1.7.0
- chromadb>=0.4.0
- schedule>=1.2.0 (미사용 확인 후 제거)

1-2. 한국 법령 API 인증 해결

현재 에러:
"사용자 정보 검증에 실패하였습니다.
 OPEN API 호출 시 사용자 검증을 위하여 정확한 서버장비의 IP주소 및 도메인주소를 등록해 주세요."

조치:
1. open.law.go.kr 접속 → 마이페이지 → 인증키 관리
2. Mac mini의 외부 IP 확인: curl ifconfig.me
3. 해당 IP를 API 호출 서버 IP로 등록
4. Tailscale IP(100.x.x.x)가 아니라 실제 공인 IP여야 함
5. 등록 후 law_monitor.py 재실행하여 확인

1-3. MailPlus IMAP 연결 수정

현재 에러: [Errno 61] Connection refused (mailplus.hyungi.net:993)

확인 순서:
1. Synology DSM → MailPlus Server → 서비스 상태 확인
2. IMAP 활성화 여부: DSM → MailPlus Server → 메일 전송 → IMAP 탭
3. 포트 확인: 993(SSL) vs 143(STARTTLS)
4. 방화벽: Synology 방화벽에서 993 포트 개방 확인
5. DNS 확인: nslookup mailplus.hyungi.net → 올바른 IP?
6. Tailscale 경유 시: 100.101.79.37:993으로 직접 테스트
   python3 -c "import imaplib; m=imaplib.IMAP4_SSL('100.101.79.37', 993); print('OK')"
7. credentials.env에 MAILPLUS_HOST 값 확인

1-4. launchd 등록 상태 확인 및 등록

# Mac mini에서 확인
launchctl list | grep pkm

# 미등록 시 심볼릭 링크 생성
ln -sf ~/Documents/code/DEVONThink_my\ server/launchd/net.hyungi.pkm.law-monitor.plist ~/Library/LaunchAgents/
ln -sf ~/Documents/code/DEVONThink_my\ server/launchd/net.hyungi.pkm.mailplus.plist ~/Library/LaunchAgents/
ln -sf ~/Documents/code/DEVONThink_my\ server/launchd/net.hyungi.pkm.daily-digest.plist ~/Library/LaunchAgents/

# 로드
launchctl load ~/Library/LaunchAgents/net.hyungi.pkm.law-monitor.plist
launchctl load ~/Library/LaunchAgents/net.hyungi.pkm.mailplus.plist
launchctl load ~/Library/LaunchAgents/net.hyungi.pkm.daily-digest.plist

Phase 2: 버그 픽스 (코드 수정)

2-1. JP 번역 thinking 오염 문제

현재: MLX Qwen3.5가 번역 시 "Wait, I'll check if..." 같은 thinking을 출력에 포함
위치: scripts/law_monitor.py의 JP 번역 호출부

수정 방향:
- 번역 프롬프트에 /nothink 모드 명시 강화
- llm_generate() 호출 시 thinking 출력 후처리 추가
- "Wait,", "Let me", "I'll check" 등 패턴 필터링
- 또는 번역 결과에서 첫 번째 유효 문장만 추출

2-2. PKM API 서버 한글 인코딩

현재: /devonthink/search?q=산업안전 → 400 Bad request syntax
위치: scripts/pkm_api_server.py

수정:
- Flask 자체는 UTF-8 지원하므로, 클라이언트 측 URL 인코딩 문제일 가능성
- curl 호출 시 --data-urlencode 사용 또는 퍼센트 인코딩 필요
- 서버 측에서도 request.args.get('q', '') 기본 인코딩 확인

2-3. /devonthink/stats 500 에러 수정

현재: GET /devonthink/stats → 500 Internal Server Error
위치: scripts/pkm_api_server.py

원인 추정: AppleScript 실행 시 DB 이름이나 경로 문제
수정: 에러 로그 확인 후 AppleScript 쿼리 수정

2-4. AppleScript 하드코딩 경로 개선

현재:
- ~/Documents/code/DEVONThink_my server/scripts/prompts/ 하드코딩
- venv 경로 하드코딩

수정:
- 스크립트 상단에 BASE_DIR 변수 정의
- 또는 환경변수 PKM_HOME으로 통일

2-5. requirements.txt 정리

추가: flask>=3.0.0, gunicorn>=21.2.0
유지: anthropic (향후 Tier 2용)
검토: schedule (미사용이면 제거)

Phase 3: API 서버 개선

3-1. 프로덕션 서빙

현재: Flask development server
변경: gunicorn + launchd로 안정 운영

launchd plist 추가:
  net.hyungi.pkm.api-server.plist
  → gunicorn -w 2 -b 127.0.0.1:9900 pkm_api_server:app

3-2. 엔드포인트 보완

현재 엔드포인트:
  GET /health
  GET /devonthink/stats        ← 500 에러 수정 필요
  GET /devonthink/search
  GET /devonthink/inbox-count
  GET /omnifocus/stats
  GET /omnifocus/today
  GET /omnifocus/overdue

추가 고려:
  GET /law-monitor/status      ← 마지막 실행 결과, 다음 실행 시간
  GET /digest/latest           ← 최근 다이제스트 조회
  POST /classify               ← 수동 분류 요청 (테스트용)

3-3. 간단한 인증 추가 (선택)

localhost 전용이면 불필요하지만, Tailscale 내부에서 접근할 경우:
- Bearer token 방식 (credentials.env에 API_TOKEN 추가)
- 또는 IP 화이트리스트 (127.0.0.1 + Tailscale 대역)

Phase 4: 테스트 & 검증

4-1. 개별 모듈 테스트

# Mac mini에서 실행

# 1. AI 분류 테스트 (5종 문서)
cd ~/Documents/code/DEVONThink_my\ server/
source venv/bin/activate
python tests/test_classify.py

# 2. 법령 모니터링 (한국 API 인증 후)
python scripts/law_monitor.py

# 3. MailPlus (IMAP 수정 후)
python scripts/mailplus_archive.py

# 4. Daily Digest
python scripts/pkm_daily_digest.py

# 5. API 서버
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"

4-2. E2E 통합 테스트

시나리오 1: Inbox → 자동분류 플로우
  1. DEVONthink Inbox에 테스트 문서 추가
  2. Smart Rule 트리거 → auto_classify.scpt 실행 확인
  3. 태그, 메타데이터, DB 이동 확인

시나리오 2: 법령 → 다이제스트 플로우
  1. law_monitor.py 수동 실행
  2. data/laws/에 파일 생성 확인
  3. DEVONthink 04_Industrial Safety 확인
  4. pkm_daily_digest.py 실행 → 법령 변경 건 포함 확인

시나리오 3: OmniFocus 연동
  1. Projects DB에 TODO 패턴 문서 추가
  2. omnifocus_sync.scpt 트리거 확인
  3. OmniFocus Inbox에 작업 생성 확인

4-3. 테스트 리포트 작성

→ docs/test-report.md
각 항목별 pass/fail + 스크린샷/로그 첨부

Phase 5: 운영 안정화 (선택)

5-1. 모니터링

- 로그 로테이션 (logrotate 또는 Python RotatingFileHandler)
- Synology Chat 웹훅 알림 연동 (CHAT_WEBHOOK_URL 설정 후)
- 에러 발생 시 즉시 알림

5-2. 백업

- Gitea 리포지토리 자동 백업 (이미 NAS에 있으므로 OK)
- credentials.env 백업 (Vaultwarden에 보관?)
- Qdrant 데이터 백업 (pkm_documents + tk_qc_issues 컬렉션)

5-3. 문서 보완

- README.md 상세화 (아키텍처 다이어그램, 기능 목록)
- 트러블슈팅 가이드 추가
- deploy.md에 API 서버 + 업데이트 절차 추가

작업 순서 요약

[GPU] Phase 1.5: GPU 서버 재구성 (Phase 2와 병행)
  1.5-A. GPU 서버 정리 (모델 교체, proxy 제거)  ← SSH 작업
  1.5-B. Docker + NFS + Komga 이전             ← SSH 작업
  1.5-C. Surya OCR 설치                        ← SSH 작업
  1.5-D. PKM 코드 갱신 (Qdrant, 임베딩)        ← 코드 수정 후 push
  1.5-E. RAG + OCR 연동                        ← 후순위

[즉시] Phase 2: 인프라 수정
  1-1. requirements.txt 수정                   ← Phase 1.5-D와 합산
  1-2. 한국 법령 API IP 등록                    ← Mac mini에서 공인IP 확인
  1-3. MailPlus IMAP 확인                      ← Synology DSM 확인
  1-4. launchd 등록                            ← Mac mini에서 실행

[코드] Phase 3: 버그 픽스
  2-1. JP 번역 thinking 필터링                 ← 코드 수정 후 push
  2-2~3. API 서버 수정                         ← 코드 수정 후 push
  2-4. AppleScript 경로 변수화                 ← Phase 1.5-D와 합산
  2-5. requirements.txt 정리                   ← Phase 1.5-D와 합산

[개선] Phase 4: API 서버 개선
  3-1. gunicorn 전환 + launchd plist           ← 코드 작성 후 push
  3-2~3. 엔드포인트 추가                       ← 필요시

[검증] Phase 5: 테스트
  4-1~2. 모듈별 + E2E 테스트                   ← Mac mini에서 실행
  4-3. 테스트 리포트                           ← 결과 기반 작성

[안정] Phase 6: 운영 안정화                     ← 여유 있을 때

예상 소요 시간

Phase 예상 시간 비고
Phase 1.5-A~C 3~4시간 GPU 서버 SSH 작업 (모델 교체, Docker, Surya)
Phase 1.5-D 3~4시간 PKM 코드 갱신 (Qdrant, architecture.md 대규모 수정)
Phase 1.5-E 2~3시간 RAG + OCR 연동 (후순위)
Phase 2 1~2시간 인프라 설정 확인 작업
Phase 3 2~3시간 버그 픽스 코드 수정
Phase 4 1~2시간 gunicorn 전환 중심
Phase 5 2~3시간 Mac mini에서 테스트 실행
Phase 6 필요시 운영하면서 점진적
합계 ~18시간 4~5일 분량