fix: 修复多个服务的 accountSequence 类型和推荐关系 bug

1. referral-service: 修复 userId 从临时值 0 导致的 "用户ID必须大于0" 错误
   - 从 accountSequence 提取数值部分作为 userId (去掉 "D" 前缀)
   - 避免依赖 identity-service 发送的临时 userId

2. 多服务 migration 修复: accountSequence/inviterSequence 类型从 BIGINT 改为 VARCHAR(12)
   - identity-service: account_sequence, inviter_sequence
   - authorization-service: account_sequence
   - blockchain-service: account_sequence
   - referral-service: account_sequence
   - reward-service: account_sequence
   - backup-service: account_sequence

3. mpc-service 与 backup-service 集成:
   - mpc-service: 添加 BACKUP_SERVICE_URL, BACKUP_SERVICE_ENABLED, SERVICE_JWT_SECRET
   - backup-service: ALLOWED_SERVICES 添加 mpc-service

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
hailin 2025-12-12 12:29:11 -08:00
parent 4be9c1fb82
commit 75c49951b7
10 changed files with 430 additions and 424 deletions

View File

@ -1,14 +1,14 @@
-- Step 1: Add account_sequence columns to all tables first -- Step 1: Add account_sequence columns to all tables first
ALTER TABLE "authorization_roles" ADD COLUMN "account_sequence" BIGINT; ALTER TABLE "authorization_roles" ADD COLUMN "account_sequence" TEXT;
ALTER TABLE "monthly_assessments" ADD COLUMN "account_sequence" BIGINT; ALTER TABLE "monthly_assessments" ADD COLUMN "account_sequence" TEXT;
ALTER TABLE "monthly_bypasses" ADD COLUMN "account_sequence" BIGINT; ALTER TABLE "monthly_bypasses" ADD COLUMN "account_sequence" TEXT;
ALTER TABLE "stickman_rankings" ADD COLUMN "account_sequence" BIGINT; ALTER TABLE "stickman_rankings" ADD COLUMN "account_sequence" TEXT;
-- Step 2: Backfill account_sequence from existing user_id (which is still String at this point) -- Step 2: Backfill account_sequence from existing user_id (which is still String at this point)
UPDATE "authorization_roles" SET "account_sequence" = CAST("user_id" AS BIGINT) WHERE "account_sequence" IS NULL; UPDATE "authorization_roles" SET "account_sequence" = "user_id" WHERE "account_sequence" IS NULL;
UPDATE "monthly_assessments" SET "account_sequence" = CAST("user_id" AS BIGINT) WHERE "account_sequence" IS NULL; UPDATE "monthly_assessments" SET "account_sequence" = "user_id" WHERE "account_sequence" IS NULL;
UPDATE "monthly_bypasses" SET "account_sequence" = CAST("user_id" AS BIGINT) WHERE "account_sequence" IS NULL; UPDATE "monthly_bypasses" SET "account_sequence" = "user_id" WHERE "account_sequence" IS NULL;
UPDATE "stickman_rankings" SET "account_sequence" = CAST("user_id" AS BIGINT) WHERE "account_sequence" IS NULL; UPDATE "stickman_rankings" SET "account_sequence" = "user_id" WHERE "account_sequence" IS NULL;
-- Step 3: Make account_sequence NOT NULL -- Step 3: Make account_sequence NOT NULL
ALTER TABLE "authorization_roles" ALTER COLUMN "account_sequence" SET NOT NULL; ALTER TABLE "authorization_roles" ALTER COLUMN "account_sequence" SET NOT NULL;

View File

