fix(auth-service): 允许synced_legacy_users的phone和password_hash为空

- 修改schema让phone和passwordHash字段可为空
- 添加migration: 20260111083500_allow_nullable_phone_password
- CDC consumer使用null替代空字符串
- 支持同步没有手机号/密码的系统账户

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
hailin 2026-01-11 08:37:02 -08:00
parent 6caae7c860
commit 849fa77df0
21 changed files with 129 additions and 19 deletions

View File

@ -701,7 +701,10 @@
"Bash(ssh ceshi@103.39.231.231 \"docker ps | grep -i kong\")", "Bash(ssh ceshi@103.39.231.231 \"docker ps | grep -i kong\")",
"Bash(ssh ceshi@103.39.231.231 \"curl -s http://localhost:8000/api/v2/mining-admin/auth/login -X POST -H ''Content-Type: application/json'' -d ''{\"\"username\"\":\"\"admin\"\",\"\"password\"\":\"\"admin123\"\"}''\")", "Bash(ssh ceshi@103.39.231.231 \"curl -s http://localhost:8000/api/v2/mining-admin/auth/login -X POST -H ''Content-Type: application/json'' -d ''{\"\"username\"\":\"\"admin\"\",\"\"password\"\":\"\"admin123\"\"}''\")",
"Bash(ssh ceshi@103.39.231.231 \"curl -s http://localhost:8000/api/v2/mining-admin/auth/profile -H ''Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3ODRlNTA0MS1hYTM2LTQ0ZTctYTM1NS0yY2I2ZjYwYmY1YmIiLCJ1c2VybmFtZSI6ImFkbWluIiwicm9sZSI6IlNVUEVSX0FETUlOIiwiaWF0IjoxNzY4MTIyMjc3LCJleHAiOjE3NjgyMDg2Nzd9.XL0i0_tQlybkT9ktLIP90WQZDujPbbARL20h6fLmeRE''\")", "Bash(ssh ceshi@103.39.231.231 \"curl -s http://localhost:8000/api/v2/mining-admin/auth/profile -H ''Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3ODRlNTA0MS1hYTM2LTQ0ZTctYTM1NS0yY2I2ZjYwYmY1YmIiLCJ1c2VybmFtZSI6ImFkbWluIiwicm9sZSI6IlNVUEVSX0FETUlOIiwiaWF0IjoxNzY4MTIyMjc3LCJleHAiOjE3NjgyMDg2Nzd9.XL0i0_tQlybkT9ktLIP90WQZDujPbbARL20h6fLmeRE''\")",
"Bash(user \")" "Bash(user \")",
"mcp__UIPro__getCodeFromUIProPlugin",
"Bash(flutter create:*)",
"Bash(DATABASE_URL=\"postgresql://postgres:postgres@localhost:5432/rwa_auth?schema=public\" npx prisma migrate dev:*)"
], ],
"deny": [], "deny": [],
"ask": [] "ask": []

View File

@ -0,0 +1,3 @@
-- AlterTable: 允许 phone 和 password_hash 为空(支持系统账户同步)
ALTER TABLE "synced_legacy_users" ALTER COLUMN "phone" DROP NOT NULL;
ALTER TABLE "synced_legacy_users" ALTER COLUMN "password_hash" DROP NOT NULL;

View File

