fix: Codex 리뷰 5건 수정 (critical 1 + high 4)
1. [critical] config.yaml → settings 객체에서 taxonomy 로드 (import crash 방지) 2. [high] ODF 변환: file_path 유지, derived_path 별도 필드 (무한 중복 방지) 3. [high] 법령 분할: 첫 장 이전 조문을 "서문"으로 보존 4. [high] Inbox: review_status 필드 분리 (pending/approved/rejected) 5. [high] 삭제: soft-delete (deleted_at) + worker 방어 + active_documents 뷰 - 모든 조회에 deleted_at IS NULL 일관 적용 - queue_consumer: row 없으면 gracefully skip Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -40,9 +40,10 @@ class DocumentResponse(BaseModel):
|
||||
importance: str | None
|
||||
ai_confidence: float | None
|
||||
user_note: str | None
|
||||
original_path: str | None
|
||||
derived_path: str | None
|
||||
original_format: str | None
|
||||
conversion_status: str | None
|
||||
review_status: str | None
|
||||
edit_url: str | None
|
||||
preview_status: str | None
|
||||
source_channel: str | None
|
||||
@@ -101,6 +102,7 @@ async def get_document_tree(
|
||||
SELECT ai_domain, COUNT(*)
|
||||
FROM documents
|
||||
WHERE ai_domain IS NOT NULL AND ai_domain != ''
|
||||
AND deleted_at IS NULL
|
||||
GROUP BY ai_domain
|
||||
ORDER BY ai_domain
|
||||
""")
|
||||
@@ -145,7 +147,7 @@ async def list_documents(
|
||||
format: str | None = None,
|
||||
):
|
||||
"""문서 목록 조회 (페이지네이션 + 필터)"""
|
||||
query = select(Document)
|
||||
query = select(Document).where(Document.deleted_at == None)
|
||||
|
||||
if domain:
|
||||
# prefix 매칭: Industrial_Safety 클릭 시 하위 전부 포함
|
||||
@@ -181,7 +183,7 @@ async def get_document(
|
||||
):
|
||||
"""문서 단건 조회"""
|
||||
doc = await session.get(Document, doc_id)
|
||||
if not doc:
|
||||
if not doc or doc.deleted_at is not None:
|
||||
raise HTTPException(status_code=404, detail="문서를 찾을 수 없습니다")
|
||||
return DocumentResponse.model_validate(doc)
|
||||
|
||||
@@ -390,27 +392,8 @@ async def delete_document(
|
||||
if not doc:
|
||||
raise HTTPException(status_code=404, detail="문서를 찾을 수 없습니다")
|
||||
|
||||
if delete_file:
|
||||
# 원본 파일 삭제
|
||||
file_path = Path(settings.nas_mount_path) / doc.file_path
|
||||
if file_path.exists():
|
||||
file_path.unlink()
|
||||
# 변환본 삭제
|
||||
if doc.original_path:
|
||||
orig = Path(settings.nas_mount_path) / doc.original_path
|
||||
if orig.exists():
|
||||
orig.unlink()
|
||||
# preview 캐시 삭제
|
||||
preview = Path(settings.nas_mount_path) / "PKM" / ".preview" / f"{doc_id}.pdf"
|
||||
if preview.exists():
|
||||
preview.unlink()
|
||||
|
||||
# 관련 processing_queue 먼저 삭제 (FK 제약)
|
||||
from sqlalchemy import delete as sql_delete
|
||||
await session.execute(
|
||||
sql_delete(ProcessingQueue).where(ProcessingQueue.document_id == doc_id)
|
||||
)
|
||||
await session.delete(doc)
|
||||
# soft-delete (물리 파일은 cleanup job에서 나중에 정리)
|
||||
doc.deleted_at = datetime.now(timezone.utc)
|
||||
await session.commit()
|
||||
|
||||
return {"message": f"문서 {doc_id} 삭제됨", "file_deleted": delete_file}
|
||||
return {"message": f"문서 {doc_id} soft-delete 완료"}
|
||||
|
||||
Reference in New Issue
Block a user