fix(memos): voice memo file_type → 'immutable' (doc_type enum 호환)

GPU 서버 main pull 후 /api/memos/?archived=false 가 500 — doc_type enum 에
'audio' 값 없음 (immutable/editable/note 만). list_memos WHERE file_type IN
('note', 'audio') 가 invalid_text_representation.

수정:
- voice upload Document.file_type = 'audio' → 'immutable' (기존 audio 컨테이너
  인입과 같은 패턴: file_type='immutable' + category='audio' + source_channel='voice')
- list_memos 필터에서 file_type 조건 제거 (source_channel IN ('memo','voice') 만으로
  분리 — file_type='immutable' 필터는 일반 PDF 까지 끌어옴, 위험)
- module docstring + voice upload 주석 업데이트

원본 plan 의 file_type='audio' 결정은 doc_type enum 미확인이 원인.
enum 확장(ALTER TYPE ADD VALUE 'audio') 대신 기존 패턴 재사용 — 안전 + 회귀 X.
This commit is contained in:
Hyungi Ahn
2026-05-11 12:28:27 +09:00
parent f3693fa2ea
commit 3dc78e4f94
+10 -4
View File
@@ -1,4 +1,8 @@
"""메모 CRUD API — 파일 없는 문서(file_type='note') + voice 메모 (file_type='audio', source_channel='voice')"""
"""메모 CRUD API — text 메모(file_type='note') + voice 메모 (file_type='immutable', category='audio', source_channel='voice')
doc_type enum = (immutable, editable, note). 기존 audio 파일이 file_type='immutable' + category='audio'
패턴을 사용하므로 voice 메모도 같은 패턴 따름 (enum 확장 회피).
"""
import hashlib
import logging
@@ -267,9 +271,10 @@ async def list_memos(
"""메모 목록 — 활성: 핀 우선 + 최신순 / 아카이브: 최신순 (핀 무시)
PR-2C: source_channel='voice' (음성 메모) 도 포함. 사용자 의도 = 메모는 모든 입력의 inbox.
voice 메모는 file_type='immutable' + category='audio' + source_channel='voice' 패턴.
source_channel 만으로 분리 (file_type 필터는 immutable 다른 binary 까지 끌어옴 — 회피).
"""
base = select(Document).where(
Document.file_type.in_(("note", "audio")),
Document.source_channel.in_(("memo", "voice")),
Document.deleted_at == None, # noqa: E711
Document.archived == archived,
@@ -746,14 +751,15 @@ async def upload_voice_memo(
# file_path 는 NAS root 기준 상대 경로 (다른 documents 컨벤션, /api/documents/{id}/file endpoint 호환)
relative_path = target_path.relative_to(nas_root)
# Document row — file_type='audio', source_channel='voice'
# Document row — file_type='immutable' (binary, doc_type enum 제약) + category='audio' + source_channel='voice'
# 기존 audio 컨테이너 인입과 같은 패턴. source_channel='voice' 로 일반 audio 와 구분.
title_seed = (orig_name or "음성 메모").rsplit(".", 1)[0]
doc = Document(
file_path=str(relative_path),
file_hash=hashlib.sha256(payload).hexdigest(),
file_format=ext.lstrip(".") or "m4a",
file_size=len(payload),
file_type="audio",
file_type="immutable",
title=title_seed[:80] or "음성 메모",
extracted_text=None, # STT 후 채움
review_status="approved",