@ -25,7 +25,7 @@ services:
- DATABASE_URL=postgresql://rwa_user:rwa_secure_password@rwa-postgres:5432/rwa_backup?schema=public - DATABASE_URL=postgresql://rwa_user:rwa_secure_password@rwa-postgres:5432/rwa_backup?schema=public
# Service Authentication # Service Authentication
- SERVICE_JWT_SECRET=${SERVICE_JWT_SECRET:-your-service-jwt-secret} - SERVICE_JWT_SECRET=${SERVICE_JWT_SECRET:-your-service-jwt-secret}
- ALLOWED_SERVICES=identity-service,recovery-service - ALLOWED_SERVICES=identity-service,recovery-service,mpc-service
# Backup Encryption # Backup Encryption
- BACKUP_ENCRYPTION_KEY=${BACKUP_ENCRYPTION_KEY:-0123456789abcdef0123456789abcdef} - BACKUP_ENCRYPTION_KEY=${BACKUP_ENCRYPTION_KEY:-0123456789abcdef0123456789abcdef}
- BACKUP_ENCRYPTION_KEY_ID=${BACKUP_ENCRYPTION_KEY_ID:-key-v1} - BACKUP_ENCRYPTION_KEY_ID=${BACKUP_ENCRYPTION_KEY_ID:-key-v1}

View File

