Public Access
1
0

feat: launch Stripe billing flows with lifecycle hardening and analytics

add Stripe checkout, portal, webhook ingestion, and idempotent event persistence

add billing lifecycle state (grace/sync/timeline/admin visibility) and stronger entitlement handling

add analytics event tracking and admin summary APIs plus account/pricing UI integration
This commit is contained in:
pguerrerox
2026-05-22 22:55:04 +00:00
parent 94b8c357b4
commit 5508e15da1
35 changed files with 2851 additions and 50 deletions
+102
View File
@@ -1,5 +1,6 @@
import type { AddonCode, BillingInterval, PlanCode } from './billing/plans.js';
import type { UsageAllowanceAvailability, UsageResource } from './billing/entitlements.js';
import type { BillingSyncStatus, BillingTimelineEventType } from './billing/lifecycle.js';
export type JobStatus = 'pending' | 'running' | 'completed' | 'failed' | 'stopped';
@@ -50,6 +51,34 @@ export interface BillingAddonBalanceSummary {
expiresAt: string | null;
}
export interface BillingWebhookEventSummary {
id: string;
provider: 'stripe';
externalEventId: string;
eventType: string;
status: 'received' | 'processed' | 'failed' | 'ignored';
externalCustomerRef: string | null;
externalSubscriptionRef: string | null;
errorMessage: string | null;
receivedAt: string;
processedAt: string | null;
}
export interface BillingTimelineEventSummary {
id: string;
workspaceId: string;
billingAccountId: string | null;
eventType: BillingTimelineEventType;
source: 'stripe' | 'app' | 'system';
payloadJson: Record<string, unknown>;
externalEventId: string | null;
externalCustomerRef: string | null;
externalSubscriptionRef: string | null;
occurredAt: string;
createdAt: string;
updatedAt: string;
}
export interface AccountBillingState {
status: AccountBillingStatus;
planCode: PlanCode | null;
@@ -57,11 +86,83 @@ export interface AccountBillingState {
currentPeriodStartsAt: string | null;
currentPeriodEndsAt: string | null;
cancelAtPeriodEnd: boolean;
canceledAt?: string | null;
trialEndsAt?: string | null;
gracePeriodEndsAt: string | null;
pendingPlanCode: PlanCode | null;
pendingPlanEffectiveAt: string | null;
billingSyncStatus: BillingSyncStatus;
lastStripeSyncAt: string | null;
provider: 'stripe' | null;
externalCustomerRef: string | null;
externalSubscriptionRef: string | null;
usage: BillingUsageResourceSummary[];
addonBalances: BillingAddonBalanceSummary[];
message: string;
}
export interface BillingCheckoutSessionResponse {
checkoutUrl: string;
}
export interface BillingPortalSessionResponse {
url: string;
}
export interface BillingDebugData {
events: BillingWebhookEventSummary[];
}
export interface BillingAdminWorkspaceSummary {
workspaceId: string;
workspaceName: string;
workspaceType: WorkspaceType;
memberCount: number;
status: AccountBillingStatus;
planCode: PlanCode | null;
billingInterval: BillingInterval | null;
currentPeriodEndsAt: string | null;
cancelAtPeriodEnd: boolean;
gracePeriodEndsAt: string | null;
pendingPlanCode: PlanCode | null;
pendingPlanEffectiveAt: string | null;
billingSyncStatus: BillingSyncStatus;
lastStripeSyncAt: string | null;
externalCustomerRef: string | null;
externalSubscriptionRef: string | null;
}
export interface BillingAdminWorkspaceDetail {
summary: BillingAdminWorkspaceSummary;
billing: AccountBillingState;
usagePeriodId: string | null;
timeline: BillingTimelineEventSummary[];
webhookEvents: BillingWebhookEventSummary[];
}
export interface BillingAdminWorkspaceListResponse {
workspaces: BillingAdminWorkspaceSummary[];
}
export interface BillingAdminWorkspaceDetailResponse {
workspace: BillingAdminWorkspaceDetail;
}
export interface AnalyticsMetricBucket {
key: string;
count: number;
}
export interface AdminAnalyticsSummary {
pricingConversionByPlan: AnalyticsMetricBucket[];
quotaExhaustionEvents: AnalyticsMetricBucket[];
upgradeTriggers: AnalyticsMetricBucket[];
addonAttach: AnalyticsMetricBucket[];
planMix: AnalyticsMetricBucket[];
churnSignals: AnalyticsMetricBucket[];
expansionSignals: AnalyticsMetricBucket[];
}
export interface AccountTeamPlaceholder {
canManageMembers: boolean;
message: string;
@@ -73,6 +174,7 @@ export interface AccountPageData {
summary: AccountSummary;
billing: AccountBillingState;
team: AccountTeamPlaceholder;
isBillingAdmin?: boolean;
}
export interface UpdateAccountProfileRequest {