涵蓋 workspace 從建立、首次付款、升降級、月結、付款失敗、取消到重新訂閱的完整生命週期。
每階段追蹤三個維度:Invoice 歷史 & 狀態、Billing 頁面本期金額、訂閱狀態(EntryDesk / Stripe 兩端)。
StripeSubscriptionMapping.status
Subscription.status(active / past_due / canceled / incomplete ...)
draft →
open →
paid /
uncollectible /
void
┌─────────────────────────────────────────────────────────────────────────┐
│ [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]
| Invoice History | (空) |
|---|---|
| Invoice 狀態 | — |
| 本期帳單金額 | $0(全員 Starter) |
| Sub@ED | 無記錄 |
| Sub@Stripe | 無 Customer、無 Subscription |
| Invoice History |
+ Invoice #1 subscription,$20 + tax,period
3/15 – 4/15
|
|---|---|
| Invoice 狀態 | paid(Checkout 當下即扣款成功) |
| 本期帳單金額 | $20/月(1 Pro × $20) |
| Sub@ED |
active,current_period = 3/15–4/15,billing_cycle_start_day = 15
|
| Sub@Stripe | active |
checkout.session.completed →
customer.subscription.created →
invoice.paid
| Invoice History | + Invoice #1 extra_usage,$50 + tax |
|---|---|
| Invoice 狀態 | paid |
| 本期帳單金額 |
$0/月(仍無 subscription,Billing 頁顯示「未訂閱」)
|
| Sub@ED | 無記錄(只有 StripeCustomerMapping) |
| Sub@Stripe | 無 Subscription(只建 Customer + Payment Method) |
checkout.session.completed →
invoice.paid(入 ExtraUsagePool)
| Invoice History | + Invoice extra_usage,$30 + tax |
|---|---|
| Invoice 狀態 | paid(用儲存的 payment method 直接扣) |
| 本期帳單金額 | 不變(subscription 月費不變,extra usage 為 one-off) |
| Sub@ED / Sub@Stripe | active(不受影響) |
uncollectible,不入帳、不重試。
| Proration 計算 | $20 × (20 天剩餘 / 31 天) ≈ $12.90 |
|---|---|
| Invoice History | + Proration Invoice $12.90 + tax |
| Invoice 狀態 |
paid(proration_behavior: always_invoice 立即扣款)
|
| 本期帳單金額 |
下期起 $40/月(2 Pro × $20)※ 當期顯示:原 $20 + proration $12.90 |
| Sub@ED | active,subscription item qty: 1 → 2 |
| Sub@Stripe | active(item quantity 更新) |
qty-1、新 item qty+1,立即收差額。
| Invoice History | (當下不產生新 Invoice) |
|---|---|
| Invoice 狀態 | — |
| 本期帳單金額 |
當期不變(仍照原 seat 計費) 下期 renewal 時才套用新價格 |
| Sub@ED |
active;SeatChangeLog 記錄
effective_at = 下期起始日
|
| Sub@Stripe |
active;Subscription Schedule 排到下一 billing cycle 生效
|
cancel_at_period_end = true)。
| Invoice History |
+ Renewal Invoice subscription,本期總額 + tax,period
4/15 – 5/15
|
|---|---|
| Invoice 狀態 |
draft → open → paid(自動扣款成功)或 open → payment_failed → 進入 [8]
|
| 本期帳單金額 | = (Pro 數 × $20) + (Premium 數 × $100) |
| Sub@ED / Sub@Stripe |
active;current_period_start/end 往後推一個月
|
| Invoice History | 不變 |
|---|---|
| Invoice 狀態 | — |
| 本期帳單金額 |
當期照常顯示當前 seat 月費;UI 標示「將於 4/15 取消」
|
| Sub@ED | active,cancel_at_period_end = true |
| Sub@Stripe | active,cancel_at_period_end = true |
cancel_at_period_end: false)→ 回 [2];customer.subscription.deleted → 進入 [9]。
| 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];| Invoice History | 保留所有歷史紀錄 |
|---|---|
| Invoice 狀態 |
最後一張依實際結果:paid /
uncollectible
|
| 本期帳單金額 |
$0/月;UI 顯示「已取消,可重新訂閱」
|
| Sub@ED |
canceled;所有付費 seat 降為 Starter;ExtraUsagePool 餘額保留(可用完,不可新買)
|
| Sub@Stripe |
canceled(customer.subscription.deleted 已發出)
|
| 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)
|
未訂閱 │ │ [升級 seat] ▼ active ──[月結]──▶ active │ │ │ [取消] [付款失敗] ▼ ▼ canceled ◀──── past_due ▲ │ │ [重新訂閱] [寬限期到期] │ ▼ └────────── canceled
可購買狀態: ✓ 正常 active ✓ cancel_at_period_end (當期仍有效) ✗ past_due(禁止新買) ✗ subscription 已到期(禁止新買) 特性: · 未訂閱者可獨立購買(走 [1B]) · 已入帳餘額取消訂閱後保留 · ExtraUsagePool 為 workspace 共用 · 失敗不重試、不入帳