feat: PDF 매칭 필터링 및 서적 정보 UI 개선

- 서적 편집 페이지에서 PDF 매칭 드롭다운이 현재 서적의 PDF만 표시하도록 수정
- PDF 관리 페이지에 서적 정보 표시 UI 추가
- 타입 안전한 비교로 book_id 필터링 개선
- PDF 통계 카드에 서적별 분류 추가
- 필터 기능에 '서적 포함' 옵션 추가
- 디버깅 로그 추가로 문제 추적 개선

주요 변경사항:
- book-editor.js: String() 타입 변환으로 안전한 book_id 비교
- pdf-manager.html/js: 서적 정보 배지 및 통계 카드 추가
- book-documents.js: HTML 문서 필터링 로직 개선
This commit is contained in:
Hyungi Ahn
2025-08-26 15:32:46 +09:00
parent 04ae64fc4d
commit 8d7f4c04bb
17 changed files with 3398 additions and 400 deletions

View File

@@ -3,15 +3,19 @@
"""
from .user import User
from .document import Document, Tag
from .book import Book
from .highlight import Highlight
from .note import Note
from .bookmark import Bookmark
from .document_link import DocumentLink
__all__ = [
"User",
"Document",
"Tag",
"Book",
"Highlight",
"Note",
"Bookmark",
"DocumentLink",
]

View File

@@ -0,0 +1,53 @@
"""
문서 링크 모델
"""
from sqlalchemy import Column, String, DateTime, Text, Integer, ForeignKey
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import relationship
from sqlalchemy.sql import func
import uuid
from ..core.database import Base
class DocumentLink(Base):
"""문서 링크 테이블"""
__tablename__ = "document_links"
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
# 링크가 생성된 문서 (출발점)
source_document_id = Column(UUID(as_uuid=True), ForeignKey('documents.id'), nullable=False, index=True)
# 링크 대상 문서 (도착점)
target_document_id = Column(UUID(as_uuid=True), ForeignKey('documents.id'), nullable=False, index=True)
# 출발점 텍스트 정보 (기존)
selected_text = Column(Text, nullable=False) # 선택된 텍스트
start_offset = Column(Integer, nullable=False) # 시작 위치
end_offset = Column(Integer, nullable=False) # 끝 위치
# 도착점 텍스트 정보 (새로 추가)
target_text = Column(Text, nullable=True) # 대상 문서에서 선택된 텍스트
target_start_offset = Column(Integer, nullable=True) # 대상 문서에서 시작 위치
target_end_offset = Column(Integer, nullable=True) # 대상 문서에서 끝 위치
# 링크 메타데이터
link_text = Column(String(500), nullable=True) # 사용자 정의 링크 텍스트 (선택사항)
description = Column(Text, nullable=True) # 링크 설명 (선택사항)
# 링크 타입 (전체 문서 vs 특정 부분)
link_type = Column(String(20), default="document", nullable=False) # "document" or "text_fragment"
# 생성자 정보
created_by = Column(UUID(as_uuid=True), ForeignKey("users.id"), nullable=False)
created_at = Column(DateTime(timezone=True), server_default=func.now())
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
# 관계
source_document = relationship("Document", foreign_keys=[source_document_id], backref="outgoing_links")
target_document = relationship("Document", foreign_keys=[target_document_id], backref="incoming_links")
creator = relationship("User", backref="created_links")
def __repr__(self):
return f"<DocumentLink(id='{self.id}', text='{self.selected_text[:50]}...')>"