이제부터는 문서와 설계를 실제 코드로 옮기기 시작합니다. 지금까지 우리는 서비스 기획, DDD 모델링, 화면 기획, 개발환경과 품질 바닥을 먼저 정리했습니다. 그 이유는 분명합니다. 설계가 없는 상태에서 코드를 쓰면 금방 돌아가는 데모는 만들 수 있어도, 장바구니와 주문과 결제가 붙는 순간 구조가 흔들리기 때문입니다.
이번 페이지는 그 설계를 백엔드의 첫 골격으로 바꾸는 단계입니다. 아직 주문과 결제를 완성하는 장은 아니지만, 그 기능들이 안전하게 들어갈 자리를 먼저 만들어야 합니다. 그래서 이번 장에서는 FastAPI 앱의 진입점, 공통 설정, 라우터 구조, 서비스 계층, 헬스체크, 공통 모듈을 먼저 세웁니다.
중요한 것은 "일단 한 파일에서 다 돌아가게 만든다"가 아닙니다. 이번 교재는 DDD 기반 이커머스 서비스를 만드는 흐름이므로, 처음부터 이후 기능이 들어갈 경계를 같이 잡아야 합니다.
백엔드 구현을 바로 products, orders, payments 같은 기능 파일부터 시작하면 처음에는 빨라 보입니다. 하지만 그렇게 시작한 프로젝트는 보통 아래 문제를 금방 만납니다.
그래서 이번 교재에서는 기능 구현보다 먼저 "어디에 무엇을 두는지"를 서버 코드 차원에서 고정합니다. 이 골격이 있어야 다음 장에서 카탈로그, 인증, 장바구니, 주문을 붙일 때도 구조를 유지할 수 있습니다.
이 페이지를 읽고 나면 아래 항목이 정리되어 있어야 합니다.
아직 주문 생성과 결제 승인까지 구현하지 않았더라도, 서버는 최소한 아래 일을 할 수 있어야 합니다.
즉 이번 페이지의 목표는 "기능이 풍부한 서버"가 아니라, "기능을 안전하게 수용할 서버 뼈대"를 만드는 것입니다.
이번 교재에서 FastAPI는 단순히 인기 있는 프레임워크라서 고른 것이 아닙니다. 아래 이유 때문에 학습과 실습 흐름에 잘 맞습니다.
즉 FastAPI는 이번 교재의 "설계 -> API 계약 -> 구현 -> 테스트" 흐름을 자연스럽게 연결하기 좋은 도구입니다.
앱 진입점 파일은 많은 일을 하면 안 됩니다. 진입점의 역할은 아래 정도면 충분합니다.
진입점이 비대해지면 이후 기능이 들어올수록 변경 충돌이 심해집니다. 따라서 이번 교재에서는 진입점을 가능한 얇게 두고, 진짜 유스케이스 로직은 다른 계층으로 내리는 편이 맞습니다.
정확한 폴더명은 팀 규칙에 따라 조금 달라도 되지만, 사고방식은 아래처럼 가져가는 것이 좋습니다.
server/
app/
main.py
api/
routers/
schemas/
application/
domain/
infra/
shared/
tests/
이 구조에서 각 폴더는 아래 역할을 가집니다.
app: 앱 시작점과 런타임 조립api: HTTP 입출력 경계application: 유스케이스 오케스트레이션domain: 도메인 규칙과 모델infra: DB, 외부 연동, 저장소 구현shared: 설정, 예외, 공통 유틸tests: 기능과 규칙 검증이 경계가 있어야 뒤 장에서 주문과 결제를 추가할 때 어디를 건드려야 하는지 명확해집니다.
FastAPI를 쓸 때 가장 흔한 실수는 라우터 함수 안에서 모든 일을 처리하는 것입니다. 예를 들어 아래를 라우터가 직접 해버리면 구조가 금방 무너집니다.
라우터의 책임은 더 좁아야 합니다.
즉 라우터는 HTTP 경계이고, 비즈니스 로직의 본체가 아닙니다.
DDD 기반 서비스에서 application 계층은 "사용자 요청 하나를 끝까지 수행하는 흐름"을 담는 자리입니다. 예를 들어 이후 장에서 아래 유스케이스가 들어옵니다.
이 유스케이스는 보통 하나의 애그리거트 메서드만으로 끝나지 않습니다. 저장소 조회, 정책 확인, 도메인 메서드 호출, 이벤트 기록, 응답 조립 같은 여러 단계가 필요합니다. 이를 라우터나 도메인 엔티티 안에 다 넣으면 역할이 섞입니다.
그래서 이번 교재에서는 유스케이스 흐름을 application 계층에 두는 것이 맞습니다.
초반에는 단순 CRUD만 보여서 도메인 계층이 과한 것처럼 보일 수 있습니다. 하지만 이번 프로젝트는 곧 아래 규칙을 다루게 됩니다.
이런 규칙은 라우터보다 도메인에 더 가깝습니다. 따라서 지금 단계부터 domain 자리를 비워두지 말고, 이후 규칙이 들어갈 경계를 먼저 준비해야 합니다.
공통 모듈이란 이름 아래 아무 것이나 넣으면 결국 쓰레기통 폴더가 됩니다. 이번 교재에서 shared는 아래처럼 "여러 계층이 함께 쓰지만 특정 도메인에 속하지 않는 것"만 담는 것이 좋습니다.
반대로 아래는 shared에 넣으면 안 됩니다.
즉 shared는 공통 기반이고, 비즈니스 규칙 저장소가 아닙니다.
실전 프로젝트에서 설정이 가장 쉽게 무너지는 방식은 필요한 곳마다 os.getenv()를 직접 호출하는 것입니다. 이 방식은 초반에는 빠르지만, 시간이 지나면 어떤 값이 필수인지도 알기 어려워집니다.
그래서 이번 교재에서는 설정을 한 곳에서 읽어 객체로 만드는 편이 좋습니다. 예를 들면 아래 정보를 설정 객체가 들고 있을 수 있습니다.
APP_ENVAPP_HOSTAPP_PORTDB_URL 또는 DB 연결 구성SECRET_KEYPAYMENT_MODECHATBOT_ENABLED이렇게 하면 테스트에서 대체 설정을 주입하기도 쉽고, 런타임 시작 시 필수 설정 검증도 한 번에 할 수 있습니다.
지금 단계에서 아직 복잡한 리포지토리 구현이 다 나오지 않아도, 최소한 "어떻게 의존성을 주입할지"는 먼저 정해야 합니다.
이번 교재에서는 아래 사고가 필요합니다.
즉 지금은 완전한 영속 계층을 다 만들지 않더라도, 나중에 교체 가능한 구조를 위한 주입 지점을 먼저 만들어야 합니다.
헬스체크는 운영용 장식이 아닙니다. 로컬 개발에서도 유용합니다. 서버가 떴는지, 설정이 읽혔는지, 기본 라우터가 연결됐는지를 가장 빨리 확인할 수 있기 때문입니다.
이번 교재에서 헬스체크는 최소한 아래를 만족하면 충분합니다.
처음부터 복잡한 내부 상태를 모두 보여줄 필요는 없지만, 적어도 "앱이 죽지 않았고 요청을 받을 준비가 됐다"는 신호는 줘야 합니다.
나중에 한 번에 정리하려고 예외 처리를 미루면, 기능이 추가될수록 응답 형식이 제각각 됩니다.
예를 들어:
프론트와 테스트가 모두 불안정해집니다.
그래서 이번 장에서는 최소한 아래 기준을 먼저 정하는 것이 좋습니다.
이 기준이 있어야 이후 장에서 프론트도 일관된 방식으로 오류를 처리할 수 있습니다.
아직 기능이 비어 있어도 아래 정도 라우터는 먼저 두는 것이 자연스럽습니다.
healthcatalog 또는 기본 상품 조회 placeholderauth placeholderadmin placeholder왜냐하면 이후 장의 프론트 앱이 붙을 자리를 먼저 마련해야 하기 때문입니다. 완전한 구현이 아니어도 경로와 책임의 뼈대는 미리 드러나야 합니다.
첫 백엔드 골격 단계에서는 아직 도메인 테스트보다 "앱이 조립되는가"를 확인하는 테스트가 중요합니다.
예를 들면 아래 정도면 충분합니다.
이 테스트가 있어야 뒤 장에서 기능이 많아져도 최소 런타임이 깨졌는지 바로 알 수 있습니다.
이번 페이지를 코드로 옮기면 최소한 아래 산출물이 있어야 합니다.
main.py 또는 앱 팩토리health 엔드포인트이 산출물이 있으면 다음 페이지에서 프론트 골격을 붙일 때도 "호출할 백엔드가 어떤 구조로 서 있는지"가 분명해집니다.
shared 폴더에 도메인 규칙까지 다 밀어 넣는다이 여섯 가지 실수는 기능이 늘수록 구조를 빠르게 무너뜨립니다.
이 페이지에서 우리는 FastAPI 백엔드의 첫 골격을 어떤 원칙으로 세워야 하는지 정리했습니다. 앱 진입점은 얇게 두고, 라우터는 HTTP 경계만 담당하며, 유스케이스는 application, 규칙은 domain, 설정과 공통 기반은 shared에 두는 방향을 잡았습니다. 또한 헬스체크, 공통 예외 처리, 의존성 주입 지점, 스모크 테스트를 왜 처음부터 함께 가져가야 하는지도 확인했습니다.
다음 페이지에서는 이제 이 서버 골격과 나란히 움직일 storefront와 admin 프론트 앱 골격을 세웁니다.