This commit is contained in:
parent
44d2e2ad80
commit
e2055483db
|
|
@ -1,5 +1,5 @@
|
|||
# Database
|
||||
DATABASE_URL="mysql://root:password@localhost:3306/rwa_identity"
|
||||
DATABASE_URL="postgresql://postgres:password@localhost:5432/rwa_identity?schema=public"
|
||||
|
||||
# JWT
|
||||
JWT_SECRET="dev-jwt-secret-key"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
# Database
|
||||
DATABASE_URL="mysql://root:password@localhost:3306/rwa_identity"
|
||||
DATABASE_URL="postgresql://postgres:password@localhost:5432/rwa_identity?schema=public"
|
||||
|
||||
# JWT
|
||||
JWT_SECRET="your-super-secret-jwt-key-change-in-production"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
# Database
|
||||
DATABASE_URL="mysql://user:password@production-db:3306/rwa_identity"
|
||||
DATABASE_URL="postgresql://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:5432/${DB_NAME}?schema=public"
|
||||
|
||||
# JWT
|
||||
JWT_SECRET="${JWT_SECRET}"
|
||||
|
|
|
|||
|
|
@ -1,13 +1,7 @@
|
|||
-- ============================================
|
||||
-- Identity Context 数据库初始化
|
||||
-- Identity Context 数据库初始化 (PostgreSQL)
|
||||
-- ============================================
|
||||
|
||||
CREATE DATABASE IF NOT EXISTS rwa_identity
|
||||
DEFAULT CHARACTER SET utf8mb4
|
||||
COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
USE rwa_identity;
|
||||
|
||||
-- 初始化账户序列号生成器
|
||||
INSERT INTO account_sequence_generator (id, current_sequence) VALUES (1, 0)
|
||||
ON DUPLICATE KEY UPDATE id = id;
|
||||
ON CONFLICT (id) DO NOTHING;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ services:
|
|||
ports:
|
||||
- "3000:3000"
|
||||
environment:
|
||||
- DATABASE_URL=mysql://root:password@mysql:3306/rwa_identity
|
||||
- DATABASE_URL=postgresql://postgres:password@postgres:5432/rwa_identity?schema=public
|
||||
- JWT_SECRET=your-super-secret-jwt-key-change-in-production
|
||||
- JWT_ACCESS_EXPIRES_IN=2h
|
||||
- JWT_REFRESH_EXPIRES_IN=30d
|
||||
|
|
@ -16,24 +16,26 @@ services:
|
|||
- APP_PORT=3000
|
||||
- APP_ENV=production
|
||||
depends_on:
|
||||
mysql:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_started
|
||||
kafka:
|
||||
condition: service_started
|
||||
|
||||
mysql:
|
||||
image: mysql:8.0
|
||||
postgres:
|
||||
image: postgres:16-alpine
|
||||
environment:
|
||||
- MYSQL_ROOT_PASSWORD=password
|
||||
- MYSQL_DATABASE=rwa_identity
|
||||
- POSTGRES_USER=postgres
|
||||
- POSTGRES_PASSWORD=password
|
||||
- POSTGRES_DB=rwa_identity
|
||||
ports:
|
||||
- "3306:3306"
|
||||
- "5432:5432"
|
||||
volumes:
|
||||
- mysql_data:/var/lib/mysql
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
|
||||
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
|
||||
|
|
@ -63,5 +65,5 @@ services:
|
|||
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
|
||||
|
||||
volumes:
|
||||
mysql_data:
|
||||
postgres_data:
|
||||
redis_data:
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ generator client {
|
|||
}
|
||||
|
||||
datasource db {
|
||||
provider = "mysql"
|
||||
provider = "postgresql"
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,83 +1,13 @@
|
|||
// Request DTOs
|
||||
export * from './request';
|
||||
|
||||
// Response DTOs
|
||||
export * from './response';
|
||||
|
||||
// 其他通用DTOs
|
||||
import { IsString, IsOptional, IsNotEmpty, Matches, IsEnum, IsNumber } from 'class-validator';
|
||||
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
||||
|
||||
// ============ Request DTOs ============
|
||||
|
||||
export class AutoCreateAccountDto {
|
||||
@ApiProperty({ example: '550e8400-e29b-41d4-a716-446655440000' })
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
deviceId: string;
|
||||
|
||||
@ApiPropertyOptional({ example: 'iPhone 15 Pro' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
deviceName?: string;
|
||||
|
||||
@ApiPropertyOptional({ example: 'ABC123' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@Matches(/^[A-Z0-9]{6}$/, { message: '推荐码格式错误' })
|
||||
inviterReferralCode?: string;
|
||||
|
||||
@ApiPropertyOptional()
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
provinceCode?: string;
|
||||
|
||||
@ApiPropertyOptional()
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
cityCode?: string;
|
||||
}
|
||||
|
||||
export class RecoverByMnemonicDto {
|
||||
@ApiProperty({ example: 10001 })
|
||||
@IsNumber()
|
||||
accountSequence: number;
|
||||
|
||||
@ApiProperty({ example: 'abandon ability able about above absent absorb abstract absurd abuse access accident' })
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
mnemonic: string;
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
newDeviceId: string;
|
||||
|
||||
@ApiPropertyOptional()
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
deviceName?: string;
|
||||
}
|
||||
|
||||
export class RecoverByPhoneDto {
|
||||
@ApiProperty({ example: 10001 })
|
||||
@IsNumber()
|
||||
accountSequence: number;
|
||||
|
||||
@ApiProperty({ example: '13800138000' })
|
||||
@IsString()
|
||||
@Matches(/^1[3-9]\d{9}$/, { message: '手机号格式错误' })
|
||||
phoneNumber: string;
|
||||
|
||||
@ApiProperty({ example: '123456' })
|
||||
@IsString()
|
||||
@Matches(/^\d{6}$/, { message: '验证码格式错误' })
|
||||
smsCode: string;
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
newDeviceId: string;
|
||||
|
||||
@ApiPropertyOptional()
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
deviceName?: string;
|
||||
}
|
||||
|
||||
export class AutoLoginDto {
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
|
|
@ -155,18 +85,6 @@ export class LoginDto {
|
|||
deviceId: string;
|
||||
}
|
||||
|
||||
export class BindPhoneDto {
|
||||
@ApiProperty({ example: '13800138000' })
|
||||
@IsString()
|
||||
@Matches(/^1[3-9]\d{9}$/, { message: '手机号格式错误' })
|
||||
phoneNumber: string;
|
||||
|
||||
@ApiProperty({ example: '123456' })
|
||||
@IsString()
|
||||
@Matches(/^\d{6}$/, { message: '验证码格式错误' })
|
||||
smsCode: string;
|
||||
}
|
||||
|
||||
export class UpdateProfileDto {
|
||||
@ApiPropertyOptional()
|
||||
@IsOptional()
|
||||
|
|
@ -195,28 +113,6 @@ export class BindWalletDto {
|
|||
address: string;
|
||||
}
|
||||
|
||||
export class SubmitKYCDto {
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
realName: string;
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
@Matches(/^[1-9]\d{5}(18|19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[0-9Xx]$/, { message: '身份证号格式错误' })
|
||||
idCardNumber: string;
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
idCardFrontUrl: string;
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
idCardBackUrl: string;
|
||||
}
|
||||
|
||||
export class RemoveDeviceDto {
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
|
|
@ -224,8 +120,7 @@ export class RemoveDeviceDto {
|
|||
deviceId: string;
|
||||
}
|
||||
|
||||
// ============ Response DTOs ============
|
||||
|
||||
// Response DTOs
|
||||
export class AutoCreateAccountResponseDto {
|
||||
@ApiProperty()
|
||||
userId: string;
|
||||
|
|
@ -285,67 +180,3 @@ export class LoginResponseDto {
|
|||
@ApiProperty()
|
||||
refreshToken: string;
|
||||
}
|
||||
|
||||
export class UserProfileResponseDto {
|
||||
@ApiProperty()
|
||||
userId: string;
|
||||
|
||||
@ApiProperty()
|
||||
accountSequence: number;
|
||||
|
||||
@ApiProperty({ nullable: true })
|
||||
phoneNumber: string | null;
|
||||
|
||||
@ApiProperty()
|
||||
nickname: string;
|
||||
|
||||
@ApiProperty({ nullable: true })
|
||||
avatarUrl: string | null;
|
||||
|
||||
@ApiProperty()
|
||||
referralCode: string;
|
||||
|
||||
@ApiProperty()
|
||||
province: string;
|
||||
|
||||
@ApiProperty()
|
||||
city: string;
|
||||
|
||||
@ApiProperty({ nullable: true })
|
||||
address: string | null;
|
||||
|
||||
@ApiProperty()
|
||||
walletAddresses: Array<{ chainType: string; address: string }>;
|
||||
|
||||
@ApiProperty()
|
||||
kycStatus: string;
|
||||
|
||||
@ApiProperty({ nullable: true })
|
||||
kycInfo: { realName: string; idCardNumber: string } | null;
|
||||
|
||||
@ApiProperty()
|
||||
status: string;
|
||||
|
||||
@ApiProperty()
|
||||
registeredAt: Date;
|
||||
|
||||
@ApiProperty({ nullable: true })
|
||||
lastLoginAt: Date | null;
|
||||
}
|
||||
|
||||
export class DeviceResponseDto {
|
||||
@ApiProperty()
|
||||
deviceId: string;
|
||||
|
||||
@ApiProperty()
|
||||
deviceName: string;
|
||||
|
||||
@ApiProperty()
|
||||
addedAt: Date;
|
||||
|
||||
@ApiProperty()
|
||||
lastActiveAt: Date;
|
||||
|
||||
@ApiProperty()
|
||||
isCurrent: boolean;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
import { IsString, IsOptional, IsNotEmpty, Matches } from 'class-validator';
|
||||
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
||||
|
||||
export class AutoCreateAccountDto {
|
||||
@ApiProperty({ example: '550e8400-e29b-41d4-a716-446655440000' })
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
deviceId: string;
|
||||
|
||||
@ApiPropertyOptional({ example: 'iPhone 15 Pro' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
deviceName?: string;
|
||||
|
||||
@ApiPropertyOptional({ example: 'ABC123' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@Matches(/^[A-Z0-9]{6}$/, { message: '推荐码格式错误' })
|
||||
inviterReferralCode?: string;
|
||||
|
||||
@ApiPropertyOptional()
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
provinceCode?: string;
|
||||
|
||||
@ApiPropertyOptional()
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
cityCode?: string;
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
import { IsString, Matches } from 'class-validator';
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export class BindPhoneDto {
|
||||
@ApiProperty({ example: '13800138000' })
|
||||
@IsString()
|
||||
@Matches(/^1[3-9]\d{9}$/, { message: '手机号格式错误' })
|
||||
phoneNumber: string;
|
||||
|
||||
@ApiProperty({ example: '123456' })
|
||||
@IsString()
|
||||
@Matches(/^\d{6}$/, { message: '验证码格式错误' })
|
||||
smsCode: string;
|
||||
}
|
||||
|
|
@ -1 +1,5 @@
|
|||
export * from '../index';
|
||||
export * from './auto-create-account.dto';
|
||||
export * from './recover-by-mnemonic.dto';
|
||||
export * from './recover-by-phone.dto';
|
||||
export * from './bind-phone.dto';
|
||||
export * from './submit-kyc.dto';
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
import { IsString, IsOptional, IsNotEmpty, IsNumber } from 'class-validator';
|
||||
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
||||
|
||||
export class RecoverByMnemonicDto {
|
||||
@ApiProperty({ example: 10001 })
|
||||
@IsNumber()
|
||||
accountSequence: number;
|
||||
|
||||
@ApiProperty({ example: 'abandon ability able about above absent absorb abstract absurd abuse access accident' })
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
mnemonic: string;
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
newDeviceId: string;
|
||||
|
||||
@ApiPropertyOptional()
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
deviceName?: string;
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
import { IsString, IsOptional, IsNotEmpty, IsNumber, Matches } from 'class-validator';
|
||||
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
||||
|
||||
export class RecoverByPhoneDto {
|
||||
@ApiProperty({ example: 10001 })
|
||||
@IsNumber()
|
||||
accountSequence: number;
|
||||
|
||||
@ApiProperty({ example: '13800138000' })
|
||||
@IsString()
|
||||
@Matches(/^1[3-9]\d{9}$/, { message: '手机号格式错误' })
|
||||
phoneNumber: string;
|
||||
|
||||
@ApiProperty({ example: '123456' })
|
||||
@IsString()
|
||||
@Matches(/^\d{6}$/, { message: '验证码格式错误' })
|
||||
smsCode: string;
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
newDeviceId: string;
|
||||
|
||||
@ApiPropertyOptional()
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
deviceName?: string;
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
import { IsString, IsNotEmpty, Matches } from 'class-validator';
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export class SubmitKycDto {
|
||||
@ApiProperty({ example: '张三' })
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
realName: string;
|
||||
|
||||
@ApiProperty({ example: '110101199001011234' })
|
||||
@IsString()
|
||||
@Matches(/^[1-9]\d{5}(18|19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[0-9Xx]$/, { message: '身份证号格式错误' })
|
||||
idCardNumber: string;
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
idCardFrontUrl: string;
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
idCardBackUrl: string;
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export class DeviceDto {
|
||||
@ApiProperty()
|
||||
deviceId: string;
|
||||
|
||||
@ApiProperty()
|
||||
deviceName: string;
|
||||
|
||||
@ApiProperty()
|
||||
addedAt: Date;
|
||||
|
||||
@ApiProperty()
|
||||
lastActiveAt: Date;
|
||||
|
||||
@ApiProperty()
|
||||
isCurrent: boolean;
|
||||
}
|
||||
|
|
@ -1 +1,2 @@
|
|||
export * from '../index';
|
||||
export * from './user-profile.dto';
|
||||
export * from './device.dto';
|
||||
|
|
|
|||
|
|
@ -0,0 +1,64 @@
|
|||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export class WalletAddressDto {
|
||||
@ApiProperty()
|
||||
chainType: string;
|
||||
|
||||
@ApiProperty()
|
||||
address: string;
|
||||
}
|
||||
|
||||
export class KycInfoDto {
|
||||
@ApiProperty()
|
||||
realName: string;
|
||||
|
||||
@ApiProperty()
|
||||
idCardNumber: string;
|
||||
}
|
||||
|
||||
export class UserProfileDto {
|
||||
@ApiProperty()
|
||||
userId: string;
|
||||
|
||||
@ApiProperty()
|
||||
accountSequence: number;
|
||||
|
||||
@ApiProperty({ nullable: true })
|
||||
phoneNumber: string | null;
|
||||
|
||||
@ApiProperty()
|
||||
nickname: string;
|
||||
|
||||
@ApiProperty({ nullable: true })
|
||||
avatarUrl: string | null;
|
||||
|
||||
@ApiProperty()
|
||||
referralCode: string;
|
||||
|
||||
@ApiProperty()
|
||||
province: string;
|
||||
|
||||
@ApiProperty()
|
||||
city: string;
|
||||
|
||||
@ApiProperty({ nullable: true })
|
||||
address: string | null;
|
||||
|
||||
@ApiProperty({ type: [WalletAddressDto] })
|
||||
walletAddresses: WalletAddressDto[];
|
||||
|
||||
@ApiProperty()
|
||||
kycStatus: string;
|
||||
|
||||
@ApiProperty({ type: KycInfoDto, nullable: true })
|
||||
kycInfo: KycInfoDto | null;
|
||||
|
||||
@ApiProperty()
|
||||
status: string;
|
||||
|
||||
@ApiProperty()
|
||||
registeredAt: Date;
|
||||
|
||||
@ApiProperty({ nullable: true })
|
||||
lastLoginAt: Date | null;
|
||||
}
|
||||
Loading…
Reference in New Issue