- 상품에 재고 없는 옵션(optionLabel/options — 예: 키링 색상)을 도입하고 주문 항목에 optionId/optionName 스냅샷 저장
- 주문 생성 시 옵션 검증: 옵션 상품에 미선택이면 OPTION_REQUIRED, 무옵션 상품에 optionId가 오면 INVALID_INPUT
- 같은 상품의 색상별 항목을 지원하도록 상품 문서를 productId당 한 번만 읽게 정리
- 재고는 별도 플랫폼에서 관리하므로 서버 재고 개념 전면 제거(ProductDoc 재고 필드, availableStock, 주문 예약/차감, stock/adjust 엔드포인트, order/status restock)
- 상세 카탈로그·주문 DTO에 옵션 노출, product/upsert가 optionLabel/options 수용
- 시드/업로드 스크립트의 재고 필드 기록 제거, vitest 계약 테스트 추가
- reward-products/ 이미지를 리사이즈(메인 1080px, 상세 너비 1440px) + WebP(품질 82)로 변환하는 공용 서비스 추가 (sharp)
- Storage 트리거 onRewardImageUploaded(us-central1)로 이후 업로드에도 자동 적용 — 다운로드 토큰을 보존해 기존 URL이 그대로 유효
- 기존 자산 일괄 최적화 스크립트(npm run optimize:reward-images) 추가, 실행 결과 38개 파일 135MB → 5.7MB
- 재처리 무한루프는 rewardImageOptimized 메타데이터 플래그로 방지
- 상품 카탈로그(products/) 신설: 공개 필드(name·pointPrice·이미지)와 재고(total/reserved/safety)를 한 문서로 관리, 목록·상세는 60초 인메모리 캐시로 서빙
- 주문 생성 시 포인트 예약(order_reserve)과 재고 예약을 단일 트랜잭션으로 원자 처리, 주문 ID를 uid_클라이언트멱등키로 고정해 더블탭·재시도 중복 생성 차단
- 주문 상태 머신(reserved→confirmed→preparing→shipped→delivered / cancelled / refunded) 전이 검증과 전이별 capture·release·refund 역거래 원장 기록
- reward HTTP 함수 신설: 지갑·원장 조회, 상품 목록·상세, 교환 자격, 주문 생성·목록·상세·취소 API
- 관리자 라우트 추가: 상품 등록·수정, 재고 조정(가용재고 음수 방지), 주문 상태 변경, 포인트 지급·회수
- Firestore 보안규칙(지갑 본인 read, 상품·주문은 API 전용)과 orders 복합 인덱스(uid+createdAt, status+createdAt) 추가
- 상품 4종 시드(seed:rewards)와 상세 이미지 업로드(upload:reward-assets) 스크립트 추가
특정 uid로 실제 도구·모델 루프를 돌려 호출된 도구·토큰·속도·캐시 히트를
보고하는 /debug/chatToolsSheet, /debug/chatProbe(Sheet) 엔드포인트를 추가한다
(요청별 model 오버라이드로 A/B 가능). prod에 같은 검증을 돌리는
scripts/chat-tools-sheet.ts도 추가한다.
무인증 + 임의 uid의 개인 데이터를 노출하는 검수용 임시 엔드포인트다.