o2o-negosium-original/negodata/backend
Mina Choi 4587be5844 [refactor] negodata/backend: 공용 PageParams(page/size/skip) + 상태 enum·모델 정비
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 11:00:15 +09:00
..
common [refactor] negodata/backend: 공용 PageParams(page/size/skip) + 상태 enum·모델 정비 2026-06-18 11:00:15 +09:00
config [chore] negodata: CORS client_url 예시 + 시드 정비 + README DB 절차 갱신 2026-06-17 15:59:08 +09:00
crud [feat] negodata/backend: 상품·협력사·견적 도메인 CRUD + delivery_type 코드화 + 공용 /v1/enums 2026-06-17 15:58:38 +09:00
loadtest requirement.dev.txt 삭제 . 2026-06-15 15:58:06 +09:00
router [feat] negodata/backend: 상품·협력사·견적 도메인 CRUD + delivery_type 코드화 + 공용 /v1/enums 2026-06-17 15:58:38 +09:00
services [feat] negodata/backend: 상품·협력사·견적 도메인 CRUD + delivery_type 코드화 + 공용 /v1/enums 2026-06-17 15:58:38 +09:00
tests [feat] negodata/backend: 상품·협력사·견적 도메인 CRUD + delivery_type 코드화 + 공용 /v1/enums 2026-06-17 15:58:38 +09:00
.dockerignore requirement.dev.txt 삭제 . 2026-06-15 15:58:06 +09:00
conftest.py [feat] negodata/backend: 상품·협력사·견적 도메인 CRUD + delivery_type 코드화 + 공용 /v1/enums 2026-06-17 15:58:38 +09:00
Dockerfile Agent 서버 구축: 멀티테넌트 협상 PoC (UCB Q-Table 학습 + /chat + 14 API + 학습검증 하네스), config 단일화(local.toml) + 빌드 경량화 2026-06-17 11:10:03 +09:00
pytest.ini requirement.dev.txt 삭제 . 2026-06-15 15:58:06 +09:00
README.md requirement.dev.txt 삭제 . 2026-06-15 15:58:06 +09:00
requirements.txt [feat] negodata/backend: 상품·협력사·견적 도메인 CRUD + delivery_type 코드화 + 공용 /v1/enums 2026-06-17 15:58:38 +09:00
web_main.py requirement.dev.txt 삭제 . 2026-06-15 15:58:06 +09:00

Negodata Backend

DerbyMasters_Server 아키텍처를 이식한 FastAPI 골격. 기능은 JWT id/pw 로그인만 예시 구현. negosium-backend 와 동일 구조이며, 실행·테스트·벤치마크 종합은 레포 최상위 README 참고.

디렉토리 구조

negodata/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 필요)
GET /v1/auth/me 내 정보 (access 토큰 필요)

실행 / 테스트

# 레포 최상위에서 docker compose up -d (backend만; DB 는 외부 PostgreSQL). 상세는 루트 README.
cd negodata/backend
pip install -r requirements.txt        # 실행
python web_main.py                      # APP_ENV 기본 local
pip install pytest pytest-asyncio httpx  # 테스트 도구
python -m pytest
  • 서버: http://localhost:9400/docs
  • 환경: config.{local,test,docker}.toml (APP_ENV 로 선택, docker 는 DB 호스트=host.docker.internal, database=negodata_db)