mmday-firebase/scripts/seed-reward-products.ts
윤정민 fde21bf8c3 Add product options and remove server-side stock management
- 상품에 재고 없는 옵션(optionLabel/options — 예: 키링 색상)을 도입하고 주문 항목에 optionId/optionName 스냅샷 저장
- 주문 생성 시 옵션 검증: 옵션 상품에 미선택이면 OPTION_REQUIRED, 무옵션 상품에 optionId가 오면 INVALID_INPUT
- 같은 상품의 색상별 항목을 지원하도록 상품 문서를 productId당 한 번만 읽게 정리
- 재고는 별도 플랫폼에서 관리하므로 서버 재고 개념 전면 제거(ProductDoc 재고 필드, availableStock, 주문 예약/차감, stock/adjust 엔드포인트, order/status restock)
- 상세 카탈로그·주문 DTO에 옵션 노출, product/upsert가 optionLabel/options 수용
- 시드/업로드 스크립트의 재고 필드 기록 제거, vitest 계약 테스트 추가
2026-07-21 13:57:07 +09:00

35 lines
1.2 KiB
TypeScript

import "./_bootstrap";
import { Timestamp } from "firebase-admin/firestore";
import { firestore } from "../src/firebase";
const products = [
{ id: "acrylic-keyring", name: "아크릴 키링", pointPrice: 3000, displayOrder: 1 },
{ id: "magsafe-tok", name: "맥세이프 톡", pointPrice: 6500, displayOrder: 2 },
{ id: "keyring-doll", name: "키링 인형", pointPrice: 11000, displayOrder: 3 },
{ id: "crossbag", name: "크로스백", pointPrice: 15000, displayOrder: 4 },
] as const;
async function main() {
const now = Timestamp.now();
for (const p of products) {
const product = firestore.doc(`products/${p.id}`);
const old = await product.get();
const existing = old.data();
const draft = old.exists ? {} : {
active: false,
redeemable: false,
mainImages: [],
detailImages: [],
};
await product.set({
name: p.name,
pointPrice: p.pointPrice,
displayOrder: p.displayOrder,
...draft,
createdAt: existing?.createdAt ?? now,
updatedAt: now,
}, { merge: true });
}
}
main().then(() => console.log(`seeded ${products.length} reward products`)).catch((e) => { console.error(e); process.exitCode = 1; });