DOCS/book/300_architecture/311_FastAPI_구조_원칙.md

8.5 KiB

FastAPI 프로젝트 구조 원칙

작성일: 2025-09-17 수정일: 2025-12-01 (DB 스키마 변경 원칙, LLM 호출 최적화 원칙 추가)

1. 계층 분리 원칙

필수 계층

요청 계층 (router/)
    ↓
비즈니스 계층 (services/, llm/, brain/)
    ↓
데이터 계층 (state/, repositories/)

계층별 책임

계층 역할 금지 사항
router/ HTTP 요청/응답 처리만 DB 직접 접근, 비즈니스 로직
services/ 비즈니스 로직 구현 DB 직접 연결 (state를 통해서만)
state/ DB CRUD만 비즈니스 로직 포함

2. 폴더 구조 규칙

표준 구조

{service_name}/
├── main.py              # 앱 실행, 라우터 등록만
├── app/
│   ├── router/         # HTTP 엔드포인트
│   │   └── v1/         # API 버전 관리 (선택)
│   ├── services/       # 비즈니스 로직
│   ├── state/          # DB 접근 (Repository 패턴)
│   ├── models/         # ORM 모델 (DB 테이블 정의)
│   ├── schemas/        # Pydantic 모델 (API 요청/응답)
│   ├── core/           # 설정, 공통 기능
│   ├── db/             # DB 세션 관리 (선택)
│   └── utils/          # 유틸리티
└── tests/

폴더 명명 규칙

  • router/ 또는 api/: HTTP 처리
  • services/: 비즈니스 로직
  • state/ 또는 repositories/: Repository 패턴으로 CRUD 캡슐화
  • models/: SQLAlchemy 등 ORM 모델
  • schemas/: Pydantic 요청/응답 스키마 (models와 분리)
  • db/: DB 엔진/세션 중앙 관리 (선택)
  • 복수형 사용 권장

3. 파일 명명 규칙

router/

  • {기능}_handler.py: 이벤트 처리 (slack_handler.py)
  • {기능}_endpoint.py: REST API (emotion_endpoint.py)

services/

  • {도메인}_{기능}.py: coldmail_filter.py, ir_analyzer.py
  • 한 파일 최대 300줄

state/ (Repository 패턴)

  • database.py: 통합 DB 접근
  • {도메인}_repository.py: 도메인별 CRUD 캡슐화

models/

  • {도메인}_model.py: ORM 모델 (예: user_model.py, emotion_model.py)

schemas/

  • {도메인}_schema.py: API 입출력 스키마 (예: user_schema.py, emotion_schema.py)

4. 의존성 방향 규칙

단방향 흐름

router → services → state/repositories
  ↓         ↓         ↓
schemas   core     models
  ↓
utils

계층 간 데이터 흐름

  • router: schemas로 요청/응답 검증
  • services: schemas + models 사용 가능
  • state/repositories: models만 사용 (DB 접근)

금지 사항

  • 순환 참조: A imports B, B imports A
  • 하위가 상위 호출: state가 services 호출
  • 계층 건너뛰기: router가 직접 state 호출 (긴급 상황 제외)

5. 코드 작성 원칙

LangGraph 워크플로우

  • 복잡한 다단계 처리: LangGraph 적극 활용
  • 프로덕션 핵심 워크플로우: PostgresSaver로 체크포인트 구현 (권장)
  • 실험/경량 플로우: stateless LangGraph 허용

계층별 원칙

  • router: 서비스 호출만, DB/비즈니스 로직 금지
  • services: 비즈니스 로직 구현, state를 통한 DB 접근
  • state: DB CRUD만, 비즈니스 로직 금지

6. DB 접근 규칙

환경변수 사용

  • DATABASE_URL: 메인 DB
  • METRICS_DATABASE_URL: 메트릭 전용 DB
  • TEST_DATABASE_URL: 테스트 DB

연결 방식

  • 권장: db/database.py에서 DB 세션 중앙 관리 (의존성 주입)
  • 간단한 경우: state/database.py에서 직접 연결

금지 사항

  • 프로덕션 router/services에서 직접 asyncpg.connect()
  • 하드코딩된 DB URL
  • JSONB 저장 시 dict 직접 전달 (json.dumps() 필수)
  • 프로덕션 요청 경로에서 직접 DB 연결 재사용

6-1. DB 스키마 변경 시 동기화 필수

핵심 원칙: ORM 모델, DDL, Repository 코드를 동시에 수정해야 함

필수 동기화 항목

  1. ORM 모델 (state/{도메인}_repository.py 또는 models/{도메인}_model.py)
    • 컬럼 타입, nullable 여부, 기본값 등
  2. DDL (_ensure_tables() 또는 마이그레이션 스크립트)
    • CREATE TABLE, ALTER TABLE 문
  3. Repository 코드 (state/{도메인}_repository.py)
    • INSERT/UPDATE 시 필드 처리 로직

