Commit Graph

31 Commits

Author SHA1 Message Date
hyungi 7d06816bac fix(ops): DS compose 잉여 ollama 서비스 제거 — 매주 재부팅 outage 근본 해소
DS compose 의 ollama 서비스가 standalone ~/ollama 컨테이너와 host 127.0.0.1:11434 를
다퉈, 정기 재부팅 후 `docker compose up` 이 'port already allocated' 로 abort →
caddy·frontend 미기동 = 웹 outage(2026-06-08 internal error). standalone 이 이미
hyungi_document_server_default 망 + 동일 ollama_data 볼륨(external) 부착으로 fastapi
`ollama:11434` 임베딩을 서빙하므로 DS 서비스는 100% 잉여 → 제거(서비스+ai-gateway
depends_on). ollama_data 볼륨 def 는 standalone external 참조용으로 보존. 임베딩 무영향.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 07:15:24 +09:00
hyungi b734fc54af fix(search): Phase 2Q rerank payload — chunk_id dedup + cap 60 + TEI batch 64 (Apply prereq)
plan pr-2q-rerank-payload-fix-resolute-haven.md. Phase 2Q multi-query path 의 reranker
413 Payload Too Large root cause = TEI 의 MAX_CLIENT_BATCH_SIZE=32 default (batch entries
한도) + multi-query 의 chunks 누적이 32 초과. MAX_BATCH_TOKENS 와 별개 (token sum 한도).

4 iteration 진단 history (json 박제):
  1) cap 60 + dedup = 413 다수 (batch 54 > 32)
  2) cap 30 + chunks_per_doc=1 = 413 0건 + NDCG 0.666 catastrophic (-0.261)
  3) cap 60 + dedup + TEI 16384 only = 413 46건 (batch size 한도 별개)
  4) cap 60 + dedup + TEI 16384/64 = 413 1건 + NDCG 0.876 (FINAL)

변경:
- app/services/search/search_pipeline.py:
  · _dedup_chunks_by_id() 신규 helper — chunk_id (None 시 doc.id) 기준 first-only.
    variant 별 same chunk 중복 누적 회피, 첫 등장 variant 보존.
  · PHASE2Q_RERANK_INPUT_CAP=60 + PHASE2Q_CHUNKS_PER_DOC=2 신규 상수 (baseline
    MAX_RERANK_INPUT=200 / MAX_CHUNKS_PER_DOC=2 와 별도).
  · search_with_rewrite() merge 후 dedup wire-up + rerank input cap swap.
- docker-compose.yml reranker env (사용자 결정, plan out-of-scope 정정):
  · MAX_BATCH_TOKENS 8192 → 16384 (token sum 한도)
  · MAX_CLIENT_BATCH_SIZE 32 → 64 신규 추가 (batch entries 한도 — root cause)
  · GPU VRAM free 6199MiB 충분 사전 verify.
- tests/test_query_rewriter.py: _dedup_chunks_by_id 5 test + PHASE2Q_* constants test.
  38/38 PASS (기존 32 + 신규 6).

측정 결과 (51 case, gemma backend, snapshot 25180/56526):
  vs Phase 3 (commit a41adb6 NDCG 0.927, 413 다수):
  · NDCG 0.876 (-0.051 acceptable, plan 변수 격리 invariant 충족)
  · Recall t≥2 0.721 (+0.034 회복)
  · Recall t≥3 0.739 (+0.011)
  · latency p50 1421ms (-1336ms, -48%) / p95 3392ms (-6292ms, -65%) major win
  · 413 fallback 1/51 (98%↓ from 다수) + reranker batch error 0
  · 카테고리 english_only +0.34 / standards -0.28 / exam -0.19 (Apply 후 분석 항목)

closure gate PASS:
  · unit test 38/38, production smoke 413 0
  · 51 case 413 < 5/51 (1건만)
  · latency 대폭 개선
  · NDCG threshold 0.92 미달 단 plan invariant (production 평가 단일 변수) 충족
  · Apply PR-2Q-Apply-Query-Rewrite-1 진입 ready

산출물:
  · reports/v0_2_phase2q_rerank_fix_2026-05-24.csv (raw)
  · tests/search_eval/baselines/v0_2_phase2q_rerank_fix_2026-05-24.json (4 iter 진단 박제)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 03:54:59 +00:00
