fix(identity-service): 添加注册流程详细日志和保存验证
问题:用户注册后 referral-service 有数据但 identity-service 没有 原因:save() 方法和 registerByPhone 方法缺少日志,无法追踪问题 修复: - save() 方法添加完整日志和 try-catch - registerByPhone 方法添加每个步骤的日志 - 添加关键验证:保存后检查 userId 是否为 0 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
45fcae5ef5
commit
1f15c494c1
|
|
@ -221,20 +221,32 @@ export class UserApplicationService {
|
|||
): Promise<AutoCreateAccountResult> {
|
||||
const phoneNumber = PhoneNumber.create(command.phoneNumber);
|
||||
|
||||
this.logger.log(
|
||||
`[REGISTER] Starting phone registration: phone=${phoneNumber.value}, deviceId=${command.deviceId}`,
|
||||
);
|
||||
|
||||
// 1. 验证短信验证码
|
||||
const cachedCode = await this.redisService.get(
|
||||
`sms:register:${phoneNumber.value}`,
|
||||
);
|
||||
if (cachedCode !== command.smsCode) {
|
||||
this.logger.warn(
|
||||
`[REGISTER] SMS code mismatch: phone=${phoneNumber.value}`,
|
||||
);
|
||||
throw new ApplicationError('验证码错误或已过期');
|
||||
}
|
||||
this.logger.log(`[REGISTER] SMS code verified`);
|
||||
|
||||
// 2. 检查手机号是否已注册
|
||||
const phoneValidation =
|
||||
await this.validatorService.validatePhoneNumber(phoneNumber);
|
||||
if (!phoneValidation.isValid) {
|
||||
this.logger.warn(
|
||||
`[REGISTER] Phone validation failed: ${phoneValidation.errorMessage}`,
|
||||
);
|
||||
throw new ApplicationError(phoneValidation.errorMessage!);
|
||||
}
|
||||
this.logger.log(`[REGISTER] Phone number validated`);
|
||||
|
||||
// 3. 验证邀请码
|
||||
let inviterSequence: AccountSequence | null = null;
|
||||
|
|
@ -243,16 +255,25 @@ export class UserApplicationService {
|
|||
const referralValidation =
|
||||
await this.validatorService.validateReferralCode(referralCode);
|
||||
if (!referralValidation.isValid) {
|
||||
this.logger.warn(
|
||||
`[REGISTER] Referral code invalid: ${command.inviterReferralCode}`,
|
||||
);
|
||||
throw new ApplicationError(referralValidation.errorMessage!);
|
||||
}
|
||||
const inviter =
|
||||
await this.userRepository.findByReferralCode(referralCode);
|
||||
inviterSequence = inviter!.accountSequence;
|
||||
this.logger.log(
|
||||
`[REGISTER] Inviter validated: ${inviterSequence.value}`,
|
||||
);
|
||||
}
|
||||
|
||||
// 4. 生成用户序列号
|
||||
const accountSequence =
|
||||
await this.sequenceGenerator.generateNextUserSequence();
|
||||
this.logger.log(
|
||||
`[REGISTER] Generated sequence: ${accountSequence.value}`,
|
||||
);
|
||||
|
||||
// 5. 生成用户名和头像
|
||||
const identity = generateIdentity(accountSequence.value);
|
||||
|
|
@ -277,6 +298,9 @@ export class UserApplicationService {
|
|||
deviceInfo: command.deviceName,
|
||||
inviterSequence,
|
||||
});
|
||||
this.logger.log(
|
||||
`[REGISTER] Account aggregate created (not saved yet): sequence=${accountSequence.value}`,
|
||||
);
|
||||
|
||||
// 8. 设置随机用户名和头像
|
||||
account.updateProfile({
|
||||
|
|
@ -285,15 +309,29 @@ export class UserApplicationService {
|
|||
});
|
||||
|
||||
// 9. 保存账户
|
||||
this.logger.log(`[REGISTER] Saving account to database...`);
|
||||
await this.userRepository.save(account);
|
||||
this.logger.log(
|
||||
`[REGISTER] Account saved: userId=${account.userId.value}, sequence=${account.accountSequence.value}`,
|
||||
);
|
||||
|
||||
// 9.1 验证保存成功
|
||||
if (account.userId.value === BigInt(0)) {
|
||||
this.logger.error(
|
||||
`[REGISTER] CRITICAL: userId is still 0 after save! sequence=${accountSequence.value}`,
|
||||
);
|
||||
throw new ApplicationError('账户保存失败:未获取到用户ID');
|
||||
}
|
||||
|
||||
// 10. 设置密码
|
||||
this.logger.log(`[REGISTER] Setting password hash...`);
|
||||
const bcrypt = await import('bcrypt');
|
||||
const passwordHash = await bcrypt.hash(command.password, 10);
|
||||
await this.prisma.userAccount.update({
|
||||
where: { userId: account.userId.value },
|
||||
data: { passwordHash },
|
||||
});
|
||||
this.logger.log(`[REGISTER] Password hash set`);
|
||||
|
||||
// 11. 删除验证码
|
||||
await this.redisService.delete(`sms:register:${phoneNumber.value}`);
|
||||
|
|
@ -304,10 +342,15 @@ export class UserApplicationService {
|
|||
accountSequence: account.accountSequence.value,
|
||||
deviceId: command.deviceId,
|
||||
});
|
||||
this.logger.log(`[REGISTER] Tokens generated`);
|
||||
|
||||
// 13. 发布领域事件
|
||||
this.logger.log(
|
||||
`[REGISTER] Publishing ${account.domainEvents.length} domain events...`,
|
||||
);
|
||||
await this.eventPublisher.publishAll(account.domainEvents);
|
||||
account.clearDomainEvents();
|
||||
this.logger.log(`[REGISTER] Domain events published`);
|
||||
|
||||
// 14. 发布 MPC Keygen 请求事件 (触发后台生成钱包)
|
||||
const sessionId = crypto.randomUUID();
|
||||
|
|
@ -324,7 +367,7 @@ export class UserApplicationService {
|
|||
);
|
||||
|
||||
this.logger.log(
|
||||
`Account registered by phone: sequence=${accountSequence.value}, phone=${phoneNumber.value}, MPC keygen requested`,
|
||||
`[REGISTER] COMPLETE: sequence=${accountSequence.value}, phone=${phoneNumber.value}, userId=${account.userId.value}`,
|
||||
);
|
||||
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { PrismaService } from '@/infrastructure/persistence/prisma/prisma.service';
|
||||
import {
|
||||
UserAccountRepository,
|
||||
|
|
@ -27,87 +27,124 @@ import {
|
|||
|
||||
@Injectable()
|
||||
export class UserAccountRepositoryImpl implements UserAccountRepository {
|
||||
private readonly logger = new Logger(UserAccountRepositoryImpl.name);
|
||||
|
||||
constructor(private readonly prisma: PrismaService) {}
|
||||
|
||||
async save(account: UserAccount): Promise<void> {
|
||||
const devices = account.getAllDevices();
|
||||
const isNewAccount = account.userId.value === BigInt(0);
|
||||
|
||||
await this.prisma.$transaction(async (tx) => {
|
||||
let savedUserId: bigint;
|
||||
this.logger.log(
|
||||
`[SAVE] Starting save: sequence=${account.accountSequence.value}, isNew=${isNewAccount}, phone=${account.phoneNumber?.value || 'null'}`,
|
||||
);
|
||||
|
||||
if (isNewAccount) {
|
||||
// 新账户,让数据库自动生成userId
|
||||
const created = await tx.userAccount.create({
|
||||
data: {
|
||||
accountSequence: account.accountSequence.value,
|
||||
phoneNumber: account.phoneNumber?.value || null,
|
||||
nickname: account.nickname,
|
||||
avatarUrl: account.avatarUrl,
|
||||
inviterSequence: account.inviterSequence?.value || null,
|
||||
referralCode: account.referralCode.value,
|
||||
kycStatus: account.kycStatus,
|
||||
realName: account.kycInfo?.realName || null,
|
||||
idCardNumber: account.kycInfo?.idCardNumber || null,
|
||||
idCardFrontUrl: account.kycInfo?.idCardFrontUrl || null,
|
||||
idCardBackUrl: account.kycInfo?.idCardBackUrl || null,
|
||||
status: account.status,
|
||||
registeredAt: account.registeredAt,
|
||||
lastLoginAt: account.lastLoginAt,
|
||||
},
|
||||
});
|
||||
savedUserId = created.userId;
|
||||
// 更新聚合根的userId
|
||||
(account as any)._userId = UserId.create(savedUserId);
|
||||
} else {
|
||||
// 已存在的账户,更新
|
||||
await tx.userAccount.update({
|
||||
where: { userId: BigInt(account.userId.value) },
|
||||
data: {
|
||||
phoneNumber: account.phoneNumber?.value || null,
|
||||
nickname: account.nickname,
|
||||
avatarUrl: account.avatarUrl,
|
||||
kycStatus: account.kycStatus,
|
||||
realName: account.kycInfo?.realName || null,
|
||||
idCardNumber: account.kycInfo?.idCardNumber || null,
|
||||
idCardFrontUrl: account.kycInfo?.idCardFrontUrl || null,
|
||||
idCardBackUrl: account.kycInfo?.idCardBackUrl || null,
|
||||
status: account.status,
|
||||
lastLoginAt: account.lastLoginAt,
|
||||
},
|
||||
});
|
||||
savedUserId = account.userId.value;
|
||||
}
|
||||
try {
|
||||
await this.prisma.$transaction(async (tx) => {
|
||||
let savedUserId: bigint;
|
||||
|
||||
// Sync devices
|
||||
await tx.userDevice.deleteMany({ where: { userId: savedUserId } });
|
||||
if (devices.length > 0) {
|
||||
await tx.userDevice.createMany({
|
||||
data: devices.map((d) => {
|
||||
// 从 deviceInfo JSON 中提取冗余字段便于查询
|
||||
const info = d.deviceInfo || {};
|
||||
return {
|
||||
userId: savedUserId,
|
||||
deviceId: d.deviceId,
|
||||
deviceName: d.deviceName,
|
||||
deviceInfo: d.deviceInfo
|
||||
? JSON.parse(JSON.stringify(d.deviceInfo))
|
||||
: null, // 100% 保存完整 JSON
|
||||
platform: (info as any).platform || null,
|
||||
deviceModel: (info as any).model || null,
|
||||
osVersion: (info as any).osVersion || null,
|
||||
appVersion: (info as any).appVersion || null,
|
||||
screenWidth: (info as any).screenWidth || null,
|
||||
screenHeight: (info as any).screenHeight || null,
|
||||
locale: (info as any).locale || null,
|
||||
timezone: (info as any).timezone || null,
|
||||
addedAt: d.addedAt,
|
||||
lastActiveAt: d.lastActiveAt,
|
||||
};
|
||||
}),
|
||||
});
|
||||
}
|
||||
});
|
||||
if (isNewAccount) {
|
||||
// 新账户,让数据库自动生成userId
|
||||
this.logger.log(`[SAVE] Creating new account in transaction...`);
|
||||
|
||||
const created = await tx.userAccount.create({
|
||||
data: {
|
||||
accountSequence: account.accountSequence.value,
|
||||
phoneNumber: account.phoneNumber?.value || null,
|
||||
nickname: account.nickname,
|
||||
avatarUrl: account.avatarUrl,
|
||||
inviterSequence: account.inviterSequence?.value || null,
|
||||
referralCode: account.referralCode.value,
|
||||
kycStatus: account.kycStatus,
|
||||
realName: account.kycInfo?.realName || null,
|
||||
idCardNumber: account.kycInfo?.idCardNumber || null,
|
||||
idCardFrontUrl: account.kycInfo?.idCardFrontUrl || null,
|
||||
idCardBackUrl: account.kycInfo?.idCardBackUrl || null,
|
||||
status: account.status,
|
||||
registeredAt: account.registeredAt,
|
||||
lastLoginAt: account.lastLoginAt,
|
||||
},
|
||||
});
|
||||
savedUserId = created.userId;
|
||||
|
||||
this.logger.log(
|
||||
`[SAVE] Account created: userId=${savedUserId}, sequence=${created.accountSequence}`,
|
||||
);
|
||||
|
||||
// 更新聚合根的userId
|
||||
(account as any)._userId = UserId.create(savedUserId);
|
||||
} else {
|
||||
// 已存在的账户,更新
|
||||
this.logger.log(
|
||||
`[SAVE] Updating existing account: userId=${account.userId.value}`,
|
||||
);
|
||||
|
||||
await tx.userAccount.update({
|
||||
where: { userId: BigInt(account.userId.value) },
|
||||
data: {
|
||||
phoneNumber: account.phoneNumber?.value || null,
|
||||
nickname: account.nickname,
|
||||
avatarUrl: account.avatarUrl,
|
||||
kycStatus: account.kycStatus,
|
||||
realName: account.kycInfo?.realName || null,
|
||||
idCardNumber: account.kycInfo?.idCardNumber || null,
|
||||
idCardFrontUrl: account.kycInfo?.idCardFrontUrl || null,
|
||||
idCardBackUrl: account.kycInfo?.idCardBackUrl || null,
|
||||
status: account.status,
|
||||
lastLoginAt: account.lastLoginAt,
|
||||
},
|
||||
});
|
||||
savedUserId = account.userId.value;
|
||||
|
||||
this.logger.log(`[SAVE] Account updated: userId=${savedUserId}`);
|
||||
}
|
||||
|
||||
// Sync devices
|
||||
this.logger.log(
|
||||
`[SAVE] Syncing ${devices.length} devices for userId=${savedUserId}`,
|
||||
);
|
||||
|
||||
await tx.userDevice.deleteMany({ where: { userId: savedUserId } });
|
||||
if (devices.length > 0) {
|
||||
await tx.userDevice.createMany({
|
||||
data: devices.map((d) => {
|
||||
// 从 deviceInfo JSON 中提取冗余字段便于查询
|
||||
const info = d.deviceInfo || {};
|
||||
return {
|
||||
userId: savedUserId,
|
||||
deviceId: d.deviceId,
|
||||
deviceName: d.deviceName,
|
||||
deviceInfo: d.deviceInfo
|
||||
? JSON.parse(JSON.stringify(d.deviceInfo))
|
||||
: null, // 100% 保存完整 JSON
|
||||
platform: (info as any).platform || null,
|
||||
deviceModel: (info as any).model || null,
|
||||
osVersion: (info as any).osVersion || null,
|
||||
appVersion: (info as any).appVersion || null,
|
||||
screenWidth: (info as any).screenWidth || null,
|
||||
screenHeight: (info as any).screenHeight || null,
|
||||
locale: (info as any).locale || null,
|
||||
timezone: (info as any).timezone || null,
|
||||
addedAt: d.addedAt,
|
||||
lastActiveAt: d.lastActiveAt,
|
||||
};
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
this.logger.log(`[SAVE] Devices synced successfully`);
|
||||
});
|
||||
|
||||
this.logger.log(
|
||||
`[SAVE] Transaction committed: sequence=${account.accountSequence.value}, userId=${account.userId.value}`,
|
||||
);
|
||||
} catch (error) {
|
||||
this.logger.error(
|
||||
`[SAVE] Transaction FAILED: sequence=${account.accountSequence.value}, error=${error.message}`,
|
||||
);
|
||||
this.logger.error(`[SAVE] Stack: ${error.stack}`);
|
||||
throw error; // 确保异常被抛出
|
||||
}
|
||||
}
|
||||
|
||||
async saveWallets(userId: UserId, wallets: WalletAddress[]): Promise<void> {
|
||||
|
|
|
|||
Loading…
Reference in New Issue