Files
Hyungi Ahn 31d76edba0 feat(dashboard): §4 — 카테고리/제안/queue lag 카드 + docs/categories.md
frontend +page.svelte:
- 4-card 메인 row 아래 새 row 추가: 자료실/오디오/비디오 (category_counts) +
  자료실 제안 (library_pending_suggestions). 제안 ≥1 일 때 warning 색 + /library 링크.
- buildPipelineRows 가 pipeline_status (24h 누적) + queue_lag (현재 시점) 머지.
  queue_lag.oldest_pending_age_sec 가 600초 초과면 stage 라벨 옆에 경과시간 표시.
- STAGE_ORDER/LABEL 에 stt/thumbnail 추가 (§3 신규 stage 자동 커버).

docs/categories.md (신규):
- 6 활성 + 3 유보 카테고리 정의 + 저장 경로 + 처리 파이프
- 역할 분리 원칙 (category / user_tags @library/ / facet_doctype / ai_suggestion)
- 업로드 경로 매트릭스 (web/NAS/collector/UI)
- video 채널별 정책 표 (web 거부 vs NAS quarantine)
- 업로드 한도 + error_code 7종 표
- orphan 임시파일 cleanup 정책

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 07:09:37 +09:00

4.9 KiB

카테고리 체계

Document Server 의 1차 진입점. 6 활성 + 3 유보. 자세한 결정 배경은 ~/.claude/plans/luminous-sprouting-hamster.md (v2.1) 참조.

6 활성 + 3 유보

카테고리 상태 저장 경로 (/volume4/Document_Server/PKM/) 처리 파이프
document 활성 Inbox/... extract → classify → embed (+ preview/OCR)
library 활성 — 사용자 승인 후 전이 동상 + @library/... 태그 동상
news 활성 DB 만 news_collector → classify
memo 활성 DB 만 메모 UI → embed
audio 활성 (§3) Recordings/ stt → classify → embed (extract 건너뜀)
video 활성 (§3, 최소판) Videos/ thumbnail 만 (classify/embed 안 함)
mail 유보 (별도 plan)
calendar 유보 (별도 plan)
plex 유보 (별도 plan)

역할 분리 원칙 (4 축)

역할 주인 누가 변경
documents.category enum 1차 진입점 — UI 탭/라우트/Sidebar 분기 document/library/news/memo/audio/video (+ 유보) 백필(§1) + 사용자 승인(§2) + file_watcher(§3)
user_tags@library/... 자료실 내부 서가 경로 (카테고리가 library 일 때 위치) 사용자 승인 태그 사용자 승인 + PATCH /documents/{id}
facet_doctype AI 가 식별한 문서 유형 (분류 신호, 필터/검색 key) 분류 파이프라인 산출물 classify_worker
ai_suggestion (JSONB) AI 가 제안했지만 미승인 된 변경 후보 (category/path/doctype) 승인 UI 소비 classify_worker 작성 / /accept-suggestion clear

4 축을 섞지 않는다. 예:

  • AI 가 발주서라고 판단 → facet_doctype='발주서' 설정 (분류 신호 완료). category건드리지 않음.
  • 동시에 ai_suggestion = {proposed_category:'library', proposed_path, confidence, source_updated_at} 저장.
  • 사용자가 /library 승인 UI 에서 1-click 승인 → 그제서야 category='library' + user_tags += @library/..., ai_suggestion clear.
  • 승인 전까지 문서는 category='document'문서함 에 남음.

자동 library 승격은 v2.1 에서 하지 않는다. 메트릭(precision > 0.9 AND reject_rate < 0.1 AND 월 제안 수 > 20 1개월 유지) 충족 시 별도 plan 으로 검토. → ~/.claude/projects/-Users-hyungiahn/memory/project_document_server_future_integrations.md

업로드 경로

채널 document library audio video news memo
웹 업로드 (UploadDropzone) indirect (§4 의존) direct play 만 (mp4/webm)
NAS 드롭 (file_watcher) (자동 전이 금지) + quarantine
외부 collector news_collector
내부 UI /memos

Video 채널별 정책 (§3 핵심 결정)

mp4 (H.264 AAC), webm (VP9) 만 브라우저 direct play 가능. 그 외 (mov/mkv/avi) 는 채널마다 다르게 처리:

채널 .mp4 .webm .mov .mkv .avi
웹 업로드 수락 → category='video', 썸네일 생성 거부 (400 + error_code='unsupported_codec'). UploadDropzone 가 배너 안내.
NAS 드롭 (file_watcher) 수락 → category='video', 썸네일 생성 quarantine import — DB 에 category='video' + needs_conversion=true, VideoPlayer 가 "재생 불가 — 변환 필요" 카드. 파일 삭제 안 함.

업로드 한도 + error_code 체계 (§4)

업로드 한도는 settings.upload.max_bytes 가 단일 진실 공급원 (현재 100MB). 프록시 (home-caddy) 는 max_bytes * content_length_slack_ratio (기본 1.05) 이상 유지.

서버 응답 detail{error_code, message} 객체:

error_code HTTP 의미
body_too_large 413 Content-Length 또는 누적이 max_bytes 초과
upload_timeout 408 서버 read timeout
network_abort 499 클라이언트 abort / 연결 끊김
empty_file 400 0 바이트
invalid_input 400 파일명/경로/필드 검증 실패
unsupported_codec 400 웹 업로드 direct play 불가 비디오 (.mov/.mkv/.avi)
internal 500 그 외 알 수 없는 에러

Orphan 임시파일 정리

업로드 중에는 <name>.uploading 임시명으로 NAS Inbox 에 쓰고 완료 시 atomic rename. 정상 abort 는 endpoint 가 즉시 정리하지만 프로세스 크래시 / 강제 종료 잔존물은 cleanup_orphan_uploads APScheduler job (10분 주기) 이 수거. 최근 3회 누적 삭제 ≥ cleanup_warn_threshold (기본 10) 이면 WARNING 로그 — abort 가 구조적으로 많거나 대용량 업로드 실패 반복 신호.

file_watcherSKIP_EXTENSIONS.uploading 포함 — 진행 중 파일을 잘못 픽업하지 않음.