• credit_ledger (dev-plan-4.md T23; schema M.2) joins users/sessions in
    the same SQLite db.js — architecture.md 1.4 named this as the other
    half of why SQLite got picked in T18 ("扣积分 + 创建生成任务 + 扣减片段
    配额" needs real atomicity, T18 only used the credential-storage half).
    spend()/refund()/topup() each read-modify-write users.creditBalance
    inside a transaction; spend() refuses to take a balance negative
    (INSUFFICIENT_BALANCE) instead of allowing debt, and topup() dedupes
    by paymentRef so a Stripe webhook's guaranteed at-least-once delivery
    can't double-credit (T24 will rely on this).
    
    pricing_config (M.12) stays a JSON file via a new pricing.js — it's
    operator-edited config, not on the atomic spend path, so SQLite would
    be over-engineering here; keyed by `key` rather than an id, hence its
    own tiny module instead of store.js's createStore. Seeded with
    placeholder credit amounts (dev-plan-4.md §1.2 item 3 — real numbers
    are still TBD).
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_011DUiYs6UjxDMkfvnjtsKFo
    yibo authored
     
    Browse File »