Billing - Migrate from Stripe metering (#20298)
**Overall strategy** **1. Introduce “Billing V2” behind a workspace flag** Gate the new model with FeatureFlagKey.IS_BILLING_V2_ENABLED so existing workspaces stay on the old behavior until they’re migrated or explicitly on V2. **2. Replace workflow metered SKUs with a resource-credit product** Conceptually, billable “workflow execution” usage is not the primary subscription line item anymore. Add a RESOURCE_CREDIT product (and keep WORKFLOW_NODE_EXECUTION as deprecated for the transition). Usage and limits are expressed through credit buckets (e.g. price metadata like credit_amount), so one product can represent pooled credits instead of a narrow workflow-only meter. **3. Migrate subscriptions in two layers** Schema/catalog: persist extra price metadata (instance upgrade) so the server knows credit amounts and can match Stripe prices to the new model. Per workspace: the registered workspace command upgrade:2-2:migrate-to-billing-v2 finds subscriptions that still have WORKFLOW_NODE_EXECUTION, swaps those items to the right RESOURCE_CREDIT prices (using existing Stripe schedule + BillingSubscriptionUpdateService stack), then treats the workspace as V2 (flag). Workspaces without that legacy item or without a subscription are skipped. **4. Unify subscription lifecycle + usage on the server** **5. Refresh the product surface in Settings** Test : - [x] Subscribe v1 + Update subscribe + Migrate - [x] Subscribe v2 + Update subscribe
This commit is contained in:
@@ -1484,6 +1484,7 @@ enum BillingUsageType {
|
||||
"""The different billing products available"""
|
||||
enum BillingProductKey {
|
||||
BASE_PRODUCT
|
||||
RESOURCE_CREDIT
|
||||
WORKFLOW_NODE_EXECUTION
|
||||
}
|
||||
|
||||
@@ -1492,6 +1493,7 @@ type BillingPriceLicensed {
|
||||
unitAmount: Float!
|
||||
stripePriceId: String!
|
||||
priceUsageType: BillingUsageType!
|
||||
creditAmount: Float
|
||||
}
|
||||
|
||||
enum SubscriptionInterval {
|
||||
@@ -1590,7 +1592,8 @@ type BillingMeteredProductUsage {
|
||||
|
||||
type BillingPlan {
|
||||
planKey: BillingPlanKey!
|
||||
licensedProducts: [BillingLicensedProduct!]!
|
||||
baseProducts: [BillingLicensedProduct!]!
|
||||
resourceCreditProducts: [BillingLicensedProduct!]!
|
||||
meteredProducts: [BillingMeteredProduct!]!
|
||||
}
|
||||
|
||||
@@ -1754,6 +1757,7 @@ enum FeatureFlagKey {
|
||||
IS_RICH_TEXT_V1_MIGRATED
|
||||
IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED
|
||||
IS_DATASOURCE_MIGRATED
|
||||
IS_BILLING_V2_ENABLED
|
||||
}
|
||||
|
||||
type WorkspaceUrls {
|
||||
|
||||
@@ -1145,13 +1145,14 @@ export type BillingUsageType = 'METERED' | 'LICENSED'
|
||||
|
||||
|
||||
/** The different billing products available */
|
||||
export type BillingProductKey = 'BASE_PRODUCT' | 'WORKFLOW_NODE_EXECUTION'
|
||||
export type BillingProductKey = 'BASE_PRODUCT' | 'RESOURCE_CREDIT' | 'WORKFLOW_NODE_EXECUTION'
|
||||
|
||||
export interface BillingPriceLicensed {
|
||||
recurringInterval: SubscriptionInterval
|
||||
unitAmount: Scalars['Float']
|
||||
stripePriceId: Scalars['String']
|
||||
priceUsageType: BillingUsageType
|
||||
creditAmount?: Scalars['Float']
|
||||
__typename: 'BillingPriceLicensed'
|
||||
}
|
||||
|
||||
@@ -1244,7 +1245,8 @@ export interface BillingMeteredProductUsage {
|
||||
|
||||
export interface BillingPlan {
|
||||
planKey: BillingPlanKey
|
||||
licensedProducts: BillingLicensedProduct[]
|
||||
baseProducts: BillingLicensedProduct[]
|
||||
resourceCreditProducts: BillingLicensedProduct[]
|
||||
meteredProducts: BillingMeteredProduct[]
|
||||
__typename: 'BillingPlan'
|
||||
}
|
||||
@@ -1386,7 +1388,7 @@ export interface FeatureFlag {
|
||||
__typename: 'FeatureFlag'
|
||||
}
|
||||
|
||||
export type FeatureFlagKey = 'IS_UNIQUE_INDEXES_ENABLED' | 'IS_JSON_FILTER_ENABLED' | 'IS_COMMAND_MENU_ITEM_ENABLED' | 'IS_MARKETPLACE_SETTING_TAB_VISIBLE' | 'IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED' | 'IS_PUBLIC_DOMAIN_ENABLED' | 'IS_EMAILING_DOMAIN_ENABLED' | 'IS_JUNCTION_RELATIONS_ENABLED' | 'IS_CONNECTED_ACCOUNT_MIGRATED' | 'IS_RICH_TEXT_V1_MIGRATED' | 'IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED' | 'IS_DATASOURCE_MIGRATED'
|
||||
export type FeatureFlagKey = 'IS_UNIQUE_INDEXES_ENABLED' | 'IS_JSON_FILTER_ENABLED' | 'IS_COMMAND_MENU_ITEM_ENABLED' | 'IS_MARKETPLACE_SETTING_TAB_VISIBLE' | 'IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED' | 'IS_PUBLIC_DOMAIN_ENABLED' | 'IS_EMAILING_DOMAIN_ENABLED' | 'IS_JUNCTION_RELATIONS_ENABLED' | 'IS_CONNECTED_ACCOUNT_MIGRATED' | 'IS_RICH_TEXT_V1_MIGRATED' | 'IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED' | 'IS_DATASOURCE_MIGRATED' | 'IS_BILLING_V2_ENABLED'
|
||||
|
||||
export interface WorkspaceUrls {
|
||||
customUrl?: Scalars['String']
|
||||
@@ -4079,6 +4081,7 @@ export interface BillingPriceLicensedGenqlSelection{
|
||||
unitAmount?: boolean | number
|
||||
stripePriceId?: boolean | number
|
||||
priceUsageType?: boolean | number
|
||||
creditAmount?: boolean | number
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
@@ -4177,7 +4180,8 @@ export interface BillingMeteredProductUsageGenqlSelection{
|
||||
|
||||
export interface BillingPlanGenqlSelection{
|
||||
planKey?: boolean | number
|
||||
licensedProducts?: BillingLicensedProductGenqlSelection
|
||||
baseProducts?: BillingLicensedProductGenqlSelection
|
||||
resourceCreditProducts?: BillingLicensedProductGenqlSelection
|
||||
meteredProducts?: BillingMeteredProductGenqlSelection
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
@@ -8629,6 +8633,7 @@ export const enumBillingUsageType = {
|
||||
|
||||
export const enumBillingProductKey = {
|
||||
BASE_PRODUCT: 'BASE_PRODUCT' as const,
|
||||
RESOURCE_CREDIT: 'RESOURCE_CREDIT' as const,
|
||||
WORKFLOW_NODE_EXECUTION: 'WORKFLOW_NODE_EXECUTION' as const
|
||||
}
|
||||
|
||||
@@ -8690,7 +8695,8 @@ export const enumFeatureFlagKey = {
|
||||
IS_CONNECTED_ACCOUNT_MIGRATED: 'IS_CONNECTED_ACCOUNT_MIGRATED' as const,
|
||||
IS_RICH_TEXT_V1_MIGRATED: 'IS_RICH_TEXT_V1_MIGRATED' as const,
|
||||
IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED: 'IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED' as const,
|
||||
IS_DATASOURCE_MIGRATED: 'IS_DATASOURCE_MIGRATED' as const
|
||||
IS_DATASOURCE_MIGRATED: 'IS_DATASOURCE_MIGRATED' as const,
|
||||
IS_BILLING_V2_ENABLED: 'IS_BILLING_V2_ENABLED' as const
|
||||
}
|
||||
|
||||
export const enumIdentityProviderType = {
|
||||
|
||||
@@ -2956,6 +2956,9 @@ export default {
|
||||
"priceUsageType": [
|
||||
136
|
||||
],
|
||||
"creditAmount": [
|
||||
11
|
||||
],
|
||||
"__typename": [
|
||||
1
|
||||
]
|
||||
@@ -3143,7 +3146,10 @@ export default {
|
||||
"planKey": [
|
||||
135
|
||||
],
|
||||
"licensedProducts": [
|
||||
"baseProducts": [
|
||||
143
|
||||
],
|
||||
"resourceCreditProducts": [
|
||||
143
|
||||
],
|
||||
"meteredProducts": [
|
||||
|
||||
Reference in New Issue
Block a user