체크리스트

  • ORM 모델 수정 완료
  • DDL 수정 완료 (기존 DB 마이그레이션 스크립트 작성)
  • Repository 코드 수정 완료 (.get() 사용 등)
  • 테스트 작성 및 검증 완료

교훈

  • 한 곳만 수정 시 런타임 에러(KeyError 등) 또는 스키마 불일치 발생
  • 스키마 변경 시 3곳(ORM/DDL/Repository) 동시 점검 필수

7. 파일 크기 제한

  • 한 파일 최대 300줄 권장
  • 초과 시 기능별 분리

8. Import 규칙

금지

  • wildcard import (from module import *)
  • 상대 import로 순환 참조 가능성 (from ..router import x)

권장

  • 명시적 import (from app.state.database import save_emotion_reading)
  • 모듈 import (from app.services import coldmail_filter)

9. 체크리스트

코드 작성 전:

  • 이 코드는 어느 계층인가?
  • DB 접근은 state를 통하는가?
  • 비즈니스 로직이 router에 있지 않은가?
  • 순환 import 가능성은 없는가?
  • 핵심 파일은 300줄 이하로 유지할 수 있는가?
  • DB 스키마 변경 시 ORM/DDL/Repository 동시 수정 확인
  • LLM 호출 횟수 계산 및 최적화 검토
  • 원칙 문서 확인 완료 (311_FastAPI_구조_원칙.md, 312_문서_작성_원칙.md)

10. 예외 상황

허용되는 예외

  1. 긴급 핫픽스: 임시로 계층 건너뛰기 가능 (문서화 필수)
  2. 레거시 코드: 점진적 리팩토링
  3. 성능 최적화: 충분한 근거 필요

예외 처리 시

  • TODO 주석으로 계층 위반 표시
  • 긴급 수정 사유 명시

11. 로깅 원칙

로그 레벨 사용 기준 (Python logging 공식 문서):

  • DEBUG: 개발/디버깅용 상세 정보 (중간 과정, 내부 상태)
  • INFO: 정상 동작 및 주요 이벤트 (시작/종료, 주요 단계)
  • WARNING: 잠재적 문제 (예상치 못한 상황, 성능 저하 가능성)
  • ERROR: 오류 발생 (기능 실패, 예외 처리)

규칙:

  • 시작/종료는 반드시 INFO 레벨
  • 중간 과정은 DEBUG 레벨
  • 프로덕션에서는 INFO 기본, DEBUG는 필요 시에만 활성화

12. 환경변수 관리 원칙

단일 소스 원칙:

  • .env: 모든 환경변수 값의 단일 소스 (실제 값만 저장)
  • docker-compose.yml: env_file: - .env로 자동 로드, environment: 섹션은 선택사항
  • config.py: Pydantic Settings로 .env 자동 로드, 타입 검증 및 기본값만 담당

금지 사항:

  • .env, docker-compose.yml, config.py에 동일한 변수를 중복 정의
  • 코드에서 os.getenv() 직접 호출 (Pydantic Settings 사용)
  • docker-compose.ymlenvironment: 섹션에 하드코딩된 값

13. LLM 호출 최적화 원칙

핵심 원칙: 호출 횟수 계산 및 최적화 사전 검토 필수

필수 검토 사항

  1. 호출 횟수 계산: 페이지/문서당 LLM 호출 횟수 사전 계산
  2. API 할당량 확인: 사용하는 LLM API의 할당량 제한 확인 (RPM, RPD 등)
  3. 통합 가능 여부: 단일 프롬프트로 통합 가능한 작업은 반드시 통합

최적화 방법

  • 단일 호출 통합: 여러 개별 호출을 하나의 프롬프트로 통합
  • 배치 처리: 가능한 경우 여러 항목을 한 번에 처리
  • 캐싱: 동일한 입력에 대한 결과 캐싱

체크리스트

  • LLM 호출 횟수 계산 완료
  • API 할당량 제한 확인 완료
  • 통합 가능한 호출 통합 완료
  • 테스트로 호출 횟수 검증 완료

교훈

  • 호출 횟수 미검토 시 API 할당량 초과(429 에러) 발생 가능
  • 단일 프롬프트로 통합 가능한 작업은 반드시 통합하여 호출 횟수 최소화

14. 모범 사례 참고

본 문서는 FastAPI 커뮤니티의 다음 모범 사례를 반영하였습니다:

  1. models/schemas 분리: DB 스키마와 API 스펙 독립 관리
  2. Repository 패턴: state/repositories에서 CRUD 캡슐화
  3. DB 세션 중앙화: db/database.py에서 의존성 주입
  4. API 버전 관리: router/v1/, router/v2/ 구조
  5. 관심사 분리: 요청/비즈니스/데이터 계층 명확한 역할 분담