@ -84,8 +84,8 @@ model SyncedLegacyUser {
// 1.0 用户数据 // 1.0 用户数据
legacyId BigInt @unique @map("legacy_id") // 1.0 的 user.id legacyId BigInt @unique @map("legacy_id") // 1.0 的 user.id
accountSequence String @unique @map("account_sequence") accountSequence String @unique @map("account_sequence")
phone String phone String? // 系统账户可能没有手机号
passwordHash String @map("password_hash") passwordHash String? @map("password_hash") // 系统账户可能没有密码
status String status String
legacyCreatedAt DateTime @map("legacy_created_at") legacyCreatedAt DateTime @map("legacy_created_at")

View File

@ -124,24 +124,12 @@ export class LegacyUserCdcConsumer implements OnModuleInit, OnModuleDestroy {
} }
private async upsertLegacyUser(user: UnwrappedCdcUser, sequenceNum: bigint) { private async upsertLegacyUser(user: UnwrappedCdcUser, sequenceNum: bigint) {
// 跳过没有手机号的系统账户user_id 1-5 通常是系统/测试账户)
if (!user.phone_number) {
this.logger.debug(`Skipped user ${user.user_id} (no phone number)`);
return;
}
// 跳过没有密码的账户
if (!user.password_hash) {
this.logger.debug(`Skipped user ${user.user_id} (no password)`);
return;
}
try { try {
await this.prisma.syncedLegacyUser.upsert({ await this.prisma.syncedLegacyUser.upsert({
where: { legacyId: BigInt(user.user_id) }, where: { legacyId: BigInt(user.user_id) },
update: { update: {
phone: user.phone_number, phone: user.phone_number || null,
passwordHash: user.password_hash, passwordHash: user.password_hash || null,
accountSequence: user.account_sequence, accountSequence: user.account_sequence,
status: user.status, status: user.status,
sourceSequenceNum: sequenceNum, sourceSequenceNum: sequenceNum,
@ -149,8 +137,8 @@ export class LegacyUserCdcConsumer implements OnModuleInit, OnModuleDestroy {
}, },
create: { create: {
legacyId: BigInt(user.user_id), legacyId: BigInt(user.user_id),
phone: user.phone_number, phone: user.phone_number || null,
passwordHash: user.password_hash, passwordHash: user.password_hash || null,
accountSequence: user.account_sequence, accountSequence: user.account_sequence,
status: user.status, status: user.status,
legacyCreatedAt: new Date(user.registered_at), legacyCreatedAt: new Date(user.registered_at),

Binary file not shown.

After

Width:  |  Height:  |  Size: 536 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 210 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 344 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 390 B

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="40dp"
android:height="40dp"
android:viewportWidth="40"
android:viewportHeight="40">
<path
android:fillColor="#FFF3F4F6"
android:pathData="M0 19.59c0-10.82 8.77-19.59 19.59-19.59h-0.01c10.82 0 19.59 8.77 19.59 19.59v0.82c0 10.82-8.77 19.59-19.59 19.59"/>
<path
android:fillColor="#FFFF6B00"
android:pathData="M24.41 14.84l1.46 1.46-4.88 4.87-3.28-3.28c-0.38-0.42-1.03-0.42-1.4 0l-6 6c-0.43 0.38-0.43 1.03 0 1.4 0.37 0.38 1.03 0.38 1.4 0l5.3-5.29 3.28 3.28c0.37 0.42 1.03 0.42 1.4 0l5.58-5.58 1.46 1.46c0.32 0.28 0.84 0.09 0.84-0.38v-4.26c0-0.29-0.19-0.52-0.47-0.52H24.8c-0.42 0-0.66 0.56-0.38 0.84Z"/>
</vector>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF1F2937"
android:pathData="M21 12.23C21 6.75 16.73 3 12 3c-4.69 0-9 3.66-9 9.28-0.6 0.33-0.98 0.99-0.98 1.74v1.96C2.02 17.11 2.9 18 3.98 18c0.57 0 1.04-0.47 1.04-0.98v-4.83c0-3.85 2.95-7.17 6.75-7.27 3.98-0.14 7.21 3.05 7.21 6.99v7.07H12c-0.56 0-0.98 0.47-0.98 1.04 0 0.51 0.42 0.98 0.98 0.98h6.98c1.13 0 2.02-0.9 2.02-2.02v-1.21c0.6-0.29 0.98-0.9 0.98-1.64v-2.3c0-0.7-0.37-1.31-0.98-1.6ZM8.02 12.98C8.02 12.47 8.44 12 9 12s0.98 0.47 0.98 0.98c0 0.57-0.42 1.04-0.98 1.04s-0.98-0.47-0.98-1.04Zm6 0c0-0.51 0.42-0.98 0.98-0.98s0.98 0.47 0.98 0.98c0 0.57-0.42 1.04-0.98 1.04s-0.98-0.47-0.98-1.04ZM18 11.02C17.53 8.2 15.05 6 12.05 6 9 6 5.77 8.53 6 12.47c2.48-1.03 4.36-3.24 4.88-5.9 1.3 2.62 3.98 4.45 7.12 4.45Z"/>
</vector>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="18dp"
android:height="28dp"
android:viewportWidth="18"
android:viewportHeight="28">
<path
android:fillColor="#FFD1D5DB"
android:pathData="M9 7.99c-3.76 0-6.96 2.35-8.26 5.62 1.3 3.3 4.5 5.63 8.26 5.63s6.96-2.32 8.26-5.63C15.96 10.34 12.76 8 9 8Zm0 9.38c-2.07 0-3.76-1.68-3.76-3.76C5.24 11.54 6.93 9.9 9 9.9s3.76 1.65 3.76 3.72c0 2.08-1.69 3.77-3.76 3.77Zm0-6c-1.23 0-2.25 1.01-2.25 2.24 0 1.27 1.02 2.25 2.25 2.25s2.25-0.98 2.25-2.25c0-1.23-1.02-2.25-2.25-2.25Z"/>
</vector>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="14dp"
android:height="20dp"
android:viewportWidth="14"
android:viewportHeight="20">
<path
android:fillColor="#FFFF6B00"
android:pathData="M7 4.18c-3.23 0-5.82 2.6-5.82 5.82 0 3.23 2.6 5.82 5.82 5.82 3.23 0 5.82-2.6 5.82-5.82 0-3.23-2.6-5.82-5.82-5.82Zm0 8.75c-0.33 0-0.57-0.28-0.57-0.6V10c0-0.33 0.24-0.57 0.57-0.57 0.33 0 0.57 0.24 0.57 0.57v2.32c0 0.33-0.24 0.6-0.57 0.6Zm0.57-4.68H6.43V7.07h1.14v1.18Z"/>
</vector>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="14dp"
android:height="20dp"
android:viewportWidth="14"
android:viewportHeight="20">
<path
android:fillColor="#FFFF6B00"
android:pathData="M5.41 6.91c-0.21 0.22-0.21 0.6 0 0.82L7.68 10l-2.27 2.27c-0.21 0.22-0.21 0.6 0 0.82 0.25 0.22 0.6 0.22 0.82 0l2.68-2.68c0.25-0.22 0.25-0.6 0-0.82L6.23 6.91c-0.21-0.22-0.57-0.22-0.82 0Z"/>
</vector>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFF6B00"
android:pathData="M18.98 5.02h-1.96V3.98c0-0.51-0.47-0.98-1.04-0.98H8.02C7.45 3 6.98 3.47 6.98 3.98v1.04H5.02C3.89 5.02 3 5.9 3 6.98v1.04c0 2.53 1.92 4.59 4.4 4.92 0.62 1.5 1.97 2.62 3.62 2.95V19h-3c-0.57 0-1.04 0.46-1.04 1.03 0 0.51 0.47 0.98 1.04 0.98h7.96c0.57 0 1.04-0.47 1.04-0.98 0-0.57-0.47-1.04-1.04-1.04h-3V15.9c1.64-0.33 3-1.45 3.61-2.95C19.08 12.6 21 10.54 21 8.02V6.98c0-1.07-0.9-1.96-2.02-1.96Zm-13.96 3V6.98h1.96v3.85C5.86 10.4 5.02 9.28 5.02 8.02Zm13.96 0c0 1.26-0.84 2.39-1.96 2.8V6.99h1.96v1.04Z"/>
</vector>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF9CA3AF"
android:pathData="M6.14 11.86l-2.76 2.81c-0.2 0.19-0.2 0.47 0 0.7l2.76 2.77c0.33 0.33 0.84 0.1 0.84-0.33v-1.83h6c0.57 0 1.04-0.42 1.04-0.98s-0.47-0.98-1.04-0.98h-6v-1.83c0-0.42-0.51-0.66-0.84-0.33Zm14.53-3.19l-2.81-2.81c-0.28-0.33-0.84-0.1-0.84 0.33v1.83h-6c-0.57 0-1.04 0.42-1.04 0.98s0.47 0.98 1.04 0.98h6v1.83c0 0.42 0.51 0.66 0.84 0.33l2.77-2.81c0.23-0.19 0.23-0.47 0.04-0.66Z"/>
</vector>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF9CA3AF"
android:pathData="M9.98 15.98V8.02C9.98 6.89 10.88 6 12 6h9V5.02C21 3.89 20.1 3 18.98 3H5.02C3.89 3 3 3.9 3 5.02v13.96C3 20.11 3.9 21 5.02 21h13.96c1.13 0 2.02-0.9 2.02-2.02V18h-9c-1.13 0-2.02-0.9-2.02-2.02Zm3-7.96C12.47 8.02 12 8.44 12 9v6c0 0.56 0.47 0.98 0.98 0.98h9V8.02h-9Zm3 5.48c-0.8 0-1.5-0.66-1.5-1.5s0.7-1.5 1.5-1.5c0.85 0 1.5 0.66 1.5 1.5s-0.65 1.5-1.5 1.5Z"/>
</vector>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF9CA3AF"
android:pathData="M12 12c2.2 0 3.98-1.78 3.98-3.98S14.2 3.98 12 3.98 8.02 5.81 8.02 8.02C8.02 10.22 9.8 12 12 12Zm0 2.02c-2.67 0-8.02 1.3-8.02 3.98v0.98c0 0.57 0.47 1.04 1.04 1.04h13.96c0.57 0 1.04-0.47 1.04-1.04V18c0-2.67-5.35-3.98-8.02-3.98Z"/>
</vector>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFF6B00"
android:pathData="M8.02 2.02C6.89 2.02 6 2.9 6 3.98v3.2c0 0.5 0.23 1.02 0.6 1.4L9.99 12l-3.37 3.42C6.23 15.8 6 16.32 6 16.82v3.2c0 1.07 0.9 1.96 2.02 1.96h7.96c1.13 0 2.02-0.89 2.02-1.96v-3.2c0-0.5-0.19-1.02-0.56-1.4L14.02 12l3.37-3.42C17.81 8.2 18 7.68 18 7.18v-3.2c0-1.07-0.9-1.96-2.02-1.96H8.02Zm7.96 14.9v2.06c0 0.57-0.42 1.04-0.98 1.04H9c-0.56 0-0.98-0.47-0.98-1.04v-2.06c0-0.28 0.09-0.51 0.28-0.7l3.7-3.7 3.7 3.7c0.2 0.19 0.28 0.42 0.28 0.7Z"/>
</vector>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp"
android:height="32dp"
android:viewportWidth="32"
android:viewportHeight="32">
<path
android:fillColor="#1AFF8C00"
android:pathData="M0 16c0-8.84 7.16-16 16-16h0c8.84 0 16 7.16 16 16v0c0 8.84-7.16 16-16 16h0c-8.84 0-16-7.16-16-16z"/>
<path
android:fillColor="#FFFF6B00"
android:pathData="M11.04 12.72c-2.27 2.26-2.27 5.94 0 8.24 1.21-2.85 3.4-5.23 6.13-6.64-2.3 1.95-3.94 4.69-4.49 7.77 2.15 1.02 4.8 0.67 6.6-1.13 2.5-2.5 3.2-9.3 3.36-11.17 0-0.24-0.2-0.43-0.43-0.43-1.87 0.16-8.67 0.86-11.17 3.36Z"/>
</vector>