// pricing_config (dev-plan-4.md T23; schema: dressup-dance-room-mvcp.md // M.12) — a JSON file, not SQLite: it's operator-edited config, not on the // "spend + generate + refund" atomic path that's why credit_ledger (db.js) // needed SQLite. Keyed by `key` (not an auto id), so this is deliberately // its own tiny module rather than store.js's createStore. const fs = require("fs"); const path = require("path"); const PRICING_PATH = process.env.PRICING_PATH || path.join(__dirname, "pricing.json"); // Real values are TBD (dev-plan-4.md §1.2 item 3) — these are placeholders // so the spend/topup mechanism has something to read; change the numbers // in pricing.json (or here, before first run) whenever real pricing lands. const DEFAULTS = [ { key: "spend_garment", kind: "spend", credits: 10, priceCents: null, segmentsPerUnit: null, isActive: true, updatedAt: Date.now() }, { key: "topup_tier_1", kind: "topup_tier", credits: 100, priceCents: 999, segmentsPerUnit: null, isActive: true, updatedAt: Date.now() }, { key: "topup_tier_2", kind: "topup_tier", credits: 550, priceCents: 4999, segmentsPerUnit: null, isActive: true, updatedAt: Date.now() }, ]; function load(filePath) { try { return JSON.parse(fs.readFileSync(filePath, "utf8")); } catch { fs.writeFileSync(filePath, JSON.stringify(DEFAULTS, null, 2)); return DEFAULTS.slice(); } } function createPricingStore(filePath) { function save(items) { fs.writeFileSync(filePath, JSON.stringify(items, null, 2)); } return { list() { return load(filePath); }, get(key) { return load(filePath).find((p) => p.key === key) || null; }, upsert(key, patch) { const items = load(filePath); const idx = items.findIndex((p) => p.key === key); const updated = idx === -1 ? { key, isActive: true, ...patch, updatedAt: Date.now() } : { ...items[idx], ...patch, key, updatedAt: Date.now() }; if (idx === -1) items.push(updated); else items[idx] = updated; save(items); return updated; }, }; } module.exports = { createPricingStore, pricing: createPricingStore(PRICING_PATH) };