🎉 Initial commit: Document Server MVP

 Features implemented:
- FastAPI backend with JWT authentication
- PostgreSQL database with async SQLAlchemy
- HTML document viewer with smart highlighting
- Note system connected to highlights (1:1 relationship)
- Bookmark system for quick navigation
- Integrated search (documents + notes)
- Tag system for document organization
- Docker containerization with Nginx

🔧 Technical stack:
- Backend: FastAPI + PostgreSQL + Redis
- Frontend: Alpine.js + Tailwind CSS
- Authentication: JWT tokens
- File handling: HTML + PDF support
- Search: Full-text search with relevance scoring

📋 Core functionality:
- Text selection → Highlight creation
- Highlight → Note attachment
- Note management with search/filtering
- Bookmark creation at scroll positions
- Document upload with metadata
- User management (admin creates accounts)
This commit is contained in:
Hyungi Ahn
2025-08-21 16:09:17 +09:00
commit 3036b8f0fb
40 changed files with 6303 additions and 0 deletions

View File

@@ -0,0 +1,47 @@
"""
하이라이트 모델
"""
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 src.core.database import Base
class Highlight(Base):
"""하이라이트 테이블"""
__tablename__ = "highlights"
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
# 연결 정보
user_id = Column(UUID(as_uuid=True), ForeignKey("users.id"), nullable=False)
document_id = Column(UUID(as_uuid=True), ForeignKey("documents.id"), nullable=False)
# 텍스트 위치 정보
start_offset = Column(Integer, nullable=False) # 시작 위치
end_offset = Column(Integer, nullable=False) # 끝 위치
selected_text = Column(Text, nullable=False) # 선택된 텍스트 (검색용)
# DOM 위치 정보 (정확한 복원을 위해)
element_selector = Column(Text, nullable=True) # CSS 선택자
start_container_xpath = Column(Text, nullable=True) # 시작 컨테이너 XPath
end_container_xpath = Column(Text, nullable=True) # 끝 컨테이너 XPath
# 스타일 정보
highlight_color = Column(String(7), default="#FFFF00") # HEX 색상 코드
highlight_type = Column(String(20), default="highlight") # highlight, underline, etc.
# 메타데이터
created_at = Column(DateTime(timezone=True), server_default=func.now())
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
# 관계
user = relationship("User", backref="highlights")
document = relationship("Document", back_populates="highlights")
note = relationship("Note", back_populates="highlight", uselist=False, cascade="all, delete-orphan")
def __repr__(self):
return f"<Highlight(id='{self.id}', text='{self.selected_text[:50]}...')>"