'못 찾음'을 유한하게 종료. 두 재시도 축을 분리(기술=큐 attempts/백오프, 검색어=refine 라운드). not_found 는 정상 종료(DONE)지 dead-letter 아님. - ai/keyword: LLM 검색어 생성(정밀/광역) — 원본 0매칭 시에만 지연 호출(비용 절약) - handler: 한정 재정제 루프(원본→정밀→광역, max_rounds=3) + 명시적 outcome(found/not_found) · 0매칭+소스정상 → 다음 라운드, 0매칭+기술실패 → raise(큐 재시도) · 라운드 소진 → not_found + 네거티브 캐시 기록 - negative_cache: search_negative 테이블 + TTL(24h) upsert — 같은 상품 재요청 재검색 차단 - worker_main: OPENAI 있으면 judge+keyword_gen ON, neg_cache 상시 - tests: 재정제/not_found/캐시히트/기술실패/캐시CRUD 11건 → 전체 39/39 - 라이브: 없는상품 3라운드→not_found(30s), 재요청 캐시히트(0.00s) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| common | ||
| config | ||
| crud | ||
| router | ||
| services | ||
| tests | ||
| worker | ||
| .dockerignore | ||
| .env.example | ||
| conftest.py | ||
| Dockerfile | ||
| pytest.ini | ||
| README.md | ||
| requirements.txt | ||
| run_local_server.sh | ||
| web_main.py | ||
| worker_main.py | ||
LPS (Lowest Price Search)
인터넷 최저가를 찾는 솔루션. 프레임워크는 backend 와 동일하게 구성한 골격이며,
구체적인 도메인 로직(크롤링/오픈API 연동/최저가 산정 등)은 아직 정해지지 않았다.
스택 / 아키텍처 (backend 미러링)
- FastAPI 앱 (
router/router.py) +web_main.py부트스트랩 - 설정:
config/— TOML 로더(config.local.toml) + pydantic 모델,APP_ENV(기본 local) - DB:
common/database/db_session_manager.py— 논리 DB × Read/Write 엔진, service→람다 위임 패턴- 엔진은 lazy 생성이라 DB 없이도 부팅/healthz 동작한다. 테이블·crud 가 생기면 그때 실제 접속.
- 공통 응답 규약:
common/models/gmodel.py—Res_WebPacketProtocol.result(성공/코드/설명) - 결과 코드:
common/enums.py—ErrorType,DBType,DBWRType - 계층 컨벤션:
router(컨트롤러) →services(비즈니스) →crud(DB 접근)
폴더 구조
lps/
├── web_main.py # 진입점
├── requirements.txt / Dockerfile / .dockerignore
├── run_local_server.sh # 로컬 실행(대화형), 포트 9600
├── pytest.ini / conftest.py
├── config/
│ ├── config_loader.py / config_models.py / server_configs.py
│ └── config.local.toml.example # cp 해서 config.local.toml 로 사용(시크릿, 미커밋)
├── common/
│ ├── enums.py / logger.py / singleton.py
│ ├── utils/gtime.py
│ ├── models/gmodel.py # 프로토콜 base
│ └── database/{db_session_manager.py, model/models.py(MAIN_BASE)}
├── router/
│ ├── router.py # app + /healthz (도메인 라우터 미등록)
│ └── v1/validator/dependencies.py# RemoveNoneResponse
├── services/ # (비어있음) 도메인 서비스 추가 위치
├── crud/ # (비어있음) DB 접근 계층 추가 위치
└── tests/test_health.py # 스모크 테스트
로컬 실행
cp config/config.local.toml.example config/config.local.toml # DB 등 비-시크릿 설정
cp .env.example .env # 시크릿(API 키) — NAVER/OPENAI 등
./run_local_server.sh # → http://localhost:9600/docs
config.local.toml= 비밀 아닌 설정(포트/DB),.env= 시크릿(API 키). 둘 다 git 미추적. 워커는 별도 프로세스:python worker_main.py
테스트
python -m pytest # tests/ (기본 healthz 스모크)
포트
- backend 9300 / negodata 9400 / agent 9500 과 겹치지 않도록 LPS 는 9600 사용.
새 도메인 추가 순서 (backend 컨벤션)
common/database/model/models.py에 테이블 정의(+DBType)crud/<domain>_crud.py(ABC 인터페이스 + 구현)services/<domain>_service.py(비즈니스 로직)router/v1/<domain>/{protocol.py, <domain>.py}작성 후router/router.py에서include_router