Skip to content

Latest commit

 

History

History
585 lines (435 loc) · 12.6 KB

File metadata and controls

585 lines (435 loc) · 12.6 KB

Backend 상세 가이드

FastAPI 백엔드 코드 상세 설명


1. 애플리케이션 구조

1.1 진입점 (main.py)

app = FastAPI(
    title=settings.API_TITLE,
    version=settings.API_VERSION,
    debug=settings.DEBUG,
)

# 미들웨어 순서 (중요!)
# 1. CORS
# 2. GZip
# 3. TrustedHost (운영 환경)

1.2 서버 실행

# 개발 환경
python run_server.py

# 또는 직접 실행
uvicorn app.main:app --host 0.0.0.0 --port 8080 --reload

2. 설정 관리 (core/config.py)

2.1 주요 설정 항목

class Settings:
    # API 기본 설정
    API_TITLE = "My Research Platform API"
    API_VERSION = "0.1.0"
    DEBUG = True

    # MongoDB 설정
    MONGO_URI = "mongodb://localhost:27017"
    DATABASE_NAME = "research_forest"

    # JWT 설정
    SECRET_KEY = "your-secret-key"
    ALGORITHM = "HS256"
    ACCESS_TOKEN_EXPIRE_MINUTES = 120  # 2시간
    REFRESH_TOKEN_EXPIRE_DAYS = 30     # 30일

    # 이메일 설정
    EMAIL_PROVIDER = "gmail"  # "gmail" 또는 "naver"

    # AI 서비스
    AI_SERVICE_URL = "http://ai-service:8001"

    # 서버 설정
    HOST = "0.0.0.0"
    PORT = 8080
    HOST_IP = "필수 설정!"

2.2 CORS 설정

config.py의 CORS_ORIGINS 프로퍼티에서 자동 관리:

  • 로컬 개발 오리진
  • HOST_IP 기반 오리진
  • Netlify 배포 도메인

3. 데이터베이스 (core/database.py)

3.1 MongoDB 연결

from app.core.database import get_database

async def some_function():
    db = await get_database()
    collection = db["posts"]
    result = await collection.find_one({"_id": post_id})

3.2 주요 컬렉션

컬렉션명 설명
users 사용자 정보
posts 게시글
comments 댓글
attachments 첨부파일 메타데이터
chat_rooms 채팅방
chat_messages 채팅 메시지
banners 배너
drafts 임시저장

3.3 연결 상태 확인

from app.core.database import get_connection_status, get_database_stats

status = await get_connection_status()
stats = await get_database_stats()

4. 라우터 구조 (routers/)

4.1 라우터 등록 (main.py)

app.include_router(auth.router,       prefix="/api/auth",       tags=["인증"])
app.include_router(board.router,      prefix="/api/board",      tags=["게시판"])
app.include_router(research.router,   prefix="/api/research",   tags=["연구"])
app.include_router(chat.router,       prefix="/api/chat",       tags=["채팅"])
app.include_router(attachment.router, prefix="/api/attachment", tags=["첨부파일"])
app.include_router(admin.router,      prefix="/api/admin",      tags=["관리"])
app.include_router(ai_proxy.router,   prefix="/api/ai",         tags=["AI"])
app.include_router(draft.router,      prefix="/api/draft",      tags=["임시저장"])

# WebSocket
app.include_router(websocket_native.router, prefix="/ws", tags=["웹소켓"])

4.2 라우터 파일별 역할

파일 주요 엔드포인트 설명
auth.py POST /login, /signup, /refresh 인증 처리
board.py GET/POST/PUT/DELETE /posts 게시판 CRUD
research.py 연구 관련 API 연구 데이터 관리
chat.py GET/POST /rooms, /messages 채팅 REST API
attachment.py POST /upload, GET /download 파일 업로드/다운로드
secure_attachment.py 보안 강화 파일 API 암호화, 접근 제어
enterprise_attachment.py 엔터프라이즈 파일 API 버전 관리, 감사 로그
admin.py 관리자 전용 API 사용자/시스템 관리
ai_proxy.py AI 서비스 프록시 AI 마이크로서비스 연동
draft.py 임시저장 API 글 작성 중 자동 저장
banner.py 배너 관리 메인 페이지 배너
activity.py 활동 기록 사용자 활동 로깅
websocket_native.py WebSocket 연결 실시간 채팅
google_oauth.py Google OAuth Google 로그인

