9.8 KiB
9.8 KiB
O2Sound Backend 개발자 가이드
프로젝트 구조
backend/
├── app/
│ ├── core/ # 핵심 설정 및 유틸리티
│ │ ├── celery_app.py # Celery 설정
│ │ ├── database.py # 데이터베이스 연결
│ │ ├── env_setting.py # 환경 변수 설정
│ │ └── redis/ # Redis 관련 설정
│ ├── domain/ # 도메인 모델
│ │ └── models/ # SQLAlchemy 모델
│ ├── infra/ # 인프라 레이어
│ │ └── google/ # Google OAuth 구현
│ ├── presentation/ # 프레젠테이션 레이어
│ │ ├── api/ # API 라우터
│ │ │ └── v1/ # v1 API 엔드포인트
│ │ └── schemas/ # Pydantic 스키마
│ ├── services/ # 비즈니스 로직
│ ├── shared/ # 공통 유틸리티
│ │ ├── decorator/ # 데코레이터
│ │ ├── logger.py # 로깅 설정
│ │ └── progress.py # 진행률 추적
│ └── workers/ # Celery 작업
│ └── tasks.py # 비동기 작업 정의
├── docs/ # API 문서
├── uploads/ # 업로드된 파일
├── main.py # FastAPI 앱 엔트리포인트
├── dependencies.py # 의존성 주입
├── pyproject.toml # Poetry 설정
└── Dockerfile # Docker 설정
핵심 개념
1. DDD (Domain-Driven Design) 구조
프로젝트는 DDD 원칙을 따라 구성되어 있습니다:
- Domain Layer: 비즈니스 엔티티와 도메인 로직
- Application Layer: 서비스와 비즈니스 유스케이스
- Infrastructure Layer: 외부 시스템과의 통합
- Presentation Layer: API 엔드포인트와 스키마
2. 의존성 주입
FastAPI의 의존성 주입 시스템을 활용:
from app.dependencies import get_user_service
@router.post("/items")
async def get_items(
request: GetItemsRequest,
user_service: UserService = Depends(get_user_service)
):
return user_service.get_items(request)
3. Response Wrapper
모든 API 응답은 일관된 형식으로 래핑됩니다:
from app.shared.decorator.response_wrapper import response_wrapper
@router.post("/login")
@response_wrapper
async def login(request: LoginRequest):
# 자동으로 성공/실패 형식으로 래핑됨
return auth_service.login(request)
주요 기능 구현
1. 인증 시스템
세션 기반 인증
# main.py
app.add_middleware(SessionMiddleware, secret_key=settings.SESSION_SECRET_KEY)
OAuth 2.0 (Google)
# infra/google/service.py
class GoogleService:
async def get_login_url(self, return_url: Optional[str], request: Request):
# OAuth 플로우 시작
async def handle_callback(self, request: Request):
# 콜백 처리 및 토큰 교환
2. 비동기 작업 처리 (Celery)
작업 정의
# workers/tasks.py
@celery_app.task(bind=True)
def task1_crawl(self, url: str, root_task_id: str):
# 웹 크롤링 작업
process = Process(redis_manager)
process.update_progress(root_task_id, "metadata", True)
워크플로우 체인
# presentation/api/v1/moviemakers.py
workflow = chain(
crawl,
chord(
[lyrics_to_music, image_to_video],
task5_merge_results.s(root_task_id)
)
)
3. 진행률 추적
# shared/progress.py
class Process:
def __init__(self, redis_manager: RedisManager):
self.redis = redis_manager
async def init_task_status(self, task_id: str):
# 초기 상태 설정
async def update_progress(self, task_id: str, step: str, completed: bool):
# 진행률 업데이트
개발 환경 설정
1. 초기 설정
# Poetry 설치
pip install poetry
# 의존성 설치
poetry install
# 환경 변수 설정
cp .env.local .env
2. 개발 서버 실행
# Redis 실행 (Docker)
docker run -d -p 6379:6379 redis
# PostgreSQL 실행 (Docker)
docker run -d -p 5432:5432 \
-e POSTGRES_USER=o2sound \
-e POSTGRES_PASSWORD=password \
-e POSTGRES_DB=o2sound \
postgres:14
# Celery Worker 실행
poetry run celery -A app.core.celery_app worker --loglevel=info
# FastAPI 개발 서버
poetry run uvicorn main:app --reload --port 8000
3. 환경 변수 설정 (.env)
# 기본 설정
PROJECT_NAME=O2Sound
API_V1_STR=/api/v1
DEBUG=True
# 데이터베이스
DATABASE_URL=postgresql://o2sound:password@localhost:5432/o2sound
# Redis
REDIS_URL=redis://localhost:6379
# 세션
SESSION_SECRET_KEY=your-secret-key-here
# Google OAuth
GOOGLE_CLIENT_ID=your-client-id
GOOGLE_CLIENT_SECRET=your-client-secret
GOOGLE_REDIRECT_URI=http://localhost:8000/social/google/callback
# Celery
CELERY_BROKER_URL=redis://localhost:6379/0
CELERY_RESULT_BACKEND=redis://localhost:6379/0
새로운 기능 추가하기
1. 새 엔드포인트 추가
Step 1: 스키마 정의
# presentation/schemas/new_feature_schema.py
from pydantic import BaseModel
from uuid import UUID
class NewFeatureRequest(BaseModel):
user_id: UUID
feature_data: str
class NewFeatureResponse(BaseModel):
success: bool
result: str
Step 2: 서비스 구현
# services/new_feature_service.py
class NewFeatureService:
def __init__(self, db_session):
self.db = db_session
def process_feature(self, request: NewFeatureRequest):
# 비즈니스 로직 구현
return NewFeatureResponse(success=True, result="processed")
Step 3: 라우터 추가
# presentation/api/v1/new_feature.py
from fastapi import APIRouter, Depends
router = APIRouter(prefix="/new-feature", tags=["new-feature"])
@router.post("/process")
@response_wrapper
async def process_feature(
request: NewFeatureRequest,
service: NewFeatureService = Depends(get_new_feature_service)
):
return service.process_feature(request)
Step 4: 메인 앱에 등록
# main.py
from app.presentation.api.v1.new_feature import router as new_feature_router
app.include_router(new_feature_router)
2. 새 Celery 작업 추가
# workers/tasks.py
@celery_app.task(bind=True)
def new_async_task(self, data: dict, task_id: str):
try:
# 작업 시작
update_progress(task_id, "started", 0)
# 처리 로직
result = process_data(data)
# 완료
update_progress(task_id, "completed", 100)
return result
except Exception as e:
update_progress(task_id, "failed", -1)
raise
테스트
1. 단위 테스트
# tests/test_auth.py
import pytest
from app.services.auth_service import AuthService
def test_user_registration():
service = AuthService(mock_db_session)
result = service.join(JoinRequest(
user_id="test_user",
name="Test User",
password="password123"
))
assert result.name == "Test User"
2. API 테스트
# tests/test_api.py
from fastapi.testclient import TestClient
from main import app
client = TestClient(app)
def test_health_check():
response = client.get("/health")
assert response.status_code == 200
assert response.json()["status"] == "healthy"
3. 통합 테스트
# Postman 컬렉션 실행
newman run tests/postman/O2Sound.postman_collection.json
배포
1. Docker 빌드
docker build -t o2sound-backend .
2. Docker Compose
# docker-compose.yml
version: '3.8'
services:
backend:
image: o2sound-backend
ports:
- "8000:8000"
environment:
- DATABASE_URL=postgresql://user:pass@db:5432/o2sound
- REDIS_URL=redis://redis:6379
depends_on:
- db
- redis
worker:
image: o2sound-backend
command: celery -A app.core.celery_app worker
environment:
- CELERY_BROKER_URL=redis://redis:6379/0
depends_on:
- redis
db:
image: postgres:14
environment:
- POSTGRES_USER=user
- POSTGRES_PASSWORD=pass
- POSTGRES_DB=o2sound
redis:
image: redis:7
3. 프로덕션 체크리스트
- 환경 변수 확인
- 데이터베이스 마이그레이션
- Redis 연결 확인
- Celery Worker 실행
- 로그 설정
- 모니터링 설정
- 백업 전략 수립
모니터링
1. 로그 확인
# FastAPI 로그
tail -f logs/app.log
# Celery 로그
tail -f logs/celery.log
2. Celery Flower (웹 UI)
celery -A app.core.celery_app flower --port=5555
3. 성능 모니터링
- APM 도구 (예: New Relic, DataDog)
- Prometheus + Grafana
- ELK Stack (Elasticsearch, Logstash, Kibana)
문제 해결
일반적인 문제
-
Redis 연결 실패
❌ Redis 연결 실패: Connection refused해결: Redis 서버가 실행 중인지 확인
-
데이터베이스 연결 오류
sqlalchemy.exc.OperationalError해결: DATABASE_URL 및 PostgreSQL 서버 상태 확인
-
Celery 작업 실패
Task task1_crawl[...] raised unexpected해결: Celery Worker 로그 확인 및 재시작
디버깅 팁
-
FastAPI 자동 문서
- Swagger UI:
http://localhost:8000/docs - ReDoc:
http://localhost:8000/redoc
- Swagger UI:
-
대화형 디버깅
import pdb; pdb.set_trace() -
로그 레벨 조정
# 개발 환경에서 상세 로그 logger.setLevel(logging.DEBUG)