hyungi bcf644f893 refactor(search): /api/search/ask dispatcher route via llm-router
PR-2 of DS AI routing policy (2026-05-23, see plan
~/.claude/plans/document-server-ai-cheeky-reddy.md +
memory project_document_server_ai_routing_policy).

DS 의 모든 backend 호출이 llm-router :8890 단일 경유. 정칙 정합:
- 신규 RouterBackend (services/llm/backends.py) — alias 별 router POST
  + requires_gate 분기 (mac-mini-default 만 llm_gate FOREGROUND 보호).
- 기존 GemmaMacMiniBackend + QwenMacBookBackend = legacy 보존
  (DS_BACKENDS_VIA_ROUTER=false rollback safety only). 1주 후 별
  cleanup PR (PR-DS-Backends-Legacy-Cleanup-1) 로 폐기.
- get_backend factory dual-path (env flag) — backward-compat
  (gemma-macmini alias → mac-mini-default 매핑).
- search.py:457 Query pattern 확장: mac-mini-default|claude-cloud|auto
  추가. /ask/react 의 isinstance(QwenMacBookBackend) → hasattr
  duck-typing (RouterBackend + Legacy 모두 generate_with_tools 구현).
- SearchAskBackendConfig 에 router_url 신규 (env LLM_ROUTER_URL 또는
  hardcoded MVP default http://100.76.254.116:8890).
- docker-compose.yml fastapi env 에 LLM_ROUTER_URL +
  DS_BACKENDS_VIA_ROUTER 추가.

AIClient (_call_chat, call_triage, call_primary, call_fallback) 경유
path 는 별 PR (PR-AIClient-Router-Migration-1) — MVP scope C 채택,
회귀 risk 최소화.

Closure (즉시 fixture/matrix):
- factory smoke 6 alias (None/mac-mini-default/gemma-macmini/
  qwen-macbook/claude-cloud/auto) + 1 invalid (nonsense → ValueError).
- live 3 case: mac-mini-default 200 \"pong! 🏓\" + qwen-macbook cold
  502 upstream_502_primary=ConnectError + claude-cloud 503
  provider_not_configured.
- silent fallback 0 + direct M5/Mac mini socket 0
  (RouterBackend 만 router 호출).

Backup: ~/.local/share/ds-routing-pr2-backups/20260523/
(backends.py + config.py + search.py + docker-compose.yml).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 03:41:29 +00:00
Hyungi Ahn 95bea0a88b ops(worker-pool): docker-compose 에 LAPTOP_WORKER_BOT env 3개 wire-through
1B/1C 단계에서 host .env 변수가 fastapi 컨테이너에 주입되지 않은 누락.
voice-memo 동일 패턴으로 environment 블록에 명시 + default false.

PR-Notebook-Client-1 에서 username swap (laptop-worker-bot → notebook-client-bot)
시 env override 로 적용 가능.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 08:12:12 +09:00
hyungi 5125f82d4a feat(study): Mac mini derived-worker (PR-MacMini-Derived-Worker-1)
GPU = RAG context provider, Mac mini = LLM 가공 공장.

GPU 측 변경:
- app/api/internal_study.py: GET /internal/study/explanation-context/{qid}
  Bearer auth, gather_explanation_context + _render_envelope_prompt 재호출.
  204=evidence missing, 410=deleted/ready.
- app/workers/study_queue_consumer.py: settings.study_explanation_enabled
  false 시 explanation 분기 skip (status/attempts 미변경, pending 유지 → Mac mini 흡수).
- app/core/config.py: study_explanation_enabled + internal_worker_token 2 setting.
- app/main.py: internal_study_router include (prefix /internal/study).
- docker-compose.yml: fastapi ports → 100.110.63.63:8000 Tailscale bind,
  STUDY_EXPLANATION_ENABLED + INTERNAL_WORKER_TOKEN env 추가.

Mac mini 측: ~/derived-worker/ (별도 push 0, 어제 작성).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 03:13:43 +00:00
Hyungi Ahn 98ee7dffe2 ops(gpu-health): GPU 서비스 health/smoke 표준화 + synthetic VRAM 피크 가드
PR-GPU-Health-1. 운영 준비성 표준화 PR (모델 성능 개선 아님).

- OCR /smoke endpoint 추가 (160x60 OK PNG in-memory, 200/503 분기, Docker healthcheck 미사용)
- marker /health endpoint 추가 (stt/ocr 동일 시그니처)
- reranker docker-compose healthcheck 추가 (TEI :80/health)
- scripts/gpu_service_smoke.sh: docker exec 표준 점검 (OCR/STT expose-only)
- scripts/gpu_vram_fixture.sh: Mode A sequential + Mode B light overlap + --stress 옵션
- tests/load/fixtures/: synthetic ocr_ok.png / sine_30s.wav / lorem_1p.pdf

OCR 빈 응답 false negative — root cause: ports 미매핑.
결정: ocr-service / stt-service 는 expose-only 유지, 운영 점검은 docker exec 내부 curl 표준.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 09:42:07 +09:00
Hyungi Ahn 52f86acda7 feat(auth): voice-memo bot 365d access token (PoC v1)
bot 계정(`voice-memo-bot`) 한정 long-expiry access token 발급 경로 추가.
일반 사용자 흐름 영향 0 (env gate default false).

- core/auth.py: create_voice_memo_bot_token() 신규 (env gate + username hard-match)
- api/auth.py: login route 에 bot 분기 (bot 이면 long token 반환, 일반은 기존 흐름)
- docker-compose.yml: 3 env (VOICE_MEMO_BOT_TOKEN_ENABLED/_USERNAME/_EXPIRE_DAYS) default false

OpenClaw `/voice-memo` plugin → DS `/memos/` Bearer proxy 의 auth 기반.
정식 service-account/api_keys 테이블은 Phase 2 (multi-service 인입 추가 시점).

plan: ~/.claude/plans/rosy-launching-otter.md
project: ~/.claude/projects/-Users-hyungiahn/memory/project_voice_memo_pipeline.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 12:24:18 +09:00
Hyungi Ahn aca2f0d62c feat(canonical): restore GPU STT owner and extend KGS watch paths
D9 Track B revised (2026-05-08):

1) STT owner GPU 정식 복귀:
   - docker-compose.yml: stt-service profiles:[legacy] 제거 → 상시 활성
   - fastapi STT_ENDPOINT = http://stt-service:3300 (compose 내부 DNS)
   - 정책: Mac mini = Gemma 26B 전용 우선이므로 STT/Whisper 는 호출량 무관
     GPU 서버 소유. 이전 "Mac mini 이전본" 주석은 trace 오인 기반.