5. 인증 시스템

5.1 JWT 토큰 구조

# Access Token 페이로드
{
    "sub": "user_id",
    "email": "user@email.com",
    "role": "student",
    "exp": 1234567890  # 만료 시간
}

# Refresh Token 페이로드
{
    "sub": "user_id",
    "type": "refresh",
    "exp": 1234567890
}

5.2 인증 미들웨어 사용

from app.utils.auth_middleware import get_current_user

@router.get("/protected")
async def protected_route(current_user: dict = Depends(get_current_user)):
    return {"user": current_user}

5.3 권한 검사

from app.utils.permissions import require_permission, require_admin

@router.post("/admin-only")
async def admin_only_route(
    current_user: dict = Depends(get_current_user),
    _: None = Depends(require_admin)
):
    return {"message": "관리자 전용"}

@router.post("/write")
async def write_post(
    current_user: dict = Depends(get_current_user),
    _: None = Depends(require_permission("write"))
):
    return {"message": "글쓰기 권한 있음"}

6. 데이터 모델 (models/)

6.1 사용자 모델 (user.py)

user_schema = {
    "_id": ObjectId,
    "email": str,
    "name": str,
    "password_hash": str,
    "role": str,  # "student", "researcher", "professor", "admin"
    "is_active": bool,
    "is_admin": bool,
    "permissions": list,
    "created_at": datetime,
    "updated_at": datetime
}

6.2 게시글 구조

post_schema = {
    "_id": ObjectId,
    "title": str,
    "content": str,
    "category": str,
    "author_id": ObjectId,
    "author_name": str,
    "attachments": list,
    "view_count": int,
    "like_count": int,
    "comment_count": int,
    "created_at": datetime,
    "updated_at": datetime
}

7. 스키마 (schemas/)

Pydantic 모델로 API 요청/응답 검증

7.1 사용자 스키마 예시

from pydantic import BaseModel, EmailStr

class UserCreate(BaseModel):
    email: EmailStr
    name: str
    password: str

class UserResponse(BaseModel):
    id: str
    email: str
    name: str
    role: str
    is_admin: bool

7.2 사용법

@router.post("/signup", response_model=UserResponse)
async def signup(user_data: UserCreate):
    # user_data는 자동으로 검증됨
    ...

8. 유틸리티 (utils/)

8.1 security.py - 보안

# 비밀번호 해싱
hash_password(password: str) -> str
verify_password(plain: str, hashed: str) -> bool

# JWT 토큰
create_access_token(data: dict) -> str
create_refresh_token(data: dict) -> str
decode_token(token: str) -> dict

8.2 email.py - 이메일 발송

# 인증 이메일 발송
send_verification_email(email: str, code: str)

# 비밀번호 재설정 이메일
send_password_reset_email(email: str, reset_link: str)

8.3 permissions.py - 권한

# 권한 확인
check_permission(user: dict, permission: str) -> bool

# 게시글 작성자 확인
is_post_owner(user: dict, post: dict) -> bool

# 관리자 확인
is_admin(user: dict) -> bool

8.4 file_security.py - 파일 보안

# 파일 타입 검증
validate_file_type(filename: str, content: bytes) -> bool

# 악성 파일 검사
scan_file(file_path: str) -> bool

# 안전한 파일명 생성
generate_safe_filename(original: str) -> str

8.5 scheduler.py - 스케줄러

# 스케줄러 초기화
init_scheduler(config: dict, db)

# 정리 작업 예약
# - 만료된 임시저장 삭제
# - 오래된 로그 정리
# - 미사용 파일 정리

8.6 audit_logger.py - 감사 로그

# 감사 로그 기록
log_action(user_id: str, action: str, details: dict)

# 예: 파일 다운로드 로깅
log_action(user_id, "file_download", {"file_id": file_id})

9. 서비스 계층 (services/)

비즈니스 로직 분리

9.1 ai_client.py

# AI 서비스 호출
async def call_ai_service(prompt: str, context: dict) -> str:
    response = await httpx.post(
        f"{settings.AI_SERVICE_URL}/generate",
        json={"prompt": prompt, "context": context}
    )
    return response.json()

