🎉 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, Boolean, ForeignKey
from sqlalchemy.dialects.postgresql import UUID, ARRAY
from sqlalchemy.orm import relationship
from sqlalchemy.sql import func
import uuid
from src.core.database import Base
class Note(Base):
"""메모 테이블 (하이라이트와 1:1 관계)"""
__tablename__ = "notes"
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
# 연결 정보
highlight_id = Column(UUID(as_uuid=True), ForeignKey("highlights.id"), nullable=False, unique=True)
# 메모 내용
content = Column(Text, nullable=False)
is_private = Column(Boolean, default=True) # 개인 메모 여부
# 태그 (메모 분류용)
tags = Column(ARRAY(String), nullable=True) # ["중요", "질문", "아이디어"]
# 메타데이터
created_at = Column(DateTime(timezone=True), server_default=func.now())
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
# 관계
highlight = relationship("Highlight", back_populates="note")
@property
def user_id(self):
"""하이라이트를 통해 사용자 ID 가져오기"""
return self.highlight.user_id if self.highlight else None
@property
def document_id(self):
"""하이라이트를 통해 문서 ID 가져오기"""
return self.highlight.document_id if self.highlight else None
def __repr__(self):
return f"<Note(id='{self.id}', content='{self.content[:50]}...')>"