2) KGS Code 등 외부 학습 자료 추가 스캔 경로:
   - ADDITIONAL_WATCH_TARGETS env (쉼표 구분, PKM 상대경로)
   - app/core/config.py: additional_watch_targets list 설정 추가
   - app/workers/file_watcher.py: 추가 watch path 처리
   - app/workers/classify_worker.py: KGS Code 분류 분기 (가스기사 학습 자료)
   - 모두 expected_category=library 처리 (md/pdf/docx 만)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 05:47:20 +00:00
Hyungi Ahn e50869cbda feat(canonical): Phase 1B marker-service + marker_worker for PDF→markdown (222)
신규 컨테이너 marker-service (port 3300, Marker 1.10.2 + surya 0.17.1 + HF
cache volume). marker_worker 가 markdown stage 큐 소비:
  classify_worker → enqueue 'markdown' (leaf, embed/chunk 와 독립)
  → SKIP_DOC_TYPES (발주서/세금계산서/명세표) 스킵
  → 확장자 != .pdf 스킵 (Phase 1B = PDF only)
  → page_count > 200 스킵
  → marker-service POST /convert
  → 422/404 = doc-level failed, 5xx = queue retry

안정성 장치:
- migration 222: ALTER TYPE process_stage ADD VALUE markdown (단일 statement)
- md_extraction_quality JSONB dict 직접 저장
- skip 시 md_content/hash NULL 클리어
- /ready Response.status_code + warmup_error 가시화
- HF cache volume (build-time download 0)
- file_path 는 NAS 상대경로 → /documents prefix prepend

성공 기준: 파이프라인 안정성. markdown 품질은 Phase 1D pilot.

Pre-flight (2026-05-01):
- marker-pdf 1.10.2 stable
- file_path 9503건 NAS 상대경로
- DOCUMENT_TYPES 한국어 7종 → SKIP alias 보강
- queue retry max_attempts=3 + reset_stale_items 확인
- main 220/221 study_q_related 선점 → 222 rebump

