feat(billing): bill by threshold to prevent cancellation edge case (#1583)

* feat(billing): bill by threshold to prevent cancellation edge case

* fix org billing

* fix idempotency key issue

* small optimization for team checks

* remove console log

* remove unused type

* fix error handling
This commit is contained in:
Vikhyath Mondreti
2025-10-09 21:13:54 -07:00
committed by waleed
parent 88d2e7b97b
commit 8ce5a1b7c0
14 changed files with 7575 additions and 42 deletions

View File

@@ -1,32 +1,14 @@
import { drizzle, type PostgresJsDatabase } from 'drizzle-orm/postgres-js'
import { drizzle } from 'drizzle-orm/postgres-js'
import postgres from 'postgres'
import * as schema from './schema'
export * from './schema'
export type { PostgresJsDatabase }
const connectionString = process.env.DATABASE_URL!
if (!connectionString) {
throw new Error('Missing DATABASE_URL environment variable')
}
console.log(
'[DB Pool Init]',
JSON.stringify({
timestamp: new Date().toISOString(),
nodeEnv: process.env.NODE_ENV,
action: 'CREATING_CONNECTION_POOL',
poolConfig: {
max: 30,
idle_timeout: 20,
connect_timeout: 30,
prepare: false,
},
pid: process.pid,
isProduction: process.env.NODE_ENV === 'production',
})
)
const postgresClient = postgres(connectionString, {
prepare: false,
idle_timeout: 20,

View File

@@ -0,0 +1 @@
ALTER TABLE "user_stats" ADD COLUMN "billed_overage_this_period" numeric DEFAULT '0' NOT NULL;

File diff suppressed because it is too large Load Diff

View File

@@ -673,6 +673,13 @@
"when": 1759534968812,
"tag": "0096_tranquil_arachne",
"breakpoints": true
},
{
"idx": 97,
"version": "7",
"when": 1759963094548,
"tag": "0097_dazzling_mephisto",
"breakpoints": true
}
]
}

View File

@@ -564,6 +564,7 @@ export const userStats = pgTable('user_stats', {
// Billing period tracking
currentPeriodCost: decimal('current_period_cost').notNull().default('0'), // Usage in current billing period
lastPeriodCost: decimal('last_period_cost').default('0'), // Usage from previous billing period
billedOverageThisPeriod: decimal('billed_overage_this_period').notNull().default('0'), // Amount of overage already billed via threshold billing
// Pro usage snapshot when joining a team (to prevent double-billing)
proPeriodCostSnapshot: decimal('pro_period_cost_snapshot').default('0'), // Snapshot of Pro usage when joining team
// Copilot usage tracking