fix(mining-admin): remove CDC sync table foreign key constraints

CDC events arrive asynchronously and order is not guaranteed.
Child records (referrals, accounts) may arrive before parent (users).
This follows CDC best practices: destination tables should not have FK constraints.

Reference: https://estuary.dev/blog/cdc-done-correctly/

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
hailin 2026-01-12 08:24:10 -08:00
parent 40fbdec47c
commit ea789f7fec
2 changed files with 27 additions and 17 deletions

View File

@ -0,0 +1,21 @@
-- =============================================================================
-- 移除 CDC 同步表的外键约束
-- 原因CDC 事件异步到达,顺序不可控,子表记录可能在父表记录之前到达
-- 参考https://estuary.dev/blog/cdc-done-correctly/
-- =============================================================================
-- 移除 synced_contribution_accounts 表的外键约束
ALTER TABLE "synced_contribution_accounts"
DROP CONSTRAINT IF EXISTS "synced_contribution_accounts_accountSequence_fkey";
-- 移除 synced_referrals 表的外键约束
ALTER TABLE "synced_referrals"
DROP CONSTRAINT IF EXISTS "synced_referrals_accountSequence_fkey";
-- 移除 synced_mining_accounts 表的外键约束
ALTER TABLE "synced_mining_accounts"
DROP CONSTRAINT IF EXISTS "synced_mining_accounts_accountSequence_fkey";
-- 移除 synced_trading_accounts 表的外键约束
ALTER TABLE "synced_trading_accounts"
DROP CONSTRAINT IF EXISTS "synced_trading_accounts_accountSequence_fkey";

View File

@ -163,11 +163,8 @@ model SyncedUser {
syncedAt DateTime @default(now())
updatedAt DateTime @updatedAt
// 关联同步表
contributionAccount SyncedContributionAccount?
miningAccount SyncedMiningAccount?
tradingAccount SyncedTradingAccount?
referral SyncedReferral?
// CDC 同步表不设置外键约束,因为事件到达顺序不可控
// 使用 accountSequence 作为逻辑关联键,查询时用 LEFT JOIN
@@index([phone])
@@index([status])
@ -182,7 +179,7 @@ model SyncedUser {
model SyncedContributionAccount {
id String @id @default(uuid())
accountSequence String @unique
accountSequence String @unique // 逻辑关联 SyncedUser.accountSequence无外键约束
personalContribution Decimal @db.Decimal(30, 8) @default(0)
teamLevelContribution Decimal @db.Decimal(30, 8) @default(0)
teamBonusContribution Decimal @db.Decimal(30, 8) @default(0)
@ -195,8 +192,6 @@ model SyncedContributionAccount {
syncedAt DateTime @default(now())
updatedAt DateTime @updatedAt
user SyncedUser @relation(fields: [accountSequence], references: [accountSequence])
@@map("synced_contribution_accounts")
}
@ -206,7 +201,7 @@ model SyncedContributionAccount {
model SyncedReferral {
id String @id @default(uuid())
accountSequence String @unique
accountSequence String @unique // 逻辑关联 SyncedUser.accountSequence无外键约束
referrerAccountSequence String? // 推荐人账户序列号
referrerUserId BigInt? // 1.0 的 referrer_id
originalUserId BigInt? // 1.0 的 user_id
@ -215,8 +210,6 @@ model SyncedReferral {
syncedAt DateTime @default(now())
updatedAt DateTime @updatedAt
user SyncedUser @relation(fields: [accountSequence], references: [accountSequence])
@@index([referrerAccountSequence])
@@index([depth])
@@map("synced_referrals")
@ -308,7 +301,7 @@ model SyncedNetworkProgress {
model SyncedMiningAccount {
id String @id @default(uuid())
accountSequence String @unique
accountSequence String @unique // 逻辑关联 SyncedUser.accountSequence无外键约束
totalMined Decimal @db.Decimal(30, 8) @default(0)
availableBalance Decimal @db.Decimal(30, 8) @default(0)
frozenBalance Decimal @db.Decimal(30, 8) @default(0)
@ -316,8 +309,6 @@ model SyncedMiningAccount {
syncedAt DateTime @default(now())
updatedAt DateTime @updatedAt
user SyncedUser @relation(fields: [accountSequence], references: [accountSequence])
@@map("synced_mining_accounts")
}
@ -327,7 +318,7 @@ model SyncedMiningAccount {
model SyncedTradingAccount {
id String @id @default(uuid())
accountSequence String @unique
accountSequence String @unique // 逻辑关联 SyncedUser.accountSequence无外键约束
shareBalance Decimal @db.Decimal(30, 8) @default(0)
cashBalance Decimal @db.Decimal(30, 8) @default(0)
frozenShares Decimal @db.Decimal(30, 8) @default(0)
@ -337,8 +328,6 @@ model SyncedTradingAccount {
syncedAt DateTime @default(now())
updatedAt DateTime @updatedAt
user SyncedUser @relation(fields: [accountSequence], references: [accountSequence])
@@map("synced_trading_accounts")
}