Plan: ~/.claude/plans/plan-idempotent-sundae.md (Round 5 approved)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 00:06:23 +00:00
Hyungi Ahn 18d684b501 ops(infra): STT Mac mini 이전 + classifier 섹션 복원 (gemma4:e4b)
- docker-compose.yml stt-service 를 profiles:[legacy] 로 이동. GPU 의
  stt-service 는 더 이상 기동하지 않고, fastapi STT_ENDPOINT 가
  Mac mini (기본 100.76.254.116:8804 Tailscale, MAC_MINI_HOST env 로
  LAN IP 주입) 를 바라보도록 변경. 복원 필요 시
  `docker compose --profile legacy up -d stt-service`.
- config.yaml: classifier 섹션을 gemma4:e4b-it-q8_0 으로 복원. 이전
  B-0 커밋이 classifier 를 주석 처리했는데, 실제로는 classifier_service
  가 쓰고 있어 gate 유효. exaone 은 이미 제거됐으니 모델만 gemma4 로
  통일. classifier_service 의 hasattr 체크는 유지되어 fallback 안전.

D13 (STT 이전) drift 를 main 으로 승격. inventory 갱신은 B-3 마감
단계에서 3-tier + STT 경로 묶어서 일괄.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 10:08:00 +09:00
Hyungi Ahn 628d886cba fix(policy): mount domain_policy.yaml into fastapi + multi-path loader
배포 검증 중 발견: domain_policy.yaml 이 repo root 에 있지만 fastapi
컨테이너의 build context 는 ./app 이라 COPY 가 포함하지 못함. 결과
load_policy() 가 FileNotFoundError.

1. docker-compose.yml: config.yaml 과 동일 패턴으로 읽기전용 bind mount
   - ./domain_policy.yaml:/app/domain_policy.yaml:ro
2. app/policy/loader.py: _resolve_path 에 4 개 후보 검색 추가 —
   cwd / /app / /app/.. / <this>.parent.parent.parent 순으로 파일 존재
   확인. 첫 매칭 반환. 로컬/컨테이너/다른 배포 환경 모두 호환.

CI: pytest tests/policy/ -q → 98 passed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 09:45:10 +09:00
Hyungi Ahn a8e24ab114 fix(documents): accept-suggestion 항상 409 버그 + compose 127.0.0.1 바인딩
- accept-suggestion: documents.updated_at != expected stale 검사 제거.
  classify_worker 가 source_updated_at 을 pre-commit 값으로 저장하는데
  SQLAlchemy onupdate 가 commit 에서 updated_at 을 bump → 항상 불일치 →
  승인 영구 불가. payload 교체 검사 하나만으로 core race 는 막힘.
  사용자 직접 편집 감지는 별도 user_updated_at 컬럼 도입 시 재논의.
- docker-compose.yml: postgres/kordoc/fastapi/frontend 포트 127.0.0.1
  바인딩. GPU 서버 로컬에만 있던 drift 를 main 으로 승격. UFW-Docker
  우회 컨텍스트에서 불필요한 LAN 노출 축소.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 07:20:38 +09:00
Hyungi Ahn cec464ae2d fix(media): §3 ship-readiness — stt preload + healthcheck + queue enum + dashboard queue_lag
stt:
- services/stt/server.py: lazy → eager preload in FastAPI lifespan.
  STT_PRELOAD=0 으로 lazy 강제 가능 (개발/테스트). preload 실패해도
  프로세스는 살아 있고 /ready false 로 남아 healthcheck 가 unhealthy 처리.
- docker-compose.yml: healthcheck /health → /ready. /health 는 단순
  liveness 라 모델 미적재 상태도 healthy 로 잡혀 운영 신호 부적합.

queue ORM:
- app/models/queue.py: process_stage enum 에 'stt'/'thumbnail' 추가 +
  create_type=False (migration 150/151 가 DB enum 확장 담당). 이게
  없으면 stt_worker INSERT 시 SQLAlchemy 가 enum value 를 거부.

dashboard 강화 (§4 선제, §3 신규 stage 까지 자동 커버):
- app/api/dashboard.py: category_counts + library_pending_suggestions +
  queue_lag (stage 별 pending/processing/failed + oldest_pending_age_sec).
- frontend/src/lib/stores/system.ts: QueueLag 타입 + DashboardSummary 확장.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 07:04:52 +09:00
Hyungi Ahn 1e2c004dd4 feat(media): §3 audio STT + video 재생 인프라
plan: ~/.claude/plans/luminous-sprouting-hamster.md §3

