# hyungi_Document_Server — Claude Code 작업 가이드 ## 프로젝트 개요 Self-hosted PKM(Personal Knowledge Management) 웹 애플리케이션. FastAPI + PostgreSQL(pgvector) + SvelteKit + Docker Compose 기반. GPU 서버를 메인 서버, Mac mini를 AI 추론, Synology NAS를 파일 저장소로 사용. ## 핵심 문서 1. `docs/architecture.md` — 전체 시스템 아키텍처 (DB 스키마, AI 전략, 인프라, UI 설계) 2. `docs/deploy.md` — Docker Compose 배포 가이드 3. `docs/development-stages.md` — Phase 0~5 개발 단계별 가이드 ## 기술 스택 | 영역 | 기술 | |------|------| | 백엔드 | FastAPI (Python 3.11+) | | 데이터베이스 | PostgreSQL 16 + pgvector + pg_trgm | | 프론트엔드 | SvelteKit 5 (runes mode) + Tailwind CSS 4 | | 문서 파싱 | kordoc (HWP/HWPX/PDF → Markdown) + LibreOffice (오피스 → 텍스트/PDF) | | 리버스 프록시 | Caddy (HTTP only, 앞단 프록시에서 HTTPS 처리) | | 인증 | JWT + TOTP 2FA | | 컨테이너 | Docker Compose | ## 네트워크 환경 ``` GPU 서버 (RTX 4070 Ti Super, Ubuntu, 메인 서버): - Docker Compose: FastAPI(:8000), PostgreSQL(:5432), kordoc(:3100), Caddy(:8080 HTTP only), Ollama(127.0.0.1:11434), AI Gateway(127.0.0.1:8081), frontend(:3000) - NFS 마운트: /mnt/nas/Document_Server → NAS /volume4/Document_Server - 외부 접근: document.hyungi.net (Mac mini nginx → Caddy) - 로컬 IP: 192.168.1.186 Mac mini M4 Pro (AI 서버 + 앞단 프록시): - MLX Server: http://100.76.254.116:8800/v1/chat/completions (Qwen3.5-35B-A3B) - nginx: HTTPS 종료 → GPU 서버 Caddy(:8080)로 프록시 - Tailscale IP: 100.76.254.116 Synology NAS (DS1525+): - LAN IP: 192.168.1.227 - Tailscale IP: 100.101.79.37 - 파일 원본: /volume4/Document_Server/PKM/ - NFS export → GPU 서버 - Synology Drive: https://link.hyungi.net (문서 편집) - Synology Calendar: CalDAV 태스크 관리 - MailPlus: IMAP(993) + SMTP(465) ``` ## 인증 정보 - 위치: `credentials.env` (프로젝트 루트, .gitignore에 포함) - 템플릿: `credentials.env.example` - 스크립트에서 python-dotenv 또는 Docker env_file로 로딩 ## AI 모델 구성 ``` Primary (Mac mini MLX, Tailscale 경유, 상시, 무료): mlx-community/Qwen3.5-35B-A3B-4bit — 분류, 태그, 요약 → http://100.76.254.116:8800/v1/chat/completions Fallback (GPU Ollama, 같은 Docker 네트워크, MLX 장애 시): qwen3.5:35b-a3b → http://ollama:11434/v1/chat/completions Premium (Claude API, 종량제, 수동 트리거만): claude-sonnet — 복잡한 분석, 장문 처리 → 일일 한도 $5, require_explicit_trigger: true Embedding (GPU Ollama, 같은 Docker 네트워크): nomic-embed-text → 벡터 임베딩 Qwen2.5-VL-7B → 이미지/도면 OCR bge-reranker-v2-m3 → RAG 리랭킹 ``` ## 프로젝트 구조 ``` hyungi_Document_Server/ ├── docker-compose.yml ├── Caddyfile ← HTTP only, auto_https off ├── config.yaml ← AI 엔드포인트, NAS 경로, 스케줄 ├── credentials.env.example ├── app/ ← FastAPI 백엔드 │ ├── main.py ← 엔트리포인트 + APScheduler (watcher/consumer 포함) │ ├── Dockerfile ← LibreOffice headless 포함 │ ├── core/ (config, database, auth, utils) │ ├── models/ (document, task, queue) │ ├── api/ (documents, search, dashboard, auth, setup) │ ├── workers/ (file_watcher, extract, classify, embed, preview, law_monitor, mailplus, digest, queue_consumer) │ ├── prompts/classify.txt │ └── ai/client.py ← AIClient + parse_json_response (Qwen3.5 thinking 처리) ├── services/kordoc/ ← Node.js 마이크로서비스 (HWP/PDF 파싱) ├── gpu-server/ ← AI Gateway (deprecated, 통합됨) ├── frontend/ ← SvelteKit 5 │ └── src/ │ ├── routes/ ← 페이지 (documents, inbox, settings, login) │ └── lib/ │ ├── components/ ← Sidebar, DocumentCard, DocumentViewer, PreviewPanel, │ │ TagPill, FormatIcon, UploadDropzone │ ├── stores/ ← auth, ui │ └── api.ts ← fetch wrapper (JWT 토큰 관리) ├── migrations/ ← PostgreSQL 스키마 (schema_migrations로 추적) ├── scripts/ ├── docs/ └── tests/ ``` ## 문서 처리 파이프라인 ``` 파일 업로드 (드래그 앤 드롭 or file_watcher) ↓ extract (텍스트 추출) - kordoc: HWP, HWPX, PDF → Markdown - LibreOffice: xlsx, docx, pptx, odt 등 → txt/csv - 직접 읽기: md, txt, csv, json, xml, html ↓ ↓ classify (AI 분류) preview (PDF 미리보기 생성) - Qwen3.5 → domain - LibreOffice → PDF 변환 - tags, summary - 캐시: PKM/.preview/{id}.pdf ↓ embed (벡터 임베딩) - nomic-embed-text (768차원) ``` **핵심 원칙:** - 파일은 업로드 위치에 그대로 유지 (물리적 이동 없음) - 분류(domain/sub_group/tags)는 DB 메타데이터로만 관리 - preview는 classify와 병렬로 실행 (AI 결과 불필요) ## UI 구조 ``` ┌──────────────────────────────────────────────────┐ │ [☰ 사이드바] [PKM / 문서] [ℹ 정보] 버튼│ ← 상단 nav ├──────────────────────────────────────────────────┤ │ [검색바] [모드] [ℹ] │ │ 문서 목록 (30%) — 드래그 업로드 지원 │ ← 상단 영역 │ █ 문서카드 (domain 색상 바 + 포맷 아이콘) │ ├──────────────────────────────────────────────────┤ │ 하단 뷰어/편집 (70%) — 전체 너비 │ ← 하단 영역 │ Markdown: split editor (textarea + preview) │ │ PDF: 브라우저 내장 뷰어 │ │ 오피스: PDF 변환 미리보기 + [편집] 새 탭 버튼 │ │ 이미지: img 태그 │ └──────────────────────────────────────────────────┘ 사이드바: 평소 접힘, ☰로 오버레이 (domain 트리 + 스마트 그룹 + Inbox) 정보 패널: ℹ 버튼 → 우측 전체 높이 drawer (메모/태그 편집/메타/처리상태/편집 URL) ``` ## 데이터 계층 1. **원본 파일** (NAS `/volume4/Document_Server/PKM/`) — 유일한 원본, 위치 변경 없음 2. **가공 데이터** (PostgreSQL) — 텍스트 추출, AI 분류, 검색 인덱스, 메모, 태그 3. **파생물** — 벡터 임베딩 (pgvector), PDF 미리보기 캐시 (`.preview/`) ## 코딩 규칙 - Python 3.11+, asyncio, type hints - SQLAlchemy 2.0+ async 세션 - Svelte 5 runes mode ($state, $derived, $effect — $: 사용 금지) - 인증 정보는 credentials.env에서 로딩 (하드코딩 금지) - 로그는 `logs/`에 저장 (Docker 볼륨) - AI 호출은 반드시 `app/ai/client.py`의 `AIClient`를 통해 (직접 HTTP 호출 금지) - 한글 주석 사용 - Migration: `migrations/*.sql`에 작성, `init_db()`가 자동 실행 (schema_migrations 추적) - SQL에 BEGIN/COMMIT 금지 (외부 트랜잭션 깨짐) - 기존 DB에서는 schema_migrations에 수동 이력 등록 필요할 수 있음 ## 개발/배포 워크플로우 ``` MacBook Pro (개발) → Gitea push → GPU 서버에서 pull 개발: cd ~/Documents/code/hyungi_Document_Server/ # 코드 작성 → git commit & push GPU 서버 배포 (메인): ssh hyungi@100.111.160.84 cd ~/Documents/code/hyungi_Document_Server/ git pull docker compose up -d --build fastapi frontend ``` ## v1 코드 참조 v1(DEVONthink 기반) 코드는 `v1-final` 태그로 보존: ```bash git show v1-final:scripts/law_monitor.py git show v1-final:scripts/pkm_utils.py ``` ## 주의사항 - credentials.env는 git에 올리지 않음 (.gitignore) - NAS NFS 마운트 경로: Docker 컨테이너 내 `/documents` - FastAPI 시작 시 `/documents/PKM` 존재 확인 (NFS 미마운트 방지) - 법령 API (LAW_OC)는 승인 대기 중 - Ollama/AI Gateway 포트는 127.0.0.1 바인딩 (외부 접근 차단) - Caddy는 `auto_https off` + `http://` only (HTTPS는 Mac mini nginx에서 처리) - Synology Office 편집은 새 탭 열기 방식 (iframe 미사용, edit_url 수동 등록)