9.2 gdrive.py

# Google Drive 파일 업로드
upload_to_drive(file_path: str, folder_id: str) -> str

# 파일 다운로드
download_from_drive(file_id: str) -> bytes

10. 미들웨어

10.1 성능 모니터링 (main.py)

@app.middleware("http")
async def performance_monitoring_middleware(request: Request, call_next):
    start_time = time.time()
    response = await call_next(request)
    process_time = time.time() - start_time

    if process_time > 2.0:
        logger.warning(f"느린 응답: {request.url.path} - {process_time:.3f}초")

    response.headers["X-Process-Time"] = str(process_time)
    return response

10.2 CORS 미들웨어

app.add_middleware(
    CORSMiddleware,
    allow_origins=settings.CORS_ORIGINS,
    allow_credentials=False,  # Authorization 헤더만 사용
    allow_methods=["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"],
    allow_headers=["Authorization", "Content-Type"],
    max_age=86400,  # Preflight 24시간 캐시
)

11. 에러 처리

11.1 전역 예외 핸들러

@app.exception_handler(Exception)
async def global_exception_handler(request: Request, exc: Exception):
    error_id = int(time.time() * 1000000) % 1000000
    logger.error(f"예외 발생 [ID: {error_id}]: {exc}")

    return JSONResponse(
        status_code=500,
        content={
            "error": "서버 내부 오류",
            "error_id": error_id,
            "detail": str(exc) if settings.DEBUG else "관리자에게 문의"
        }
    )

11.2 HTTP 예외

from fastapi import HTTPException

# 사용 예시
if not user:
    raise HTTPException(status_code=404, detail="사용자를 찾을 수 없습니다")

if not authorized:
    raise HTTPException(status_code=403, detail="권한이 없습니다")

12. 로깅

12.1 로그 설정

# 로그 레벨: LOG_LEVEL 환경변수로 제어
# 기본값: WARNING

# 개발환경: DEBUG
# 운영환경: WARNING 또는 ERROR

LOG_LEVEL = os.getenv("LOG_LEVEL", "WARNING").upper()

12.2 로그 파일 위치

  • Linux/Unix: /tmp/research_board.log
  • Windows: %TEMP%/research_board/research_board.log

12.3 로그 포맷

2026-02-03 10:30:00 - app.main - WARNING - 느린 응답: /api/posts - 2.5초

13. 헬스체크 및 모니터링

13.1 헬스체크 엔드포인트

GET /api/health

응답:

{
    "status": "healthy",
    "timestamp": 1234567890,
    "database": {"connected": true, "latency_ms": 5},
    "system": {
        "memory_usage_percent": 45.2,
        "cpu_usage_percent": 12.5,
        "disk_usage_percent": 60.0
    },
    "version": "0.1.0"
}

13.2 시스템 통계

GET /api/system/stats

14. WebSocket (실시간 채팅)

14.1 연결

// 클라이언트
const ws = new WebSocket('wss://your-domain/ws/chat/{room_id}');

14.2 메시지 형식

// 메시지 전송
{
    "type": "message",
    "content": "안녕하세요",
    "sender_id": "user_id"
}

// 입장 알림
{
    "type": "join",
    "user_id": "user_id",
    "user_name": "홍길동"
}

15. 파일 처리

15.1 기본 첨부파일 (attachment.py)

  • 단순 업로드/다운로드
  • 파일 크기 제한

15.2 보안 첨부파일 (secure_attachment.py)

  • 파일 암호화
  • 접근 권한 검사
  • 다운로드 로깅

15.3 엔터프라이즈 첨부파일 (enterprise_attachment.py)

  • 파일 버전 관리
  • 감사 로그
  • 중복 파일 감지
  • Google Drive 연동

16. 배포 관련

16.1 Docker 설정 (Dockerfile)

FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8080"]

16.2 필수 환경변수

HOST_IP=your-server-ip          # 필수!
MONGO_URI=mongodb://...         # 필수
SECRET_KEY=your-secret          # 필수
DATABASE_NAME=research_forest

# 선택
LOG_LEVEL=WARNING
ENVIRONMENT=production
DEBUG=False