o2o-site-AEO/backend/config/config_models.py
Mina Choi 6784e59ca5 최초 커밋 — 기존 코드 전체 + 문서 체계 신설
git 저장소가 없어 히스토리·협업 기반이 아예 없던 상태를 연다.
함께 문서를 재편했다. 그동안 문서가 있어도 "이 제품이 뭘 푸는가"와
"어떻게 도는가"를 담은 문서가 없어서, 목표 문장이 backend/frontend
README 두 곳에 복붙돼 있었다 — 상위 문서가 없어 아래로 샌 것이다.

신설
  README.md               레포 진입점 + 문서 지도 + 문서 규칙 4가지
  AGENTS.md               에이전트·신규 합류자용 함정 목록과 규약
                          (CLAUDE.md 는 여기로 걸린 심볼릭 링크)
  docs/PRODUCT.md         제품 정의 — 문제·사용자·원칙·**non-goals**·성공 기준
  docs/ARCHITECTURE.md    payload 경계·발행 파이프라인·서빙 결정·앱 분리 설계

이동
  backend/docs/DECISIONS.md → docs/DECISIONS.md
    백엔드만의 결정이 아니다. 게다가 코드 주석 ~25곳이 이미
    `docs/DECISIONS.md` 로 적고 있어 레포 루트 기준으로는 그게 맞다.

갱신
  docs/DEPLOY.md          서빙 결정 반영 — nginx 정적 서빙이 지금 경로(3절),
                          Azure 는 나중에 켤 때(4절)로 분리
  docs/ARCHITECTURE.md    사이트 = 한 장(2026-08-31) 구조 반영
  docs/COLLECTION_SEO_AEO_FLOW.md
                          robots.txt·sitemap.xml 은 오리진 루트에만 굽는다는 점 명시
  frontend/site/scripts/prerender.ts
                          헤더 주석의 렌더 보고서 경로가 실제(422줄)와 달라 수정

.gitignore
  ★ CLAUDE.md 를 더 이상 무시하지 않는다. 에이전트 지침은 팀과 모든
    에이전트가 공유하는 규약이라 커밋해야 한다 — 무시하면 클론한 사람이
    "배포 후 republish_all.py 필수" 같은 함정을 전달받지 못한다.
    개인용 오버라이드는 ~/.claude/CLAUDE.md 에 둔다.
2026-08-31 13:57:59 +09:00

67 lines
3.2 KiB
Python

from config.config_loader import ConfigModel
class WebServerConfig(ConfigModel):
server_name: str = ""
port: int = 0
process_count: int = 1
is_ssl: bool = False
is_test: bool = False
client_url: str = "" # 관리자 프론트 오리진. CORS 허용 대상
landing_url: str = "" # 랜딩(마케팅 사이트) 오리진. 빈값=미허용
class LogConfig(ConfigModel):
print_console: bool = True
log_level: str = "debug"
# DB Read/Write 분리 설정.
# 하나의 논리 DB 에 대해 write(주) / read(복제) 접속 정보를 각각 가진다.
class MainDBConfig(ConfigModel):
db_type: str = "postgresql"
name: str = ""
write_host: str = ""
write_port: int = 5432
write_id: str = ""
write_pw: str = ""
read_host: str = ""
read_port: int = 5432
read_id: str = ""
read_pw: str = ""
show_log: bool = False
# 커넥션 풀 사이징. 실제 동시 커넥션 상한 = (pool_size + max_overflow) x 엔진수(R/W=2) x 워커수.
# PostgreSQL max_connections 를 넘지 않도록 설정해야 한다. (예: 10+20=30 x 2 x 5워커 = 300)
pool_size: int = 10
max_overflow: int = 20
# SSL/TLS 모드: ""/"disable"=미사용(로컬), "require"/"verify-ca"/"verify-full"=관리형 DB(RDS/Aurora/Azure).
sslmode: str = ""
class JwtToken(ConfigModel):
access_key: str = ""
refresh_key: str = ""
access_expire_min: int = 30
refresh_expire_day: int = 7
# 외부 API 키. 수집 파이프라인(Perplexity → 카카오 로컬 → 크롤링 → Gemini)이 쓴다.
# 키가 비면 해당 어댑터는 비활성 — 서버는 그대로 뜬다(부팅이 외부 계약에 묶이면 안 된다).
class ExternalApiConfig(ConfigModel):
perplexity_api_key: str = "" # 채널 URL 발견 (api.perplexity.ai)
# 동일 업소 검증 — 두 소스 중 설정된 쪽을 쓴다(둘 다 있으면 카카오 우선).
# 카카오: 15건 · 전화번호 O · 고유 place id O · 행정구역 코드 O → 판정 근거가 강하다
# 네이버: 5건 · 전화번호 X · 고유 id 불확실 · 행정구역 코드 X → 그만큼 AMBIGUOUS 가 늘어난다
kakao_rest_api_key: str = "" # dapi.kakao.com (미발급)
naver_client_id: str = "" # openapi.naver.com 지역검색
naver_client_secret: str = ""
gemini_api_key: str = "" # 사진 분류 + 카피 작성 (Google AI Studio)
# 비전 모델. 사진 1장 ≈ 1,200 토큰이라 사업장 1건(50장)에 3.7-flash $0.045 / 2.5-flash $0.018.
# 기본을 3.7 로 두는 이유: 라벨이 틀리면 사람 확인 큐 비용이 모델 값 차이보다 크다.
gemini_vision_model: str = "gemini-3.7-flash"
# 소개문·FAQ 생성 모델. 비전과 따로 둔다 — 텍스트는 토큰이 적어 상위 모델을 써도 싸다.
gemini_text_model: str = "gemini-3.7-flash"
# ★ 이 값 미만이면 자동 반영하지 않고 사람 확인 큐(PENDING_REVIEW)에 남긴다. 운영하며 조정한다.
vision_confidence_threshold: float = 0.7
tour_api_key: str = "" # 공공데이터포털 일반 인증키(전국문화축제표준데이터)