-
Notifications
You must be signed in to change notification settings - Fork 2.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add sync customer command and drop subscription customer constraint #9131
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PR Summary
This PR adds a command to sync Stripe customer data with the BillingCustomer table and modifies database constraints to facilitate this synchronization.
- Added
BillingSyncCustomerDataCommand
in/billing/commands/billing-sync-customer-data.command.ts
to sync Stripe customer data for active workspaces - Removed foreign key constraint between
billingSubscription
andbillingCustomer
tables via migration1734532875877-dropSubscriptionCustomerConstraint.ts
- Added
getCustomerData()
inStripeService
lacks error handling for empty subscription results and array bounds checking - Potential data integrity risk from removing foreign key constraints without compensating application-level checks
- Command assumes Stripe API availability and lacks comprehensive error recovery strategy
5 file(s) reviewed, 6 comment(s)
Edit PR Review Bot Settings | Greptile
|
||
public async up(queryRunner: QueryRunner): Promise<void> { | ||
await queryRunner.query( | ||
`ALTER TABLE "core"."billingSubscription" DROP CONSTRAINT "FK_9120b7586c3471463480b58d20a"`, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logic: dropping this constraint removes referential integrity - ensure application code properly handles subscription cleanup when customers are deleted
{ | ||
nullable: false, | ||
onDelete: 'CASCADE', | ||
createForeignKeyConstraints: false, | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logic: disabling foreign key constraints removes database-level data integrity checks - ensure application code properly validates customer existence before subscription operations
if (!options.dryRun && !billingCustomer) { | ||
const customerData = | ||
await this.stripeService.getCustomerData(workspaceId); | ||
|
||
await this.billingCustomerRepository.upsert(customerData, { | ||
conflictPaths: ['workspaceId'], | ||
}); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logic: No validation that customerData exists or is valid before upserting. Could create empty/invalid records if Stripe call fails silently.
if (options.verbose) { | ||
this.logger.log( | ||
chalk.yellow(`Added ${workspaceId} to billingCustomer table`), | ||
); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logic: Log message indicates addition but this runs even for failed operations. Move inside the if block after successful upsert.
} catch (error) { | ||
this.logger.log( | ||
chalk.red( | ||
`Running command on workspace ${workspaceId} failed with error: ${error}, ${error.stack}`, | ||
), | ||
); | ||
continue; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: Error is logged but not tracked/reported. Consider adding error metrics or alerting for failed syncs.
query: `metadata['workspaceId']:'${workspaceId}'`, | ||
limit: 1, | ||
}); | ||
const stripeCustomerId = String(subscription.data[0].customer); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logic: direct array access without length check could throw error - validate subscription.data.length > 0 first
|
||
public async up(queryRunner: QueryRunner): Promise<void> { | ||
await queryRunner.query( | ||
`ALTER TABLE "core"."billingSubscription" DROP CONSTRAINT "FK_9120b7586c3471463480b58d20a"`, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should be removed from the original migration, otherwise we will apply it first before removing it and end up in the same issue while applying it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thank you, I've left an important comment :)
Log
|
TLDR:
Solves (https://github.com/twentyhq/private-issues/issues/212)
Add command to sync customer data from stripe to BillingCustomerTable for all active workspaces. Drop foreign key contraint on billingCustomer in BillingSubscription (in order to not break the DB).
In order to test:
Run the command:
npx nx run twenty-server:command billing:sync-customer-data
Take into consideration
Due that all the previous subscriptions in Stripe have the workspaceId in their metadata, we use that information as source of true for the data sync
Things to do: