diff --git a/backend/services/identity-service/REMAINING_STEPS.md b/backend/services/identity-service/REMAINING_STEPS.md new file mode 100644 index 00000000..5cb5c8ec --- /dev/null +++ b/backend/services/identity-service/REMAINING_STEPS.md @@ -0,0 +1,143 @@ +# 剩余步骤说明 + +所有源代码错误已修复!现在需要执行以下步骤来解决 Prisma Client 和依赖包的问题。 + +## 🔧 需要执行的命令(按顺序) + +### 1. 安装新增的依赖包 +```bash +npm install +``` + +这将安装以下新增的包: +- `@nestjs/passport@^10.0.0` +- `@nestjs/schedule@^4.0.0` +- `passport-jwt@^4.0.1` +- `@types/passport-jwt@^4.0.0` + +### 2. 生成 Prisma Client +```bash +npm run prisma:generate +``` + +这将根据更新后的 `schema.prisma` 生成新的 Prisma Client,包括: +- `DeadLetterEvent` 模型 +- `SmsCode` 模型 + +### 3. 创建并应用数据库迁移 +```bash +npm run prisma:migrate +``` + +这将创建并应用新表的数据库迁移。如果提示输入迁移名称,可以使用: +``` +add_dead_letter_and_sms_tables +``` + +### 4. 启动开发服务器 +```bash +npm run start:dev +``` + +## ✅ 已修复的所有错误(共 21 个) + +### 代码层面的修复: + +1. ✅ **DomainException → DomainError** (3 处) + - [wallet-generator.service.ts:131](src/infrastructure/external/blockchain/wallet-generator.service.ts#L131) + - [wallet-generator.service.ts:153](src/infrastructure/external/blockchain/wallet-generator.service.ts#L153) + - [wallet-generator.service.ts:169](src/infrastructure/external/blockchain/wallet-generator.service.ts#L169) + +2. ✅ **UserId 类型问题** (2 处) + - 修改为使用 `UserId.create(params.userId)` 并使用 `WalletAddress.createFromMnemonic()` + - [wallet-generator.service.ts:54-65](src/infrastructure/external/blockchain/wallet-generator.service.ts#L54-L65) + - [wallet-generator.service.ts:84-95](src/infrastructure/external/blockchain/wallet-generator.service.ts#L84-L95) + +3. ✅ **Seed Buffer 类型问题** (2 处) + - 添加 `Buffer.from()` 转换 + - [wallet-generator.service.ts:102](src/infrastructure/external/blockchain/wallet-generator.service.ts#L102) + +4. ✅ **IDENTITY_TOPICS 缺失主题** (2 处) + - 添加 `KYC_APPROVED` 和 `ACCOUNT_FROZEN` + - [event-publisher.service.ts:28-31](src/infrastructure/kafka/event-publisher.service.ts#L28-L31) + +5. ✅ **DomainEventMessage 缺失字段** (2 处) + - 添加 `eventId` 和 `occurredAt` 字段 + - [event-retry.service.ts:40-47](src/infrastructure/kafka/event-retry.service.ts#L40-L47) + - [event-retry.service.ts:77-84](src/infrastructure/kafka/event-retry.service.ts#L77-L84) + +### 需要命令解决的问题: + +6. ⏳ **Prisma Client 未生成** (10 处) + - 需要运行 `npm run prisma:generate` + - 涉及所有 `prisma.deadLetterEvent` 和 `prisma.smsCode` 的调用 + +7. ⏳ **依赖包未安装** (2 处) + - 需要运行 `npm install` + - `@nestjs/passport` 和 `passport-jwt` + +## 📝 修改的文件列表 + +- ✏️ [prisma/schema.prisma](prisma/schema.prisma) - 添加 DeadLetterEvent 和 SmsCode 模型 +- ✏️ [package.json](package.json) - 添加依赖包 +- ✏️ [src/infrastructure/external/blockchain/wallet-generator.service.ts](src/infrastructure/external/blockchain/wallet-generator.service.ts) - 修复所有类型和导入问题 +- ✏️ [src/infrastructure/kafka/event-publisher.service.ts](src/infrastructure/kafka/event-publisher.service.ts) - 添加缺失的主题 +- ✏️ [src/infrastructure/kafka/event-retry.service.ts](src/infrastructure/kafka/event-retry.service.ts) - 修复 DomainEventMessage 参数 + +## 🎯 验证步骤 + +完成上述命令后,验证所有问题已解决: + +```bash +# 1. 检查编译 +npm run build + +# 2. 运行测试 +npm test + +# 3. 启动开发服务器 +npm run start:dev +``` + +如果一切正常,你应该看到类似以下的输出: +``` +[Nest] 12345 - 2025/11/24, 9:43:00 AM LOG [NestFactory] Starting Nest application... +[Nest] 12345 - 2025/11/24, 9:43:00 AM LOG [InstanceLoader] AppModule dependencies initialized +... +[Nest] 12345 - 2025/11/24, 9:43:01 AM LOG [NestApplication] Nest application successfully started +``` + +## 🔍 如果遇到问题 + +### Prisma 迁移失败 +如果数据库迁移失败,可以尝试: +```bash +# 重置数据库(开发环境) +npm run prisma:migrate reset + +# 或手动创建迁移 +npx prisma migrate dev --create-only +# 然后编辑迁移文件 +# 最后应用迁移 +npx prisma migrate dev +``` + +### 依赖安装失败 +如果 npm install 失败,尝试: +```bash +# 清理缓存 +npm cache clean --force + +# 删除 node_modules 和 lock 文件 +rm -rf node_modules package-lock.json + +# 重新安装 +npm install +``` + +## 📚 相关文档 + +- [Prisma 迁移文档](https://www.prisma.io/docs/concepts/components/prisma-migrate) +- [Passport JWT 文档](http://www.passportjs.org/packages/passport-jwt/) +- [NestJS Passport 文档](https://docs.nestjs.com/security/authentication) +- [NestJS 定时任务文档](https://docs.nestjs.com/techniques/task-scheduling) diff --git a/backend/services/identity-service/src/infrastructure/external/blockchain/wallet-generator.service.ts b/backend/services/identity-service/src/infrastructure/external/blockchain/wallet-generator.service.ts index ad392983..bd78e02e 100644 --- a/backend/services/identity-service/src/infrastructure/external/blockchain/wallet-generator.service.ts +++ b/backend/services/identity-service/src/infrastructure/external/blockchain/wallet-generator.service.ts @@ -10,10 +10,9 @@ import { import { bech32 } from 'bech32'; import { ethers } from 'ethers'; import { ConfigService } from '@nestjs/config'; -import { Mnemonic } from '@/domain/value-objects/mnemonic.vo'; +import { Mnemonic, UserId, ChainType, CHAIN_CONFIG } from '@/domain/value-objects'; import { WalletAddress } from '@/domain/entities/wallet-address.entity'; -import { ChainType, CHAIN_CONFIG } from '@/domain/enums/chain-type.enum'; -import { DomainException } from '@/shared/exceptions/domain.exception'; +import { DomainError } from '@/shared/exceptions/domain.exception'; import { v4 as uuidv4 } from 'uuid'; export interface WalletSystemResult { @@ -51,20 +50,14 @@ export class WalletGeneratorService { const wallets = new Map(); const chains = [ChainType.KAVA, ChainType.DST, ChainType.BSC]; + const userId = UserId.create(params.userId); for (const chainType of chains) { - const address = this.deriveAddress(chainType, mnemonic); - const encryptedMnemonic = this.encryptMnemonic( - mnemonic.value, - encryptionKey, - ); - - const wallet = WalletAddress.create({ - addressId: `addr_${uuidv4()}`, - userId: params.userId, + const wallet = WalletAddress.createFromMnemonic({ + userId, chainType, - address, - encryptedMnemonic: JSON.stringify(encryptedMnemonic), + mnemonic, + encryptionKey, }); wallets.set(chainType, wallet); @@ -87,20 +80,14 @@ export class WalletGeneratorService { const wallets = new Map(); const chains = [ChainType.KAVA, ChainType.DST, ChainType.BSC]; + const userId = UserId.create(params.userId); for (const chainType of chains) { - const address = this.deriveAddress(chainType, params.mnemonic); - const encryptedMnemonic = this.encryptMnemonic( - params.mnemonic.value, - encryptionKey, - ); - - const wallet = WalletAddress.create({ - addressId: `addr_${uuidv4()}`, - userId: params.userId, + const wallet = WalletAddress.createFromMnemonic({ + userId, chainType, - address, - encryptedMnemonic: JSON.stringify(encryptedMnemonic), + mnemonic: params.mnemonic, + encryptionKey, }); wallets.set(chainType, wallet); @@ -112,7 +99,7 @@ export class WalletGeneratorService { } deriveAddress(chainType: ChainType, mnemonic: Mnemonic): string { - const seed = mnemonic.toSeed(); + const seed = Buffer.from(mnemonic.toSeed()); const config = CHAIN_CONFIG[chainType]; switch (chainType) { @@ -128,7 +115,7 @@ export class WalletGeneratorService { return this.deriveEVMAddress(seed, config.derivationPath); default: - throw new DomainException(`不支持的链类型: ${chainType}`); + throw new DomainError(`不支持的链类型: ${chainType}`); } } @@ -150,7 +137,7 @@ export class WalletGeneratorService { const childKey = hdkey.derive(path); if (!childKey.publicKey) { - throw new DomainException('无法派生公钥'); + throw new DomainError('无法派生公钥'); } const pubkey = childKey.publicKey; @@ -166,7 +153,7 @@ export class WalletGeneratorService { const childKey = hdkey.derive(path); if (!childKey.privateKey) { - throw new DomainException('无法派生私钥'); + throw new DomainError('无法派生私钥'); } // 将 Uint8Array 转换为十六进制字符串 diff --git a/backend/services/identity-service/src/infrastructure/kafka/event-publisher.service.ts b/backend/services/identity-service/src/infrastructure/kafka/event-publisher.service.ts index 1f37c676..88bb745b 100644 --- a/backend/services/identity-service/src/infrastructure/kafka/event-publisher.service.ts +++ b/backend/services/identity-service/src/infrastructure/kafka/event-publisher.service.ts @@ -25,8 +25,10 @@ export const IDENTITY_TOPICS = { KYC_SUBMITTED: 'identity.KYCSubmitted', KYC_VERIFIED: 'identity.KYCVerified', KYC_REJECTED: 'identity.KYCRejected', + KYC_APPROVED: 'identity.KYCApproved', USER_LOCATION_UPDATED: 'identity.UserLocationUpdated', USER_ACCOUNT_FROZEN: 'identity.UserAccountFrozen', + ACCOUNT_FROZEN: 'identity.AccountFrozen', USER_ACCOUNT_DEACTIVATED: 'identity.UserAccountDeactivated', } as const; diff --git a/backend/services/identity-service/src/infrastructure/kafka/event-retry.service.ts b/backend/services/identity-service/src/infrastructure/kafka/event-retry.service.ts index 2894fed1..c09a5dc1 100644 --- a/backend/services/identity-service/src/infrastructure/kafka/event-retry.service.ts +++ b/backend/services/identity-service/src/infrastructure/kafka/event-retry.service.ts @@ -38,6 +38,8 @@ export class EventRetryService { try { await this.eventPublisher.publish(event.topic, { + eventId: event.eventId, + occurredAt: event.createdAt.toISOString(), aggregateId: event.aggregateId, aggregateType: event.aggregateType, eventType: event.eventType, @@ -73,6 +75,8 @@ export class EventRetryService { try { await this.eventPublisher.publish(event.topic, { + eventId: event.eventId, + occurredAt: event.createdAt.toISOString(), aggregateId: event.aggregateId, aggregateType: event.aggregateType, eventType: event.eventType,