From 22fe6200cb62418b3e66fe66dd58699778d9b85e Mon Sep 17 00:00:00 2001 From: Bilal Godil Date: Fri, 10 Apr 2026 10:14:07 -0700 Subject: [PATCH] Emit delete tombstone when provider_account_id changes The ClickHouse connected_accounts table is keyed by (project_id, branch_id, user_id, provider, provider_account_id), so updating providerAccountId in place on ProjectUserOAuthAccount orphaned the old CH sort-key row: the sync re-emitted the row under the new key while the old key sat untouched with no tombstone, and FINAL couldn't collapse them. verify-data-integrity would then report a row count mismatch for connected_accounts. Record a delete tombstone for the old row state before the update runs, so the sync pipeline marks the stale sort key as deleted. --- apps/backend/src/app/api/latest/oauth-providers/crud.tsx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/backend/src/app/api/latest/oauth-providers/crud.tsx b/apps/backend/src/app/api/latest/oauth-providers/crud.tsx index 99a92d1737..5f7de19f3d 100644 --- a/apps/backend/src/app/api/latest/oauth-providers/crud.tsx +++ b/apps/backend/src/app/api/latest/oauth-providers/crud.tsx @@ -303,6 +303,14 @@ export const oauthProviderCrudHandlers = createLazyProxy(() => createCrudHandler }); } + if (data.account_id !== undefined && data.account_id !== existingOAuthAccount.providerAccountId) { + await recordExternalDbSyncDeletion(tx, { + tableName: "ProjectUserOAuthAccount", + tenancyId: auth.tenancy.id, + oauthAccountId: params.provider_id, + }); + } + await tx.projectUserOAuthAccount.update({ where: { tenancyId_id: {