원작성자 컨벤션 대조 리뷰 반영. - README 엔드포인트 표에 logout·popup/status·popup/hide 추가(누락분 포함) - user_crud: get_hide_service_info 의 불필요한 bool() 캐스트 제거 (execute 가 단일 컬럼 select 에서 이미 스칼라 반환 — get_supplier_name 과 동일) - account: popup 라우터를 me 뒤로 이동(로그인→계정→토큰→내정보→팝업 흐름) - test_auth: test_popup_hide_without_token 추가(me 섹션과 무토큰 가드 대칭) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3.6 KiB
3.6 KiB
Negosium Backend
DerbyMasters_Server 아키텍처를 이식한 FastAPI 골격. 기능은 JWT id/pw 로그인만 예시 구현. 실행·테스트·벤치마크 종합은 레포 최상위 README 참고.
디렉토리 구조
backend/
├── web_main.py # 엔트리포인트 (uvicorn)
├── config/ # 환경설정 (APP_ENV 별 toml 로드)
├── common/
│ ├── enums.py # ErrorType / DBType / DBWRType / EXCEPTION_*
│ ├── models/gmodel.py # 프로토콜 베이스 (WebPacketProtocol 등)
│ └── database/
│ ├── db_session_manager.py# ★ DB Read/Write + 람다 실행 핵심
│ └── model/models.py # ORM 모델 (tbl_account)
├── crud/user_crud.py # DB 접근 (I*CRUD 인터페이스 + 구현)
├── services/auth_service.py # 비즈니스 로직
└── router/
├── router.py # FastAPI app
└── v1/
├── auth/{account,protocol}.py # 엔드포인트 / Req_·Res_
└── validator/dependencies.py # ★ JWT 발급·검증, 해시, RemoveNoneResponse
핵심 패턴
- MVC: router(컨트롤러) → service(로직) → crud(쿼리). crud 는 인터페이스/구현 분리.
- Depends 주입: service 가
IUserCRUD = Depends(UserCRUD), router 가Depends(AuthService), 인증은Depends(IsValidAccessToken). - DB Read/Write 분리:
DBType×DBWRType조합마다 별도 async 엔진(조회=Read, 변경=Write). - 람다 DB 실행: service 는 세션을 직접 열지 않고 람다를 매니저에 넘긴다. 세션/트랜잭션은 매니저가 책임.
err, acc = await DB_SESSION_MNG.execute_lambda( # 단일 조회 tbl_account.DBType(), DBWRType.DB_READ.value, lambda s: crud.get_account_by_id(s, id)) err = await DB_SESSION_MNG.execute_lambda_run( # 여러 변경 = 1 트랜잭션 [tbl_account.DBType()], [lambda s: crud.update_last_login(s, uid)]) - 비동기: 전 계층 async/await, SQLAlchemy async + asyncpg, task 단위 scoped session.
- Protocol 규약: 모든 패킷
WebPacketProtocol상속,Req_*/Res_*(응답엔result: ErrorInfo), 라우터별protocol.py. - ResponseNone: 응답의
None필드 재귀 제거(RemoveNoneResponse). - bcrypt 비차단:
GetHashedPW/VerifyPW를asyncio.to_thread로 오프로드(이벤트 루프 비차단). → 벤치마크
엔드포인트
| Method | Path | 설명 |
|---|---|---|
| POST | /v1/auth/create |
계정 생성 (pw bcrypt 해시) |
| POST | /v1/auth/login |
로그인, access/refresh 토큰 발급 |
| POST | /v1/auth/refresh_token |
access 토큰 재발급 (refresh 필요) |
| POST | /v1/auth/logout |
로그아웃, 저장 토큰 폐기 (access 토큰 필요) |
| GET | /v1/auth/me |
내 정보 (access 토큰 필요) |
| GET | /v1/auth/popup/status |
팝업 '안내 보지 않기' 저장 상태 (access 토큰 필요) |
| POST | /v1/auth/popup/hide |
팝업 안내 보지 않기 영구 저장 (access 토큰 필요) |
실행 / 테스트
# 레포 최상위에서 docker compose up -d (backend만; DB 는 외부 PostgreSQL). 상세는 루트 README.
cd backend
pip install -r requirements.txt # 실행
python web_main.py # APP_ENV 기본 local
pip install pytest pytest-asyncio httpx # 테스트 도구
python -m pytest
- 서버: http://localhost:9300/docs
- 환경:
config.{local,test,docker}.toml(APP_ENV로 선택, docker 는 DB 호스트=host.docker.internal)