o2o-negosium-original/backend
민헌 ba996f47c1 fix(anchoring): 3방향 적대 리뷰 반영 — 테스트 격리·Redis 방어·운영 견고화
모듈·backend·문서 3개 관점의 적대 리뷰에서 확인된 결함 일괄 수정:

[모듈]
- 배치에 company_ids 스코프 옵션 추가 — 통합 테스트가 공유 dev DB 의 실세션을
  소비/마킹하던 문제 해소(테스트는 시드 회사로 한정), 표적 수동 실행 옵션 겸용
- Redis 방어: compose 포트를 127.0.0.1 바인딩(무인증 공개 차단), get_rate 에
  범위([10,200]) 검증 — 오염 캐시값은 미스 취급 후 자가 교정, 미스 백필은 SET NX
  (배치가 방금 쓴 새 값을 구값으로 덮는 write-after-read 경합 방지)
- 배치: Redis ping 후 re-SET(다운 시 셀×timeout 지연 없이 즉시 스킵), 스캔 조인
  ON 절에 quotations/items deleted 필터(철회 거래를 학습에서 배제), 제외 마킹을
  청크별 커밋(레거시 대량 첫 실행의 장시간 단일 트랜잭션 방지)
- main: SIGTERM/SIGINT 핸들러(docker stop 시 정리 로직 보장), --once 부분 실패 시
  종료코드 1(런북/cron 감지 가능)

[backend]
- finalize_session·update_last_offered_price 에 status=IN_PROGRESS 가드 —
  negodata 일괄마감/중복 전송 경합이 종료된 세션을 되살리거나 가격 흔적을
  사후 변경하는 것 차단(파생 판정 결정성 보호)
- 신규 DB 부트스트랩: sessions 3컬럼을 postgres-init/01-schema·04-alter 에도
  반영(backend 가 모듈 DDL 없이 기동) — anchoring 스키마 자체는 모듈 소유 유지
- 낡은 주석 정리(agent_client·quotation_settings 의 구 앵커 산출 서술)

[테스트·문서]
- 신규 테스트: 격주 게이트 골든(ISO 주차), supplier_type NULL, 가격 제시율 0%
  WARN — 모듈 18개·backend 57개 통과
- 문서 정합 감사 20건 반영: 잔존 33,334/노출 문구 제거, §10 SQL 을 실제 코드
  (LEFT JOIN+deleted)와 일치, §11 자동/수동 검증 구분, FastAPI 오기 제거,
  인수인계 reader 시그니처(db 인자), TODO 백로그 5건 기록

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 20:55:46 +09:00
..
common fix(anchoring): 3방향 적대 리뷰 반영 — 테스트 격리·Redis 방어·운영 견고화 2026-07-02 20:55:46 +09:00
config Merge branch 'feature/negodata' 2026-06-23 08:31:13 +09:00
crud fix(anchoring): 3방향 적대 리뷰 반영 — 테스트 격리·Redis 방어·운영 견고화 2026-07-02 20:55:46 +09:00
loadtest chore(backend): 로컬 실행/부하테스트 스크립트 추가 2026-06-18 11:17:37 +09:00
router Merge branch 'main' into refactor/backend 2026-07-02 09:01:48 +09:00
scripts [chore] negodata: enum 주석 영문값 보강 + 견적상태 3종 정리 + 대시보드 정비 2026-06-30 17:25:38 +09:00
services fix(anchoring): 3방향 적대 리뷰 반영 — 테스트 격리·Redis 방어·운영 견고화 2026-07-02 20:55:46 +09:00
tests fix(anchoring): 3방향 적대 리뷰 반영 — 테스트 격리·Redis 방어·운영 견고화 2026-07-02 20:55:46 +09:00
.dockerignore chore(config): agent mock 모드 제거 및 .dockerignore 정리 2026-06-19 17:32:38 +09:00
conftest.py feat(backend): supplier_users 기반 인증 재구축 및 단일세션 토큰 저장 2026-06-18 11:16:33 +09:00
Dockerfile Agent 서버 구축: 멀티테넌트 협상 PoC (UCB Q-Table 학습 + /chat + 14 API + 학습검증 하네스), config 단일화(local.toml) + 빌드 경량화 2026-06-17 11:10:03 +09:00
pytest.ini 백엔드 프레임 설계 2026-06-15 15:53:39 +09:00
README.md requirement.dev.txt 삭제 . 2026-06-15 15:57:20 +09:00
requirements.txt feat(backend): 협상 채팅(chat) API + agent 위임 2026-06-18 14:24:57 +09:00
run_local_locust.sh chore(backend): 로컬 실행/부하테스트 스크립트 추가 2026-06-18 11:17:37 +09:00
run_local_pgwatch.sh chore(backend): 로컬 실행/부하테스트 스크립트 추가 2026-06-18 11:17:37 +09:00
run_local_server.sh chore(backend): 로컬 실행/부하테스트 스크립트 추가 2026-06-18 11:17:37 +09:00
web_main.py 백엔드 프레임 설계 2026-06-15 15:53:39 +09:00

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