스키마:
- migrations/147_audio_segments_table.sql: audio_segments (STT 타임스탬프
  세그먼트)
- migrations/148_audio_segments_idx.sql: (document_id, start_s) idx
- migrations/149_document_media_cols.sql: documents.thumbnail_path +
  needs_conversion
- migrations/150_queue_stage_stt.sql: process_stage += 'stt'
- migrations/151_queue_stage_thumbnail.sql: process_stage += 'thumbnail'
- app/models/audio_segment.py, document.py (thumbnail_path/needs_conversion)

서비스:
- services/stt/{Dockerfile, requirements.txt, server.py} — faster-whisper
  large-v3 GPU 컨테이너. /transcribe (filePath/langs/beamSize) +
  /health + /ready (cuda device_count + model_loaded). NFC/NFD 경로
  resolver (OCR 교훈).
- docker-compose.yml: stt-service 추가 (GPU 1 예약, :3300, NAS ro mount,
  stt_models volume, start_period 300s), fastapi env 에 STT_ENDPOINT.

파이프라인 (의존 §1 category):
- app/workers/stt_worker.py 신규: stage='stt' pickup → STT_ENDPOINT 호출 →
  extracted_text + audio_segments 저장. Timeout 30분.
- app/workers/thumbnail_worker.py 신규: ffmpeg 50% 지점 1장 →
  PKM/Videos/.thumbs/{id}.jpg + thumbnail_path 세팅.
  needs_conversion=true 는 skip.
- app/workers/file_watcher.py 확장: PKM/{Inbox, Recordings, Videos}
  스캔. 확장자→category, audio→stage=stt, video .mp4/.webm→
  stage=thumbnail, video .mov/.mkv/.avi→needs_conversion=true + stage
  없음. settings.roon_library_path prefix skip.
- app/workers/queue_consumer.py 확장: stt + thumbnail workers 등록,
  BATCH_SIZE(stt=1, thumbnail=3), next_stages 에 stt→[classify] 추가
  (audio 는 extract 건너뜀).
- app/Dockerfile: ffmpeg 추가 (썸네일 subprocess 용).

API (의존 §1):
- /api/audio/{id}/segments — AudioSegment ORDER BY start_s
- /api/video/{id}/thumbnail — thumbnail_path FileResponse (쿼리 토큰)
- /api/documents/{id}/file: media_types 에 audio/video mime 포함 (§2
  커밋에 이미 포함). Starlette FileResponse 가 Range 자동.
- upload_document: .mov/.mkv/.avi 웹 업로드 거부 (error_code
  unsupported_codec). NAS 드롭은 file_watcher 가 quarantine 수용.

프론트:
- AudioPlayer.svelte: HTML5 audio + 전사 세그먼트 sticky 패널 + 줄
  클릭 seek. activeIdx 하이라이트.
- VideoPlayer.svelte: HTML5 video direct play + needs_conversion 안내
  카드. poster 는 thumbnail endpoint.
- /audio (목록 grid) + /audio/[id] (플레이어)
- /video (썸네일 grid + 변환 필요 배지) + /video/[id] (플레이어)
- Sidebar.svelte: Mic/Film 아이콘 + audio/video 네비 활성, count
  배지 (§2 /stats/category-counts 재사용).

설정:
- app/core/config.py: stt_endpoint + roon_library_path.

DoD 배포 후 smoke: /ready cuda:true, 회의 mp3 transcribe, audio
extract 없이 classify 진행(queue 회귀), /audio 재생, .mp4 재생,
.mov 웹 400, .mov NAS quarantine, Sidebar 네비 + count.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 06:47:36 +09:00
Hyungi Ahn 7883ac67b3 feat(ocr): Surya OCR 마이크로서비스 추가
GPU 가속 OCR (Surya, Apache 2.0) 별도 컨테이너로 추가.
스캔 PDF/이미지 파일의 텍스트 추출 지원.

- services/ocr: Dockerfile + server.py + requirements.txt
- /health (liveness) + /ready (readiness, CUDA+모델 상태)
- /ocr: 페이지 단위 스트리밍 처리 (메모리 피크 억제)
- docker-compose: ocr-service + GPU reservation + ocr_models 볼륨

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 15:03:55 +09:00
Hyungi Ahn 32c79740f8 fix(kordoc): 파일 크기 제한 삭제, Docker 메모리 상한 4GiB 적용
25MB 파일 크기 제한은 텍스트 PDF(18MB 성공)까지 차단하는 문제.
실제 원인은 이미지 스캔 PDF의 in-memory 파싱 시 메모리 폭발.

