0개요
‘씩씩이’는 사장님의 실제 발주 데이터를 분석해 메뉴 재료·최저가·발주 타이밍을 안내하는 식자재 발주 AI입니다. 현재 스테이징에서 정상 동작하며, 파일럿(활성·우량 41곳, 약 2주)을 위해 운영 전환이 필요합니다.
이 문서는 운영 전환에 필요한 아키텍처 · 실행법 · 시크릿 · 식별 주입 지점 · 보안 게이트 · 알려진 한계 · 배포 체크리스트를 담습니다. 분석·추천·테넌트 격리 로직은 이미 사장님(member_id) 단위로 구현되어 있어, 핵심 작업은 ‘로그인 사용자 식별 주입 + 보안/배포’입니다.
1아키텍처
[사장님 브라우저]
│ (단일 origin, /api/* 프록시)
▼
[Next.js 16 프론트] ──/api/*──▶ [FastAPI 백엔드]
· 챗 UI / 어드민 │ ├─ reference 두뇌 import (cards·llm·storage)
│ ├─ 채팅 로그 DB (SQLite: 세션·메시지·피드백·추천큐)
│ ├─ STG 발주 DB (PostgreSQL, 읽기전용) ── 발주 이력·카탈로그·가격
│ └─ BizRouter (Anthropic 호환) ── Claude Haiku
| 구성 | 스택 | 역할 |
|---|---|---|
| 프론트 | Next.js 16 · shadcn/ui · Turbopack | 챗/어드민 UI. next.config.ts rewrite로 /api/*를 백엔드에 프록시(단일 origin) |
| 백엔드 | FastAPI · uvicorn (:8000) | SSE 챗, 추천/피드백/세션, 어드민 집계. app/brain.py가 reference 두뇌를 import |
| 두뇌 | reference/ (v1 파이썬) | 카드 라우팅·핸들러, 프롬프트, DB 접근. 백엔드가 그대로 재사용 |
| 채팅 로그 DB | SQLite (storage/db) | 세션·메시지·라우팅로그·피드백·추천큐 |
| 발주 DB | STG PostgreSQL | 발주 이력·상품 카탈로그·가격 (읽기전용) |
| LLM | BizRouter → Claude Haiku | Anthropic 호환 게이트웨이 |
레포: ~/Documents/orderhero-ai-v2 (git, main). 구조: frontend/ · backend/ · reference/.
2레포 & 로컬 실행
백엔드
cd backend && source venv/bin/activate && uvicorn app.main:app --port 8000
프론트
cd frontend && npm install && npm run build && npm run start (개발: npm run dev)
| 주요 경로 | 내용 |
|---|---|
backend/app/routes/chat.py | POST /api/chat (SSE) |
backend/app/routes/{sessions,admin}.py | 추천·피드백·세션·능동제안 / 어드민 집계 |
backend/app/deps.py | get_member_id — 식별 주입 지점 (4장) |
reference/cards/router.py | 카드 라우팅(키워드 모드) |
reference/cards/card1..6, recommendations.py | 카드 핸들러·추천 빌드 |
reference/storage/orders_repo.py | STG 발주/카탈로그/가격·집계 |
reference/storage/db.py | 채팅 로그 DB + 어드민 집계 쿼리 |
reference/llm/{client,anthropic_client}.py | LLM 스트리밍 / 도구 루프 |
3환경변수 & 시크릿
두 .env는 git에 올리지 않습니다(gitignore 유지). 운영에선 시크릿 매니저/환경변수로 주입하세요.
reference/.env (백엔드 두뇌)
| 키 | 값/설명 |
|---|---|
LLM_MODE | real (실 LLM) / mock(무료 오프라인) |
ANTHROPIC_BASE_URL | https://api.bizrouter.ai (BizRouter 게이트웨이) |
MODEL_NAME | claude-haiku-4-5-20251001 |
ANTHROPIC_API_KEY | BizRouter 키 (sk-br-…) — 재발급 필요 |
ORDERS_SOURCE | stg_db |
ROUTER_MODE | keyword (LLM 분류 호출 없음 → 빠름/저비용) |
STG_DB_* | STG PostgreSQL 접속(host/port/name/user/password) — 재발급 필요 |
frontend/.env.local
NEXT_PUBLIC_API_BASE= 빈 값(같은 origin 프록시). 직접 백엔드 지정 시만 채움NEXT_PUBLIC_MEMBER_ID=0000003268(스테이징 단일 사장님 — 운영에선 제거, 4장 참조)
🔴 시크릿 로테이트. BizRouter API 키·STG 자격증명은 데모 과정에서 노출 이력이 있습니다. 운영 전 반드시 재발급하고 시크릿 매니저로 관리하세요. (이 문서엔 실제 값 미포함)
4식별 / 인증 — 운영 전환 핵심
백엔드는 사장님을 X-Member-Id 헤더에서 받습니다(app/deps.py의 get_member_id). 코드 주석에 "운영 전환 시 실제 인증(JWT 클레임)으로 교체"로 명시돼 있습니다.
현재(스테이징): 프론트 NEXT_PUBLIC_MEMBER_ID(0000003268) ──X-Member-Id──▶ 백엔드
운영(전환 후): 앱 로그인 회원 idx ───────────────────────▶ X-Member-Id(또는 JWT claim) ──▶ 백엔드
- 해야 할 일: 로그인한 사장님의 idx(member_id)를
X-Member-Id(또는 검증된 JWT 클레임)로 주입. - 그 외 분석·추천·어드민·테넌트 격리는 이미 member_id 단위로 동작 — 재작업 없음.
- 격리: 요청마다
runtime_context.set_current_member()로 테넌트 고정. 도구 호출엔 member_id를 서버가 강제 주입(LLM 입력 신뢰 안 함). - 노출 대상: 파일럿 41곳만. 로그인/접근 권한에서 게이팅(앱 측).
✅ 식별만 꽂으면 끝나는 깨끗한 seam입니다. 분석 로직은 손대지 않아도 41곳이 각자 정확히 분리됩니다.
5데이터 소스
- STG 발주 DB (PostgreSQL, 읽기전용) —
order_placement(created_at, target_seller_id/name, target_main_product_name, target_quantity, target_unit_price 등), 상품 카탈로그,seller_product_price_log(시장가 추이). 접속 실패 시 더미로 폴백. ※ 현재morty계정의 STG 10개 테이블 SELECT 권한이 전부 회수되어 데이터 조회가 실패 중(권한 오류는 더미 폴백도 안 됨) — 운영 전 권한 복구 필요(9장). - 채팅 로그 DB — 현재 SQLite 파일(
storage/db). 세션·메시지·피드백·추천큐·라우팅로그.
⚠️ 운영에서 백엔드를 다중 인스턴스로 띄우면 SQLite 파일은 부적합 → 관리형 Postgres 등으로 이전 권장. 발주 DB는 운영 STG/PROD 자격증명으로 교체.
6LLM · 비용
- 게이트웨이 BizRouter(Anthropic 호환), 모델 Claude Haiku 4.5. Anthropic SDK의
base_url오버라이드로 호출. - 라우팅은 키워드 모드라 분류용 LLM 호출이 없습니다(지연·비용 절감).
- card3(메뉴추천)/card4(분석)만 추천 카드 생성. card3 응답 ~수십초(에이전트성) — 최적화 여지(10장).
- 어드민 ‘비용·토큰’은 글자수 기반 추정치 — 정확 청구는 BizRouter 대시보드.
7API 계약
| 엔드포인트 | 설명 |
|---|---|
POST /api/chat | 헤더 X-Member-Id, body {message, session_id?} → SSE 이벤트 meta·delta·cards·done·error |
GET /api/proactive | 능동 제안(발주 타이밍·최저가) — 홈 배너 진입점 콘텐츠 소스 |
GET /api/cart · POST /api/recommendations | 장바구니 / 추천 담기 |
POST /api/feedback | 👍/👎 + VOC 텍스트 |
GET /api/sessions[/{id}/messages] | 대화 목록 · 복원 |
GET /api/admin/* | dashboard·recommendations·voc·conversations·merchants·cost·routing·errors·prompts |
모든 사용자 데이터 조회/쓰기는 X-Member-Id 기준으로 스코프됩니다.
8카드 · 라우팅
| 카드 | 역할 | 추천카드 |
|---|---|---|
| card1 | 발주 이력(월별 총액·거래처/품목 TOP·등락) — Python 집계 | — |
| card2 | 시즌·시세(정성) | — |
| card3 | 메뉴 재료 추천 | ✅ 담기 |
| card4 | 가격·재발주·최저가 비교 | ✅ 담기/발주타이밍 |
| card5 | 운영 인사이트(패턴 변화) | — |
| card6 | 발주 정산(발주액·예치금) | — |
| out_of_scope / blocked | 범위 밖 차단·안내 | — |
가드레일: 프롬프트 유출·주입 방어, 본인 데이터만(타 회원 요청 거절), 범위 밖 차단 — 마스터 페르소나에 명시.
9운영 전 필수 (Must-do)
🔴 어드민 인증. 현재
/admin·/api/admin/*에 인증이 없습니다. 운영 전 반드시 인증·권한(사내 전용)으로 보호하세요. (사장님 발주·VOC 데이터 노출)🔴 시크릿 로테이트 — BizRouter 키·STG 자격증명 재발급 + 시크릿 매니저 (3장).
🔴 STG 데이터 접근 복구 (현재 챗 먹통의 직접 원인).
morty@db_base의 STG 10개 테이블 SELECT 권한이 전부 회수되어, 모든 데이터 카드가 “답변 생성이 어려워요”로 실패합니다. 권한 오류는 더미 폴백도 안 됨(폴백은 ‘접속 실패’에만 동작). 아래 권한 복구 + 영업장 업장코드 ↔ STG member_id 매칭 검증 필요.-- 복구 대상: order_placement · seller · seller_product · seller_product_group_mscd
-- seller_product_price_log · seller_product_purchase_summary
-- member_deposit_account · member_order_details_summary · payment_deposit_log · payment_log
GRANT SELECT ON order_placement, seller, seller_product, seller_product_group_mscd,
seller_product_price_log, seller_product_purchase_summary, member_deposit_account,
member_order_details_summary, payment_deposit_log, payment_log TO morty;
⚠️ 식별 주입 — 로그인 idx →
X-Member-Id (4장).⚠️ 채팅 로그 DB — 다중 인스턴스면 SQLite→Postgres (5장).
⚠️ 진입점 디자인 — 홈 상단 ‘씩씩이 제안 배너’ 비주얼(오더히어로 톤). 콘텐츠는
/api/proactive가 공급.10알려진 한계 & TODO
| 항목 | 내용 | 상태 |
|---|---|---|
| STG 접근 / 코드 매칭 | morty 계정 STG 10개 테이블 SELECT 전부 회수 → 챗 데이터 카드 전부 실패(더미 폴백도 안 됨) · 복구 후 영업장 업장코드 = STG member_id 여부 검증 필요 | 차단 |
| 카탈로그 매칭 | 일부 품목 매칭 부정확(예: ‘김치’→‘김치만두’ — 깔끔한 매칭 상품이 카탈로그에 없을 때) | 개선 |
| 발주액 소스 정합 | ‘이번 달 발주액’이 card1(order_placement 합)과 card6(정산 this_month)에서 다를 수 있음 — 소스 일원화 필요 | 정합 |
| card3 본문↔카드 | 스트리밍 본문을 SSoT로 재사용하도록 수정됨(이중 LLM 루프 제거) | 완료 |
| 응답 속도(card3) | 에이전트성 ~21초 — 프롬프트 캐싱·도구 병렬·DB 연결 풀링으로 추가 단축 여지 | 최적화 |
| DB 연결 풀링 | 요청마다 psycopg2.connect(원격 재연결) — 운영 시 풀링 권장 | 최적화 |
| 비용 지표 | 글자수 기반 추정 — 정확값은 BizRouter | 참고 |
11배포 체크리스트
- ☐ 프론트 호스팅(예: Vercel/CF Pages) + 백엔드 호스팅(서버/컨테이너, uvicorn)
- ☐ 채팅 로그 DB → 관리형 Postgres(다중 인스턴스 시)
- ☐ 시크릿 매니저로 BizRouter 키·STG 자격증명 주입(+로테이트)
- ☐ 어드민 인증 적용
- ☐ 로그인 idx →
X-Member-Id주입,NEXT_PUBLIC_MEMBER_ID제거 - ☐ STG
order_placement등 접근 권한 복구 + 업장코드↔member_id 매칭 검증 - ☐ 파일럿 41곳만 접근 게이팅
- ☐ 홈 상단 진입 배너 비주얼 +
/api/proactive연결 - ☐ 도메인·HTTPS·모니터링(에러·비용)
오더히어로 사장님 AI ‘씩씩이’ · 개발 핸드오프 · 문의 morty
현 코드/스냅샷 기준이며 진행에 따라 갱신됩니다.