From dd578a42f710f3d33e0e1afd568ad0fabd86b629 Mon Sep 17 00:00:00 2001 From: Claude-51124 Date: Sat, 29 Nov 2025 17:15:36 +0900 Subject: [PATCH] =?UTF-8?q?docs:=20FastAPI=20=EA=B5=AC=EC=A1=B0=20?= =?UTF-8?q?=EC=9B=90=EC=B9=99=20=EB=AC=B8=EC=84=9C=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=EA=B8=B4=20=EC=BD=94=EB=93=9C=20=EC=98=88=EC=8B=9C=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0=20(=EC=9B=90=EC=B9=99=EB=A7=8C=20=EA=B0=84=EA=B2=B0?= =?UTF-8?q?=ED=95=98=EA=B2=8C)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../311_FastAPI_구조_원칙.md | 76 +++---------------- 1 file changed, 12 insertions(+), 64 deletions(-) diff --git a/book/300_architecture/311_FastAPI_구조_원칙.md b/book/300_architecture/311_FastAPI_구조_원칙.md index 086a094..002fec8 100644 --- a/book/300_architecture/311_FastAPI_구조_원칙.md +++ b/book/300_architecture/311_FastAPI_구조_원칙.md @@ -98,46 +98,10 @@ utils - **프로덕션 핵심 워크플로우**: PostgresSaver로 체크포인트 구현 (권장) - **실험/경량 플로우**: stateless LangGraph 허용 -### router 계층 -```python -# ✅ 올바름 -async def handle_request(data: dict): - result = await some_service.process(data) # 서비스 호출 - return {"result": result} - -# ❌ 금지 -async def handle_request(data: dict): - conn = await asyncpg.connect(...) # DB 직접 접근 - result = complex_logic(data) # 비즈니스 로직 -``` - -### services 계층 -```python -# ✅ 올바름 -async def process_data(data: dict): - validated = validate(data) # 비즈니스 로직 - await save_to_db(validated) # state 호출 - return validated - -# ❌ 금지 -async def process_data(data: dict): - conn = await asyncpg.connect(...) # 직접 DB 연결 -``` - -### state 계층 -```python -# ✅ 올바름 -async def save_emotion(data: dict): - conn = await asyncpg.connect(METRICS_DB_URL) - await conn.execute("INSERT INTO ...") # DB만 - await conn.close() - -# ❌ 금지 -async def save_emotion(data: dict): - if data['emotion'] == 'anger': # 비즈니스 로직 - data = transform(data) - await conn.execute(...) -``` +### 계층별 원칙 +- **router**: 서비스 호출만, DB/비즈니스 로직 금지 +- **services**: 비즈니스 로직 구현, state를 통한 DB 접근 +- **state**: DB CRUD만, 비즈니스 로직 금지 ## 6. DB 접근 규칙 @@ -147,17 +111,8 @@ async def save_emotion(data: dict): - `TEST_DATABASE_URL`: 테스트 DB ### 연결 방식 -```python -# db/database.py: DB 세션 중앙 관리 (권장) -from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession - -async def get_session() -> AsyncSession: - pass - -# state/database.py: 직접 연결 (간단한 경우) -async def get_connection(): - return await asyncpg.connect(os.getenv("DATABASE_URL")) -``` +- **권장**: `db/database.py`에서 DB 세션 중앙 관리 (의존성 주입) +- **간단한 경우**: `state/database.py`에서 직접 연결 ### 금지 사항 - ❌ 프로덕션 router/services에서 직접 asyncpg.connect() @@ -169,21 +124,16 @@ async def get_connection(): - **한 파일 최대 300줄 권장** - 초과 시 기능별 분리 -- 예: `services/email_integration.py` (500줄) → `email_send.py` + `email_fetch.py` ## 8. Import 규칙 ### 금지 -```python -from app.state.database import * # ❌ wildcard -from ..router.slack_handler import x # ❌ 순환 가능성 -``` +- ❌ wildcard import (`from module import *`) +- ❌ 상대 import로 순환 참조 가능성 (`from ..router import x`) ### 권장 -```python -from app.state.database import save_emotion_reading # ✅ 명시적 -from app.services import coldmail_filter # ✅ 모듈 import -``` +- ✅ 명시적 import (`from app.state.database import save_emotion_reading`) +- ✅ 모듈 import (`from app.services import coldmail_filter`) ## 9. 체크리스트 @@ -202,10 +152,8 @@ from app.services import coldmail_filter # ✅ 모듈 import 3. **성능 최적화**: 충분한 근거 필요 ### 예외 처리 시 -```python -# TODO: 계층 위반 - 리팩토링 필요 -# 긴급 수정: 사유 명시 -``` +- TODO 주석으로 계층 위반 표시 +- 긴급 수정 사유 명시 ## 11. 로깅 원칙