- extract_worker: 25MB 파일 크기 제한 삭제
- docker-compose: kordoc-service mem_limit 4g + memswap_limit 4g
- 텍스트 PDF → 크기 무관 정상 파싱
- 이미지 PDF → 4GiB 초과 시 Docker OOM-kill → 재시작 → 3회 실패 후 failed

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 14:21:08 +09:00
Hyungi Ahn d5f91556e6 fix(deploy): mount migrations into fastapi container
기존 fastapi build context는 ./app이라 부모 디렉토리의 migrations/가
컨테이너에 들어가지 않아 init_db()의 _run_migrations가 디렉토리 부재로 스킵.
016까지는 postgres docker-entrypoint-initdb.d 마운트로 첫 init 시점에만
적용되었고, 이후 추가된 마이그레이션(101 등)이 자동 적용되지 못하는 문제.

./migrations:/app/migrations:ro 한 줄 마운트로 init_db()가 100+ 마이그레이션
추적 + 적용 가능. Phase 4 deploy 검증 중 발견.
2026-04-09 07:53:22 +09:00
Hyungi Ahn 3bf6193337 fix(deploy): TEI 1.5 → 1.7 (1.5는 reranker 모델 다운로드 버그)
TEI 1.5 첫 시도 시 'builder error: relative URL without a base' 에러로
BAAI/bge-reranker-v2-m3 metadata 다운로드 실패. TEI 1.5의 알려진 버그.

해결: TEI 1.7로 업그레이드 (sequence-classification reranker 모델 지원 개선).
2026-04-08 13:18:37 +09:00
Hyungi Ahn e0f928f429 feat(deploy): Phase 1.3 reranker (TEI bge-reranker-v2-m3) 서비스 추가
docker-compose.yml에 reranker 서비스 추가:
- image: ghcr.io/huggingface/text-embeddings-inference:1.5
- MODEL_ID=BAAI/bge-reranker-v2-m3
- MAX_BATCH_TOKENS=8192, MAX_CONCURRENT_REQUESTS=4
- GPU 1개 할당 (RTX 4070 Ti Super, CUDA 13.0)
- expose 80만 (host 노출 X, internal network 전용)
- reranker_cache volume으로 모델 영속화
- fastapi가 depends_on 안 함 → 단독 시작 가능, reranker 없어도 fastapi 동작
  (rerank_service가 RRF fallback)

다음 단계:
- GPU에서 docker pull로 호환성 확인
- docker compose up -d reranker → warmup
- config.yaml의 rerank.endpoint를 http://reranker:80/rerank로 갱신 (GPU 직접)
- fastapi rebuild + 평가셋 측정 (rerank=true)
2026-04-08 13:16:37 +09:00
Hyungi Ahn e0f45f9ce0 fix(deploy): primary endpoint 8801로 갱신
ai-gateway 환경 변수 PRIMARY_ENDPOINT를 8800 → 8801로 갱신.
mlx-proxy 경유 라우팅에 맞춰 정합성 확보.
2026-04-07 13:26:55 +09:00
Hyungi Ahn 87683ca000 security: NAS 마운트 검증 + AI 서비스 포트 제한 + deploy 문서 갱신
- NAS fail-fast: 시작 시 /documents/PKM 존재 확인, NFS 미마운트 방지
- ollama/ai-gateway 포트를 127.0.0.1로 제한 (외부 무인증 접근 차단)
- deploy.md: Caddy HTTPS 자동발급 → 앞단 프록시 HTTPS 종료 구조 반영

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 08:25:07 +09:00
Hyungi Ahn 3df03134ff fix: bind Caddy to 0.0.0.0:8080 for external proxy access
Mac mini nginx proxies to GPU server Caddy. localhost-only binding
blocked external connections.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 08:14:56 +09:00
Hyungi Ahn 0ca78640ee infra: migrate application from Mac mini to GPU server
- Integrate ollama + ai-gateway into root docker-compose.yml
  (NVIDIA GPU runtime, single compose for all services)
- Change NAS mount from SMB (NAS_SMB_PATH) to NFS (NAS_NFS_PATH)
  Default: /mnt/nas/Document_Server (fstab registered on GPU server)
