EntryDesk × Stripe — Workspace Billing Lifecycle

涵蓋 workspace 從建立、首次付款、升降級、月結、付款失敗、取消到重新訂閱的完整生命週期。
每階段追蹤三個維度:Invoice 歷史 & 狀態Billing 頁面本期金額訂閱狀態(EntryDesk / Stripe 兩端)

圖例
Sub@ED EntryDesk 的 StripeSubscriptionMapping.status
Sub@Stripe Stripe 原生 Subscription.status(active / past_due / canceled / incomplete ...)
本期金額 Billing 頁面「Plan Overview」顯示的本期應付月費(稅前)
Invoice 狀態 Stripe 原生 draftopenpaid / uncollectible / void
總覽 — Lifecycle Flow
  ┌─────────────────────────────────────────────────────────────────────────┐
  │                     [0] 新 workspace 建立                                │
  │  全員 Starter $0 / 無 Stripe Customer / 無 Subscription / 無 Invoice     │
  └────────────────────────────────┬────────────────────────────────────────┘
                                   │
            ┌──────────────────────┴──────────────────────┐
            │                                             │
            ▼                                             ▼
  ╔═══════════════════════╗                    ╔═══════════════════════╗
  ║ [1A] 首次升級 seat    ║                    ║ [1B] 首次買 extra     ║
  ║   (Pro / Premium)     ║                    ║   usage (未訂閱)      ║
  ║                       ║                    ║                       ║
  ║ Stripe Checkout       ║                    ║ Stripe Checkout       ║
  ║  mode = subscription  ║                    ║  mode = payment       ║
  ║                       ║                    ║                       ║
  ║ 建 Customer + Sub     ║                    ║ 建 Customer (無 Sub)  ║
  ║ billing cycle 起算日  ║                    ║ 綁 payment method     ║
  ╚═══════════╦═══════════╝                    ╚═══════════╦═══════════╝
              │                                            │
              │   ┌────────────────────────────────────────┘
              │   │   (未訂閱者可反覆走 [3] 買 extra usage;
              │   │    升級 seat 時轉入 [1A] 建立 subscription)
              ▼   ▼
  ┌─────────────────────────────────────────────────────────────────────────┐
  │                      [2] Active Subscription                             │
  │         Sub@Stripe = active    /    Sub@ED = active                      │
  └──┬──────────────┬──────────────┬──────────────┬──────────────┬──────────┘
     │              │              │              │              │
     ▼              ▼              ▼              ▼              ▼
  [3] 期中       [4] 期中       [5] 期中       [6] Billing    [7] 主動
  買 extra       升級 /         降級 /          cycle           取消
  usage          新增 seat       移除 seat       renewal         訂閱
     │              │              │              │              │
     ▼              ▼              ▼              ▼              ▼
  one-off      proration       排程下期        月結 invoice    cancel_at
  invoice      invoice         生效            auto-charge     _period_end
  立即扣款     立即扣款         當期不變         │               = true
     │              │              │          ┌───┴────┐          │
     └──────────────┴──────────────┘          │        │          │
                    │                       成功      失敗        │
                    ▼                         │        │          │
           回到 [2] Active                   │         ▼          │
                                             │  ┌───────────────┐ │
                                             │  │ [8] past_due  │ │
                                             │  │   (3 天寬限)   │ │
                                             │  │  禁買 extra   │ │
                                             │  └──┬────────┬───┘ │
                                             │     │        │     │
                                             │  寬限內   寬限到期  │
                                             │  收款成功    │     │
                                             │     │        │     │
                                             └────>┘        ▼     ▼
                                                      ┌───────────────────┐
                                                      │ [9] Canceled      │
                                                      │ 全員回 Starter    │
                                                      │ Extra usage 保留   │
                                                      │ (可用完不可新買)   │
                                                      └────────┬──────────┘
                                                               │
                                                               ▼
                                                      ┌───────────────────┐
                                                      │ [10] 重新訂閱      │
                                                      │ 沿用同 Customer    │
                                                      │ 建新 Subscription │
                                                      │ 全員從 Starter 起  │
                                                      └────────┬──────────┘
                                                               │
                                                               └──> 回 [2]