@ -2,7 +2,7 @@
CREATE TABLE "backup_shares" ( CREATE TABLE "backup_shares" (
"share_id" BIGSERIAL NOT NULL, "share_id" BIGSERIAL NOT NULL,
"user_id" BIGINT NOT NULL, "user_id" BIGINT NOT NULL,
"account_sequence" BIGINT NOT NULL, "account_sequence" VARCHAR(12) NOT NULL,
"public_key" VARCHAR(130) NOT NULL, "public_key" VARCHAR(130) NOT NULL,
"party_index" INTEGER NOT NULL DEFAULT 2, "party_index" INTEGER NOT NULL DEFAULT 2,
"threshold" INTEGER NOT NULL DEFAULT 2, "threshold" INTEGER NOT NULL DEFAULT 2,

View File

@ -14,7 +14,7 @@ model BackupShare {
// 用户标识 (来自 identity-service) // 用户标识 (来自 identity-service)
userId BigInt @unique @map("user_id") userId BigInt @unique @map("user_id")
accountSequence String @unique @map("account_sequence") // 格式: D + YYMMDD + 5位序号 accountSequence String @unique @map("account_sequence") @db.VarChar(12) // 格式: D + YYMMDD + 5位序号
// MPC 密钥信息 // MPC 密钥信息
publicKey String @unique @map("public_key") @db.VarChar(130) publicKey String @unique @map("public_key") @db.VarChar(130)

View File

@ -5,7 +5,7 @@
-- AlterTable: monitored_addresses -- AlterTable: monitored_addresses
-- Add new columns for system accounts and account_sequence -- Add new columns for system accounts and account_sequence
ALTER TABLE "monitored_addresses" ADD COLUMN "address_type" VARCHAR(20) NOT NULL DEFAULT 'USER'; ALTER TABLE "monitored_addresses" ADD COLUMN "address_type" VARCHAR(20) NOT NULL DEFAULT 'USER';
ALTER TABLE "monitored_addresses" ADD COLUMN "account_sequence" BIGINT; ALTER TABLE "monitored_addresses" ADD COLUMN "account_sequence" VARCHAR(20);
ALTER TABLE "monitored_addresses" ADD COLUMN "system_account_type" VARCHAR(50); ALTER TABLE "monitored_addresses" ADD COLUMN "system_account_type" VARCHAR(50);
ALTER TABLE "monitored_addresses" ADD COLUMN "system_account_id" BIGINT; ALTER TABLE "monitored_addresses" ADD COLUMN "system_account_id" BIGINT;
ALTER TABLE "monitored_addresses" ADD COLUMN "region_code" VARCHAR(10); ALTER TABLE "monitored_addresses" ADD COLUMN "region_code" VARCHAR(10);
@ -16,7 +16,7 @@ ALTER TABLE "monitored_addresses" ALTER COLUMN "user_id" DROP NOT NULL;
-- AlterTable: deposit_transactions -- AlterTable: deposit_transactions
-- Add new columns for system accounts and account_sequence -- Add new columns for system accounts and account_sequence
ALTER TABLE "deposit_transactions" ADD COLUMN "address_type" VARCHAR(20) NOT NULL DEFAULT 'USER'; ALTER TABLE "deposit_transactions" ADD COLUMN "address_type" VARCHAR(20) NOT NULL DEFAULT 'USER';
ALTER TABLE "deposit_transactions" ADD COLUMN "account_sequence" BIGINT; ALTER TABLE "deposit_transactions" ADD COLUMN "account_sequence" VARCHAR(20);
ALTER TABLE "deposit_transactions" ADD COLUMN "system_account_type" VARCHAR(50); ALTER TABLE "deposit_transactions" ADD COLUMN "system_account_type" VARCHAR(50);
ALTER TABLE "deposit_transactions" ADD COLUMN "system_account_id" BIGINT; ALTER TABLE "deposit_transactions" ADD COLUMN "system_account_id" BIGINT;
@ -26,7 +26,7 @@ ALTER TABLE "deposit_transactions" ALTER COLUMN "user_id" DROP NOT NULL;
-- CreateTable: recovery_mnemonics -- CreateTable: recovery_mnemonics
CREATE TABLE "recovery_mnemonics" ( CREATE TABLE "recovery_mnemonics" (
"id" BIGSERIAL NOT NULL, "id" BIGSERIAL NOT NULL,
"account_sequence" INTEGER NOT NULL, "account_sequence" VARCHAR(20) NOT NULL,
"public_key" VARCHAR(130) NOT NULL, "public_key" VARCHAR(130) NOT NULL,
"encrypted_mnemonic" TEXT NOT NULL, "encrypted_mnemonic" TEXT NOT NULL,
"mnemonic_hash" VARCHAR(64) NOT NULL, "mnemonic_hash" VARCHAR(64) NOT NULL,

View File

@ -1,11 +1,11 @@
-- CreateTable -- CreateTable
CREATE TABLE "user_accounts" ( CREATE TABLE "user_accounts" (
"user_id" BIGSERIAL NOT NULL, "user_id" BIGSERIAL NOT NULL,
"account_sequence" BIGINT NOT NULL, "account_sequence" VARCHAR(12) NOT NULL,
"phone_number" VARCHAR(20), "phone_number" VARCHAR(20),
"nickname" VARCHAR(100) NOT NULL, "nickname" VARCHAR(100) NOT NULL,
"avatar_url" TEXT, "avatar_url" TEXT,
"inviter_sequence" BIGINT, "inviter_sequence" VARCHAR(12),
"referral_code" VARCHAR(10) NOT NULL, "referral_code" VARCHAR(10) NOT NULL,
"kyc_status" VARCHAR(20) NOT NULL DEFAULT 'NOT_VERIFIED', "kyc_status" VARCHAR(20) NOT NULL DEFAULT 'NOT_VERIFIED',
"real_name" VARCHAR(100), "real_name" VARCHAR(100),
@ -61,13 +61,17 @@ CREATE TABLE "wallet_addresses" (
-- CreateTable -- CreateTable
CREATE TABLE "account_sequence_generator" ( CREATE TABLE "account_sequence_generator" (
"id" INTEGER NOT NULL DEFAULT 1, "id" SERIAL NOT NULL,
"current_sequence" BIGINT NOT NULL DEFAULT 0, "date_key" VARCHAR(6) NOT NULL,
"current_sequence" INTEGER NOT NULL DEFAULT 0,
"updated_at" TIMESTAMP(3) NOT NULL, "updated_at" TIMESTAMP(3) NOT NULL,
CONSTRAINT "account_sequence_generator_pkey" PRIMARY KEY ("id") CONSTRAINT "account_sequence_generator_pkey" PRIMARY KEY ("id")
); );
-- CreateIndex: account_sequence_generator unique constraint
CREATE UNIQUE INDEX "account_sequence_generator_date_key_key" ON "account_sequence_generator"("date_key");
-- CreateTable -- CreateTable
CREATE TABLE "user_events" ( CREATE TABLE "user_events" (
"event_id" BIGSERIAL NOT NULL, "event_id" BIGSERIAL NOT NULL,
@ -346,7 +350,3 @@ ALTER TABLE "user_devices" ADD CONSTRAINT "user_devices_user_id_fkey" FOREIGN KE
-- AddForeignKey -- AddForeignKey
ALTER TABLE "wallet_addresses" ADD CONSTRAINT "wallet_addresses_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "user_accounts"("user_id") ON DELETE CASCADE ON UPDATE CASCADE; ALTER TABLE "wallet_addresses" ADD CONSTRAINT "wallet_addresses_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "user_accounts"("user_id") ON DELETE CASCADE ON UPDATE CASCADE;
-- Initialize sequence generator
INSERT INTO "account_sequence_generator" ("id", "current_sequence", "updated_at")
VALUES (1, 0, CURRENT_TIMESTAMP)
ON CONFLICT ("id") DO NOTHING;

View File

@ -46,6 +46,10 @@ services:
MPC_COORDINATOR_TIMEOUT: 30000 MPC_COORDINATOR_TIMEOUT: 30000
# Share Encryption # Share Encryption
SHARE_MASTER_KEY: ${SHARE_MASTER_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef} SHARE_MASTER_KEY: ${SHARE_MASTER_KEY:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}
# Backup Service
BACKUP_SERVICE_URL: ${BACKUP_SERVICE_URL:-http://rwa-backup-service:3002}
BACKUP_SERVICE_ENABLED: ${BACKUP_SERVICE_ENABLED:-true}
SERVICE_JWT_SECRET: ${SERVICE_JWT_SECRET:-your-service-jwt-secret-change-in-production}
# Timeouts # Timeouts
MPC_KEYGEN_TIMEOUT: 300000 MPC_KEYGEN_TIMEOUT: 300000
MPC_SIGNING_TIMEOUT: 180000 MPC_SIGNING_TIMEOUT: 180000

View File

@ -2,7 +2,7 @@
CREATE TABLE "referral_relationships" ( CREATE TABLE "referral_relationships" (
"relationship_id" BIGSERIAL NOT NULL, "relationship_id" BIGSERIAL NOT NULL,
"user_id" BIGINT NOT NULL, "user_id" BIGINT NOT NULL,
"account_sequence" INTEGER NOT NULL, "account_sequence" VARCHAR(12) NOT NULL,
"referrer_id" BIGINT, "referrer_id" BIGINT,
"root_user_id" BIGINT, "root_user_id" BIGINT,
"my_referral_code" VARCHAR(20) NOT NULL, "my_referral_code" VARCHAR(20) NOT NULL,
@ -48,7 +48,7 @@ CREATE TABLE "direct_referrals" (
"direct_referral_id" BIGSERIAL NOT NULL, "direct_referral_id" BIGSERIAL NOT NULL,
"referrer_id" BIGINT NOT NULL, "referrer_id" BIGINT NOT NULL,
"referral_id" BIGINT NOT NULL, "referral_id" BIGINT NOT NULL,
"referral_sequence" BIGINT NOT NULL, "referral_sequence" VARCHAR(12) NOT NULL,
"referral_nickname" VARCHAR(100), "referral_nickname" VARCHAR(100),
"referral_avatar" VARCHAR(255), "referral_avatar" VARCHAR(255),
"personal_planting_count" INTEGER NOT NULL DEFAULT 0, "personal_planting_count" INTEGER NOT NULL DEFAULT 0,

View File

@ -64,15 +64,17 @@ export class UserRegisteredHandler implements OnModuleInit {
`Processing ${event.eventType} event: accountSequence=${payload.accountSequence}, inviterSequence=${payload.inviterSequence}`, `Processing ${event.eventType} event: accountSequence=${payload.accountSequence}, inviterSequence=${payload.inviterSequence}`,
); );
// 使用 accountSequence 作为 userId因为 identity-service 的 userId 是内部自增ID // 从 accountSequence 提取数值部分作为 userId
// 在事件发布时可能还是临时值 0而 accountSequence 是全局唯一的业务标识 // accountSequence 格式: D + YYMMDD + 5位序号 (例如: D25121200000)
// 注意userId 仍然需要是 bigint这里我们需要从 accountSequence 字符串中提取数值部分或使用其他方式 // 去掉 "D" 前缀后得到 11 位数字,作为全局唯一的 userId
// 暂时保持原有逻辑,但 accountSequence 本身现在是字符串类型 // 这样可以避免依赖 identity-service 的临时 userId (可能是 0)
const userIdFromSequence = BigInt(payload.accountSequence.substring(1)); // 去掉 "D" 前缀
const command = new CreateReferralRelationshipCommand( const command = new CreateReferralRelationshipCommand(
BigInt(payload.userId), // 使用 userId userIdFromSequence, // 使用从 accountSequence 提取的数值作为 userId
payload.accountSequence, // 现在是字符串格式 payload.accountSequence, // 完整的 accountSequence 字符串
null, // referrerCode - 不通过推荐码查找 null, // referrerCode - 不通过推荐码查找
payload.inviterSequence, // 通过 accountSequence 查找推荐人,现在是字符串格式 payload.inviterSequence, // 通过 accountSequence 查找推荐人
); );
const result = await this.referralService.createReferralRelationship(command); const result = await this.referralService.createReferralRelationship(command);

View File

@ -1,19 +1,19 @@
-- Add account_sequence column to reward_ledger_entries -- Add account_sequence column to reward_ledger_entries
ALTER TABLE "reward_ledger_entries" ADD COLUMN "account_sequence" BIGINT; ALTER TABLE "reward_ledger_entries" ADD COLUMN "account_sequence" VARCHAR(20);
-- Add indexes for account_sequence on reward_ledger_entries -- Add indexes for account_sequence on reward_ledger_entries
CREATE INDEX "idx_account_status" ON "reward_ledger_entries"("account_sequence", "reward_status"); CREATE INDEX "idx_account_status" ON "reward_ledger_entries"("account_sequence", "reward_status");
CREATE INDEX "idx_account_created" ON "reward_ledger_entries"("account_sequence", "created_at" DESC); CREATE INDEX "idx_account_created" ON "reward_ledger_entries"("account_sequence", "created_at" DESC);
-- Add account_sequence column to reward_summaries -- Add account_sequence column to reward_summaries
ALTER TABLE "reward_summaries" ADD COLUMN "account_sequence" BIGINT; ALTER TABLE "reward_summaries" ADD COLUMN "account_sequence" VARCHAR(20);
-- Add unique constraint and index for account_sequence on reward_summaries -- Add unique constraint and index for account_sequence on reward_summaries
CREATE UNIQUE INDEX "reward_summaries_account_sequence_key" ON "reward_summaries"("account_sequence"); CREATE UNIQUE INDEX "reward_summaries_account_sequence_key" ON "reward_summaries"("account_sequence");
CREATE INDEX "idx_summary_account" ON "reward_summaries"("account_sequence"); CREATE INDEX "idx_summary_account" ON "reward_summaries"("account_sequence");
-- Add account_sequence column to settlement_records -- Add account_sequence column to settlement_records
ALTER TABLE "settlement_records" ADD COLUMN "account_sequence" BIGINT; ALTER TABLE "settlement_records" ADD COLUMN "account_sequence" VARCHAR(20);
-- Add index for account_sequence on settlement_records -- Add index for account_sequence on settlement_records
CREATE INDEX "idx_settlement_account" ON "settlement_records"("account_sequence"); CREATE INDEX "idx_settlement_account" ON "settlement_records"("account_sequence");