- Update config.yaml AI endpoints:
  primary → Mac mini MLX via Tailscale (100.76.254.116:8800)
  fallback/embedding/vision/rerank → ollama (same Docker network)
  gateway → ai-gateway (same Docker network)
- Update credentials.env.example (remove GPU_SERVER_IP, add NFS path)
- Mark gpu-server/docker-compose.yml as deprecated
- Update CLAUDE.md network diagram and AI model config
- Update architecture.md, deploy.md, devlog.md for GPU server as main
- Caddyfile: auto_https off, HTTP only (TLS at upstream proxy)
- Caddy port: 127.0.0.1:8080:80 (localhost only)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 07:47:09 +09:00
Hyungi Ahn cfa95ff031 feat: implement Phase 4 SvelteKit frontend + backend enhancements
Backend:
- Add dashboard API (today stats, inbox count, law alerts, pipeline status)
- Add /api/documents/tree endpoint for sidebar domain/sub_group tree
- Migrate auth to HttpOnly cookie for refresh token (XSS defense)
- Add /api/auth/logout endpoint (cookie cleanup)
- Register dashboard router in main.py

Frontend (SvelteKit + Tailwind CSS v4):
- api.ts: fetch wrapper with refresh queue pattern, 401 single retry,
  forced logout on refresh failure
- Auth store: login/logout/refresh with memory-based access token
- UI store: toast system, sidebar state
- Login page with TOTP support
- Dashboard with 4 stat widgets + recent documents
- Document list with hybrid search (debounce, URL query state, mode select)
- Document detail with format-aware viewer (markdown/PDF/HWP/Synology/fallback)
- Metadata panel (AI summary, tags, processing history)
- Inbox triage UI (batch select, confirm dialog, domain override)
- Settings page (password change, TOTP status)

Infrastructure:
- Enable frontend service in docker-compose
- Caddy path routing (/api/* → fastapi, / → frontend) + gzip

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 06:46:19 +09:00
Hyungi Ahn d8fbe187bf fix: use port 9443 for Caddy HTTPS (8443 also taken by OrbStack)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 13:52:35 +09:00
Hyungi Ahn 0290dad923 fix: remap Caddy ports to 8080/8443 to avoid OrbStack conflict
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 13:52:08 +09:00
Hyungi Ahn 629fe37790 fix: use node fetch for kordoc healthcheck (wget/curl missing in slim)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 13:51:29 +09:00
Hyungi Ahn 8484389086 fix: change postgres external port to 15432 to avoid OrbStack conflict
Internal container communication still uses 5432.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 13:50:57 +09:00
Hyungi Ahn 16d99011db fix: disable frontend service until Phase 4, simplify Caddy proxy
Frontend SvelteKit build has dependency conflicts (Svelte 5 + Vite 8).
Phase 0 setup wizard is served by FastAPI/Jinja2, no frontend needed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 13:28:03 +09:00
Hyungi Ahn a601991f48 feat: implement Phase 0 auth system, setup wizard, and Docker config
- Add users table to migration, User ORM model
- Implement JWT+TOTP auth API (login, refresh, me, change-password)
- Add first-run setup wizard with rate-limited admin creation,
  TOTP QR enrollment (secret saved only after verification), and
  NAS path verification — served as Jinja2 single-page HTML
- Add setup redirect middleware (bypasses /health, /docs, /openapi.json)
- Mount config.yaml, scripts, logs volumes in docker-compose
- Route API vs frontend traffic in Caddyfile
- Include admin seed script as CLI fallback

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 13:21:45 +09:00
Hyungi Ahn 131dbd7b7c feat: scaffold v2 project structure with Docker, FastAPI, and config
동작하는 최소 코드 수준의 v2 스캐폴딩:

- docker-compose.yml: postgres, fastapi, kordoc, frontend, caddy
- app/: FastAPI 백엔드 (main, core, models, ai, prompts)
- services/kordoc/: Node.js 문서 파싱 마이크로서비스
- gpu-server/: AI Gateway + GPU docker-compose
- frontend/: SvelteKit 기본 구조
- migrations/: PostgreSQL 초기 스키마 (documents, tasks, processing_queue)
- tests/: pytest conftest 기본 설정
- config.yaml, Caddyfile, credentials.env.example 갱신

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 10:20:15 +09:00