From 17fd663fe30c3c858351fed4f3e827fe63f5fdaf Mon Sep 17 00:00:00 2001 From: hailin Date: Sat, 6 Dec 2025 18:05:11 -0800 Subject: [PATCH] refactor: improve auto-create API semantics and use real device ID MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Frontend (account_service.dart): - Use Android ID instead of random UUID for deviceId - Add DeviceHardwareInfo class with full hardware details - Remove provinceCode/cityCode from CreateAccountRequest - Simplify to: deviceId (required), deviceName (optional JSON), inviterReferralCode (optional) Backend (identity-service): - Rename validateDeviceId() to checkDeviceNotRegistered() for clarity - Rename generateNext() to generateNextUserSequence() for semantics - Update error message: "该设备已创建过账户" 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- backend/services/.claude/settings.local.json | 12 ++ .../auto-create-account.handler.ts | 6 +- .../services/user-application.service.ts | 6 +- .../account-sequence-generator.service.ts | 2 +- .../domain/services/user-validator.service.ts | 4 +- .../lib/core/services/account_service.dart | 132 ++++++++++++------ 6 files changed, 114 insertions(+), 48 deletions(-) create mode 100644 backend/services/.claude/settings.local.json diff --git a/backend/services/.claude/settings.local.json b/backend/services/.claude/settings.local.json new file mode 100644 index 00000000..7ab967ee --- /dev/null +++ b/backend/services/.claude/settings.local.json @@ -0,0 +1,12 @@ +{ + "permissions": { + "allow": [ + "Bash(cat:*)", + "Bash(git add:*)", + "Bash(git commit:*)", + "Bash(git push:*)" + ], + "deny": [], + "ask": [] + } +} diff --git a/backend/services/identity-service/src/application/commands/auto-create-account/auto-create-account.handler.ts b/backend/services/identity-service/src/application/commands/auto-create-account/auto-create-account.handler.ts index 67a849e3..0432e23b 100644 --- a/backend/services/identity-service/src/application/commands/auto-create-account/auto-create-account.handler.ts +++ b/backend/services/identity-service/src/application/commands/auto-create-account/auto-create-account.handler.ts @@ -26,8 +26,8 @@ export class AutoCreateAccountHandler { ) {} async execute(command: AutoCreateAccountCommand): Promise { - const deviceValidation = await this.validatorService.validateDeviceId(command.deviceId); - if (!deviceValidation.isValid) throw new ApplicationError(deviceValidation.errorMessage!); + const deviceCheck = await this.validatorService.checkDeviceNotRegistered(command.deviceId); + if (!deviceCheck.isValid) throw new ApplicationError(deviceCheck.errorMessage!); let inviterSequence: AccountSequence | null = null; if (command.inviterReferralCode) { @@ -38,7 +38,7 @@ export class AutoCreateAccountHandler { inviterSequence = inviter!.accountSequence; } - const accountSequence = await this.sequenceGenerator.generateNext(); + const accountSequence = await this.sequenceGenerator.generateNextUserSequence(); const account = UserAccount.createAutomatic({ accountSequence, diff --git a/backend/services/identity-service/src/application/services/user-application.service.ts b/backend/services/identity-service/src/application/services/user-application.service.ts index 61c10554..935e960d 100644 --- a/backend/services/identity-service/src/application/services/user-application.service.ts +++ b/backend/services/identity-service/src/application/services/user-application.service.ts @@ -73,8 +73,8 @@ export class UserApplicationService { inviterSequence = inviter!.accountSequence; } - // 3. 生成账户序列号 - const accountSequence = await this.sequenceGenerator.generateNext(); + // 3. 生成用户序列号 + const accountSequence = await this.sequenceGenerator.generateNextUserSequence(); // 4. 创建用户账户 const account = UserAccount.createAutomatic({ @@ -301,7 +301,7 @@ export class UserApplicationService { inviterSequence = inviter!.accountSequence; } - const accountSequence = await this.sequenceGenerator.generateNext(); + const accountSequence = await this.sequenceGenerator.generateNextUserSequence(); const account = UserAccount.create({ accountSequence, diff --git a/backend/services/identity-service/src/domain/services/account-sequence-generator.service.ts b/backend/services/identity-service/src/domain/services/account-sequence-generator.service.ts index 032a5cf3..7750e479 100644 --- a/backend/services/identity-service/src/domain/services/account-sequence-generator.service.ts +++ b/backend/services/identity-service/src/domain/services/account-sequence-generator.service.ts @@ -9,7 +9,7 @@ export class AccountSequenceGeneratorService { private readonly repository: UserAccountRepository, ) {} - async generateNext(): Promise { + async generateNextUserSequence(): Promise { return this.repository.getNextAccountSequence(); } } diff --git a/backend/services/identity-service/src/domain/services/user-validator.service.ts b/backend/services/identity-service/src/domain/services/user-validator.service.ts index 3cb83eb4..0f0e8c75 100644 --- a/backend/services/identity-service/src/domain/services/user-validator.service.ts +++ b/backend/services/identity-service/src/domain/services/user-validator.service.ts @@ -30,9 +30,9 @@ export class UserValidatorService { return ValidationResult.success(); } - async validateDeviceId(deviceId: string): Promise { + async checkDeviceNotRegistered(deviceId: string): Promise { const existing = await this.repository.findByDeviceId(deviceId); - if (existing) return ValidationResult.failure('该设备已创建账户'); + if (existing) return ValidationResult.failure('该设备已创建过账户'); return ValidationResult.success(); } diff --git a/frontend/mobile-app/lib/core/services/account_service.dart b/frontend/mobile-app/lib/core/services/account_service.dart index f5f9ddd6..b7a5ffc5 100644 --- a/frontend/mobile-app/lib/core/services/account_service.dart +++ b/frontend/mobile-app/lib/core/services/account_service.dart @@ -8,29 +8,60 @@ import '../storage/storage_keys.dart'; import '../errors/exceptions.dart'; import 'mpc_share_service.dart'; +/// 设备硬件信息 (存储在 deviceName 字段中) +class DeviceHardwareInfo { + final String? brand; // 品牌 (如 "Xiaomi") + final String? manufacturer; // 厂商 (如 "Xiaomi") + final String? model; // 型号 (如 "Mi 11") + final String? device; // 设备名 (如 "venus") + final String? product; // 产品名 (如 "venus_eea") + final String? hardware; // 硬件名 (如 "qcom") + final String? osVersion; // 系统版本 (如 "13") + final int? sdkInt; // SDK 版本 (如 33) + final bool? isPhysicalDevice; // 是否真机 + + DeviceHardwareInfo({ + this.brand, + this.manufacturer, + this.model, + this.device, + this.product, + this.hardware, + this.osVersion, + this.sdkInt, + this.isPhysicalDevice, + }); + + Map toJson() => { + if (brand != null) 'brand': brand, + if (manufacturer != null) 'manufacturer': manufacturer, + if (model != null) 'model': model, + if (device != null) 'device': device, + if (product != null) 'product': product, + if (hardware != null) 'hardware': hardware, + if (osVersion != null) 'osVersion': osVersion, + if (sdkInt != null) 'sdkInt': sdkInt, + if (isPhysicalDevice != null) 'isPhysicalDevice': isPhysicalDevice, + }; +} + /// 创建账号请求 class CreateAccountRequest { - final String deviceId; - final String? deviceName; - final String? inviterReferralCode; - final String? provinceCode; - final String? cityCode; + final String deviceId; // 必填: Android ID 或 iOS identifierForVendor + final DeviceHardwareInfo? deviceName; // 可选: 设备硬件信息 (JSON) + final String? inviterReferralCode; // 可选: 邀请人推荐码 CreateAccountRequest({ required this.deviceId, this.deviceName, this.inviterReferralCode, - this.provinceCode, - this.cityCode, }); Map toJson() => { 'deviceId': deviceId, - if (deviceName != null) 'deviceName': deviceName, + if (deviceName != null) 'deviceName': deviceName!.toJson(), if (inviterReferralCode != null) 'inviterReferralCode': inviterReferralCode, - if (provinceCode != null) 'provinceCode': provinceCode, - if (cityCode != null) 'cityCode': cityCode, }; } @@ -108,33 +139,59 @@ class AccountService { }) : _apiClient = apiClient, _secureStorage = secureStorage; - /// 获取或生成设备ID - Future getOrCreateDeviceId() async { - // 尝试从存储读取 - var deviceId = await _secureStorage.read(key: StorageKeys.deviceId); - if (deviceId != null && deviceId.isNotEmpty) { - return deviceId; - } - - // 生成新的设备ID - deviceId = const Uuid().v4(); - await _secureStorage.write(key: StorageKeys.deviceId, value: deviceId); - return deviceId; - } - - /// 获取设备名称 - Future getDeviceName() async { - final deviceInfo = DeviceInfoPlugin(); + /// 获取设备唯一标识符 + /// + /// Android: 使用 Android ID (64位十六进制字符串) + /// iOS: 使用 identifierForVendor + Future getDeviceId() async { + final deviceInfoPlugin = DeviceInfoPlugin(); if (Platform.isAndroid) { - final info = await deviceInfo.androidInfo; - return '${info.brand} ${info.model}'; + final info = await deviceInfoPlugin.androidInfo; + return info.id; // Android ID } else if (Platform.isIOS) { - final info = await deviceInfo.iosInfo; - return info.name; + final info = await deviceInfoPlugin.iosInfo; + return info.identifierForVendor ?? const Uuid().v4(); } - return 'Unknown Device'; + // 其他平台回退到 UUID + return const Uuid().v4(); + } + + /// 获取设备硬件信息 + /// + /// Android: 完整硬件信息 + /// iOS: 基本信息 + Future getDeviceHardwareInfo() async { + final deviceInfoPlugin = DeviceInfoPlugin(); + + if (Platform.isAndroid) { + final info = await deviceInfoPlugin.androidInfo; + return DeviceHardwareInfo( + brand: info.brand, + manufacturer: info.manufacturer, + model: info.model, + device: info.device, + product: info.product, + hardware: info.hardware, + osVersion: info.version.release, + sdkInt: info.version.sdkInt, + isPhysicalDevice: info.isPhysicalDevice, + ); + } else if (Platform.isIOS) { + final info = await deviceInfoPlugin.iosInfo; + return DeviceHardwareInfo( + brand: 'Apple', + manufacturer: 'Apple', + model: info.model, + device: info.name, + osVersion: info.systemVersion, + isPhysicalDevice: info.isPhysicalDevice, + ); + } + + // 其他平台返回空信息 + return DeviceHardwareInfo(); } /// 自动创建账号 (首次打开APP) @@ -142,13 +199,12 @@ class AccountService { /// 使用 MPC 2-of-3 协议生成钱包地址 Future createAccount({ String? inviterReferralCode, - String? provinceCode, - String? cityCode, }) async { try { - // 获取设备信息 - final deviceId = await getOrCreateDeviceId(); - final deviceName = await getDeviceName(); + // 获取设备ID (必填) + final deviceId = await getDeviceId(); + // 获取设备硬件信息 (可选) + final deviceName = await getDeviceHardwareInfo(); // 调用 API final response = await _apiClient.post( @@ -157,8 +213,6 @@ class AccountService { deviceId: deviceId, deviceName: deviceName, inviterReferralCode: inviterReferralCode, - provinceCode: provinceCode, - cityCode: cityCode, ).toJson(), );