各階段狀態對照
[0] 新 workspace 建立 — 全員 Starter,尚未接觸 Stripe
Invoice History (空)
Invoice 狀態
本期帳單金額 $0(全員 Starter)
Sub@ED 無記錄
Sub@Stripe 無 Customer、無 Subscription
[1A] 首次升級 seat → Checkout 完成 — 例:3/15 指派 1 Pro seat
Invoice History + Invoice #1 subscription$20 + tax,period 3/15 – 4/15
Invoice 狀態 paid(Checkout 當下即扣款成功)
本期帳單金額 $20/月(1 Pro × $20)
Sub@ED activecurrent_period = 3/15–4/15billing_cycle_start_day = 15
Sub@Stripe active
Webhooks checkout.session.completedcustomer.subscription.createdinvoice.paid
[1B] 未訂閱者首次買 extra usage — 例:3/20 購買 $50
Invoice History + Invoice #1 extra_usage$50 + tax
Invoice 狀態 paid
本期帳單金額 $0/月(仍無 subscription,Billing 頁顯示「未訂閱」)
Sub@ED 無記錄(只有 StripeCustomerMapping
Sub@Stripe 無 Subscription(只建 Customer + Payment Method)
Webhooks checkout.session.completedinvoice.paid(入 ExtraUsagePool
[3] 期中買 extra usage(已訂閱者) — 例:4/1 購買 $30
Invoice History + Invoice extra_usage$30 + tax
Invoice 狀態 paid(用儲存的 payment method 直接扣)
本期帳單金額 不變(subscription 月費不變,extra usage 為 one-off)
Sub@ED / Sub@Stripe active(不受影響)
Auto-reload 觸發走相同流程;失敗時 Invoice 狀態 = uncollectible,不入帳、不重試。
[4] 期中新增 / 升級付費 seat — 例:週期 3/15–4/15 中的 3/25 再加 1 Pro
Proration 計算 $20 × (20 天剩餘 / 31 天) ≈ $12.90
Invoice History + Proration Invoice $12.90 + tax
Invoice 狀態 paidproration_behavior: always_invoice 立即扣款)
本期帳單金額 下期起 $40/月(2 Pro × $20)
※ 當期顯示:原 $20 + proration $12.90
Sub@ED active,subscription item qty: 1 → 2
Sub@Stripe active(item quantity 更新)
升級 Pro → Premium 同理:舊 item qty-1、新 item qty+1,立即收差額。
[5] 期中降級 / 移除付費 seat — 例:4/1 把 1 Premium 降為 Pro
Invoice History (當下不產生新 Invoice)
Invoice 狀態
本期帳單金額 當期不變(仍照原 seat 計費)
下期 renewal 時才套用新價格
Sub@ED activeSeatChangeLog 記錄 effective_at = 下期起始日
Sub@Stripe active;Subscription Schedule 排到下一 billing cycle 生效
若「所有付費 seat 降為 Starter」= 等同取消訂閱 → 進入階段 [7]cancel_at_period_end = true)。
[6] Billing cycle renewal(月結) — 例:4/15 扣下一個月費用
Invoice History + Renewal Invoice subscription,本期總額 + tax,period 4/15 – 5/15
Invoice 狀態 draftopenpaid(自動扣款成功)
openpayment_failed → 進入 [8]
本期帳單金額 = (Pro 數 × $20) + (Premium 數 × $100)
Sub@ED / Sub@Stripe activecurrent_period_start/end 往後推一個月
[7] 主動取消訂閱(cancel_at_period_end) — 期中取消,當期服務到期日仍有效
Invoice History 不變
Invoice 狀態
本期帳單金額 當期照常顯示當前 seat 月費;UI 標示「將於 4/15 取消」
Sub@ED activecancel_at_period_end = true
Sub@Stripe activecancel_at_period_end = true
到期前可撤銷取消(cancel_at_period_end: false)→ 回 [2];
到期 → customer.subscription.deleted → 進入 [9]。
[8] past_due(付款失敗 3 天寬限期) — Smart Retry 自動重試
Invoice History + Renewal Invoice(已建立)
Invoice 狀態 open → retry 中(Stripe 視角仍屬未付);
寬限期結束若仍失敗 → uncollectible
本期帳單金額 照常顯示;UI 警示「付款失敗,請更新付款方式」
Sub@ED past_due禁止新買 extra usage(manual & auto-reload 皆禁);basic usage 照常
Sub@Stripe past_due
寬限期內收款成功 → invoice.paid → Invoice 狀態 = paid,移除 past_due,回 [2];
寬限期到期仍失敗 → 進入 [9]。
[9] Canceled — 主動到期 or 寬限期用盡
Invoice History 保留所有歷史紀錄
Invoice 狀態 最後一張依實際結果:paid / uncollectible
本期帳單金額 $0/月;UI 顯示「已取消,可重新訂閱」
Sub@ED canceled;所有付費 seat 降為 Starter
ExtraUsagePool 餘額保留(可用完,不可新買
Sub@Stripe canceledcustomer.subscription.deleted 已發出)
[10] 重新訂閱 — 例:5/1 重新走 Checkout
Invoice History + 新 Invoice subscription,新起始月費 + tax,period 5/1 – 6/1
Invoice 狀態 paid
本期帳單金額 依重新指派的 seat 計算
全員預設 Starter,需管理員手動指派
Sub@ED active(新的 StripeSubscriptionMapping;billing cycle 從 5/1 重算)
Sub@Stripe active(沿用同一 Customer,新的 Subscription ID)
兩條付款軌道 — Subscription vs Extra Usage
Track A — Subscription(Seat 月費)
未訂閱
  │
  │ [升級 seat]
  ▼
active ──[月結]──▶ active
  │                  │
  │ [取消]     [付款失敗]
  ▼                  ▼
canceled ◀──── past_due
  ▲                  │
  │ [重新訂閱]  [寬限期到期]
  │                  ▼
  └────────── canceled
Track B — Extra Usage(one-off,可獨立)
可購買狀態:
  ✓ 正常 active
  ✓ cancel_at_period_end (當期仍有效)
  ✗ past_due(禁止新買)
  ✗ subscription 已到期(禁止新買)

特性:
  · 未訂閱者可獨立購買(走 [1B])
  · 已入帳餘額取消訂閱後保留
  · ExtraUsagePool 為 workspace 共用
  · 失敗不重試、不入帳