gcx/docs/guides/05-后端开发指南.md

1467 lines
46 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Genex 后端开发指南
> DDD + Clean Architecture + 微服务 | NestJS + Go + Kong + PostgreSQL
---
## 1. 技术栈总览
| 层级 | 技术 | 用途 |
|------|------|------|
| **API网关** | Kong | 限流、认证、路由、负载均衡 |
| **主要业务服务** | NestJS (TypeScript) | 业务逻辑微服务 |
| **高性能服务** | Go | 撮合引擎、链上事件监听、高频任务 |
| **翻译层** | Go + Redis | 地址映射、Gas代付、术语翻译 |
| **数据库** | PostgreSQL 15+ | 核心业务数据 |
| **时序数据库** | TimescaleDB | 行情数据、监控指标 |
| **缓存** | Redis Cluster | 热点数据、会话、订单簿缓存 |
| **消息队列** | Kafka | 事件驱动、链上事件监听 |
| **搜索** | Elasticsearch | 全文检索、日志分析 |
| **AI/ML** | FastAPI (Python) | 信用评分、价格预测、异常检测 |
---
## 2. 架构设计:三层五域
### 2.1 五大业务域
| 域 | 服务名 | 语言 | 职责 |
|----|--------|------|------|
| D1 发行域 | `issuer-service` | NestJS | 发行方入驻、券管理、发行审批 |
| D2 交易域 | `trading-service` | Go | 撮合引擎、订单簿、做市商 |
| D3 清算域 | `clearing-service` | NestJS + Go | 链上结算、兑付清算、退款 |
| D4 合规域 | `compliance-service` | NestJS | KYC/AML、OFAC、Travel Rule |
| D5 AI域 | `ai-service` | FastAPI | 信用评分、定价、异常检测 |
| 通用 | `user-service` | NestJS | 用户注册、认证、Profile |
| 通用 | `translate-service` | Go | UX翻译层地址映射、Gas代付 |
| 通用 | `notification-service` | NestJS | 消息推送、邮件、短信 |
| 通用 | `chain-indexer` | Go | 链上事件监听、数据索引 |
### 2.2 服务间通信
```
┌──────────────────────────────────────────────┐
│ Kong API Gateway │
│ 限流 | OAuth 2.1 + JWT | 路由 | 负载均衡 │
├──────────────────────────────────────────────┤
│ │
│ ┌─────────┐ ┌──────────┐ ┌────────────┐ │
│ │ user │ │ issuer │ │ trading │ │
│ │ service │ │ service │ │ service(Go)│ │
│ └────┬────┘ └────┬─────┘ └─────┬──────┘ │
│ │ │ │ │
│ └────────────┼──────────────┘ │
│ │ │
│ ┌─────┴─────┐ │
│ │ Kafka │ │
│ └─────┬─────┘ │
│ ┌────────────┼───────────────┐ │
│ ┌────┴────┐ ┌─────┴──────┐ ┌─────┴─────┐ │
│ │clearing │ │compliance │ │ai-service │ │
│ │service │ │service │ │(FastAPI) │ │
│ └─────────┘ └────────────┘ └───────────┘ │
└──────────────────────────────────────────────┘
```
- **同步通信**gRPC服务间直接调用如撮合→结算
- **异步通信**Kafka事件驱动链上事件、通知、审计日志
---
## 3. DDD + Clean ArchitectureNestJS服务
### 3.1 模块结构以issuer-service为例
```
issuer-service/
├── src/
│ ├── main.ts
│ ├── app.module.ts
│ ├── domain/ # 领域层(纯业务逻辑,零外部依赖)
│ │ ├── entities/
│ │ │ ├── issuer.entity.ts # 发行方聚合根
│ │ │ ├── coupon-template.entity.ts
│ │ │ └── credit-rating.vo.ts # 值对象
│ │ ├── repositories/
│ │ │ └── issuer.repository.ts # Repository接口
│ │ ├── services/
│ │ │ ├── issuer-domain.service.ts
│ │ │ └── credit-scoring.service.ts
│ │ └── events/
│ │ ├── issuer-approved.event.ts
│ │ └── coupon-issued.event.ts
│ ├── application/ # 应用层(用例编排)
│ │ ├── commands/
│ │ │ ├── register-issuer.command.ts
│ │ │ ├── create-coupon.command.ts
│ │ │ └── handlers/
│ │ ├── queries/
│ │ │ ├── get-issuer.query.ts
│ │ │ └── handlers/
│ │ └── dto/
│ │ ├── create-issuer.dto.ts
│ │ └── create-coupon.dto.ts
│ ├── infrastructure/ # 基础设施层(外部实现)
│ │ ├── persistence/
│ │ │ ├── issuer.repository.impl.ts
│ │ │ ├── issuer.orm-entity.ts
│ │ │ └── typeorm.config.ts
│ │ ├── messaging/
│ │ │ └── kafka-publisher.ts
│ │ └── external/
│ │ └── chain-client.ts # 链上交互
│ └── interfaces/ # 接口层HTTP/gRPC
│ ├── http/
│ │ ├── issuer.controller.ts
│ │ └── coupon.controller.ts
│ └── grpc/
│ └── issuer.grpc-controller.ts
├── test/
└── package.json
```
### 3.2 领域实体
```typescript
// src/domain/entities/issuer.entity.ts
export class Issuer {
readonly id: string;
readonly companyName: string;
private _creditRating: CreditRating;
private _issuanceQuota: number;
private _tier: IssuerTier;
private _status: IssuerStatus;
// 信用评分四因子
updateCreditScore(metrics: CreditMetrics): void {
const score =
0.35 * metrics.redemptionRate +
0.25 * (1 - metrics.breakageRatio) +
0.20 * Math.log(metrics.marketTenure + 1) / Math.log(37) +
0.20 * metrics.userSatisfaction;
this._creditRating = CreditRating.fromScore(score);
this._issuanceQuota = this._creditRating.calculateQuota();
}
// 发券校验
canIssueCoupon(params: CreateCouponParams): Result<void> {
if (this._status !== IssuerStatus.ACTIVE)
return Result.fail('发行方状态异常');
if (params.totalValue > this.remainingQuota)
return Result.fail('超出发行额度');
if (params.expiryDays > 365)
return Result.fail('Utility Track有效期不得超过12个月');
return Result.ok();
}
}
```
### 3.3 应用层Command
```typescript
// src/application/commands/handlers/create-coupon.handler.ts
@CommandHandler(CreateCouponCommand)
export class CreateCouponHandler {
constructor(
private issuerRepo: IssuerRepository,
private eventBus: EventBus,
) {}
async execute(command: CreateCouponCommand): Promise<CouponDraft> {
const issuer = await this.issuerRepo.findById(command.issuerId);
if (!issuer) throw new NotFoundException('发行方不存在');
// 领域校验
const validation = issuer.canIssueCoupon(command.params);
if (validation.isFailure) throw new BadRequestException(validation.error);
// 创建券草稿(待审核)
const draft = CouponDraft.create(issuer, command.params);
await this.issuerRepo.saveCouponDraft(draft);
// 发布领域事件
this.eventBus.publish(new CouponDraftCreatedEvent(draft));
return draft;
}
}
```
---
## 4. Go 高性能服务
### 4.1 撮合引擎
```go
// trading-service/internal/matching/engine.go
type MatchingEngine struct {
orderBooks map[string]*OrderBook // couponId → OrderBook
mu sync.RWMutex
}
type OrderBook struct {
Bids *redblacktree.Tree // 买单:价格降序
Asks *redblacktree.Tree // 卖单:价格升序
}
func (e *MatchingEngine) SubmitOrder(order *Order) []*Trade {
e.mu.Lock()
defer e.mu.Unlock()
book := e.getOrCreateBook(order.CouponID)
// Utility Track价格校验
if order.CouponType == CouponTypeUtility && order.Price > order.FaceValue {
return nil // 拒绝溢价单
}
// 撮合:价格优先 → 时间优先
trades := book.Match(order)
// 成交后发布事件到Kafka
for _, trade := range trades {
e.publisher.Publish("trade.matched", trade)
}
return trades
}
```
### 4.2 链上事件监听
```go
// chain-indexer/internal/indexer/indexer.go
type ChainIndexer struct {
ethClient *ethclient.Client
kafka sarama.SyncProducer
contracts map[string]common.Address
}
func (i *ChainIndexer) Start(ctx context.Context) {
// 监听Genex Chain事件
query := ethereum.FilterQuery{
Addresses: []common.Address{
i.contracts["CouponFactory"],
i.contracts["Settlement"],
i.contracts["Redemption"],
},
}
logs := make(chan types.Log)
sub, _ := i.ethClient.SubscribeFilterLogs(ctx, query, logs)
for {
select {
case log := <-logs:
event := i.parseEvent(log)
i.kafka.SendMessage(&sarama.ProducerMessage{
Topic: "chain.events",
Value: sarama.ByteEncoder(event.Marshal()),
})
case err := <-sub.Err():
log.Error("subscription error", "err", err)
// 重连逻辑
case <-ctx.Done():
return
}
}
}
```
---
## 5. UX翻译层
> 核心创新将所有Web3操作翻译为Web2用户可理解的操作。
```go
// translate-service/internal/service/translate.go
type TranslateService struct {
mappingDB *redis.Client // 手机号→链上地址映射
mpcClient MPCClient // MPC钱包服务
paymaster PaymasterClient // Gas代付服务
}
// 手机号→链上地址
func (s *TranslateService) ResolveAddress(phone string) (common.Address, error) {
addr, err := s.mappingDB.Get(ctx, "phone:"+phone).Result()
if err == redis.Nil {
return common.Address{}, ErrUserNotFound
}
return common.HexToAddress(addr), nil
}
// 购买券:法币→链上原子交换
func (s *TranslateService) ExecutePurchase(req PurchaseRequest) (*PurchaseResult, error) {
// 1. 法币支付确认
// 2. 法币→稳定币转换
// 3. 调用Settlement合约原子交换Gas由Paymaster代付
// 4. 返回"订单号"映射TX Hash
}
```
---
## 6. API设计
### 6.1 RESTful规范
```yaml
API规范:
风格: RESTful
版本控制: URL路径 /api/v1/
认证: OAuth 2.1 + JWT
限流:
普通用户: 100 req/min
发行方: 1,000 req/min
做市商: 10,000 req/min
响应格式: JSON
错误处理: RFC 7807 Problem Details
```
### 6.2 核心API端点
| 域 | 路径前缀 | 主要接口 |
|-----|---------|---------|
| 用户 | `/api/v1/users` | 注册、登录、KYC、资产查询 |
| 券 | `/api/v1/coupons` | 发行、查询、转让、核销 |
| 交易 | `/api/v1/trades` | 挂单、撤单、成交、历史 |
| 支付 | `/api/v1/payments` | 充值、提现、法币转换 |
| 发行方 | `/api/v1/issuers` | 入驻、审核、数据统计 |
| 合规 | `/api/v1/compliance` | KYC、AML、审计日志 |
| 翻译层 | `/api/v1/translate` | 地址映射、Gas代付 |
---
## 7. 数据库设计
### 7.1 PostgreSQL核心表
```sql
-- 用户表
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
phone VARCHAR(20) UNIQUE,
email VARCHAR(100) UNIQUE,
kyc_level SMALLINT NOT NULL DEFAULT 0,
wallet_mode VARCHAR(10) NOT NULL DEFAULT 'standard',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- 发行方表
CREATE TABLE issuers (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
company_name VARCHAR(200) NOT NULL,
business_license VARCHAR(100),
credit_rating VARCHAR(5) NOT NULL DEFAULT 'BBB',
credit_score NUMERIC(5,2) NOT NULL DEFAULT 60.00,
issuance_quota NUMERIC(15,2) NOT NULL DEFAULT 100000,
tier VARCHAR(10) NOT NULL DEFAULT 'silver',
status VARCHAR(20) NOT NULL DEFAULT 'pending',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- 券表(链下缓存,权威数据在链上)
CREATE TABLE coupons (
id UUID PRIMARY KEY,
chain_token_id BIGINT UNIQUE, -- 链上Token ID
issuer_id UUID REFERENCES issuers(id),
face_value NUMERIC(12,2) NOT NULL,
current_price NUMERIC(12,2),
expiry_date DATE NOT NULL,
coupon_type VARCHAR(10) NOT NULL DEFAULT 'utility',
status VARCHAR(20) NOT NULL DEFAULT 'available',
resale_count SMALLINT NOT NULL DEFAULT 0,
max_resale_count SMALLINT NOT NULL DEFAULT 3,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- 地址映射表(翻译层核心)
CREATE TABLE address_mappings (
user_id UUID REFERENCES users(id),
chain_address VARCHAR(42) NOT NULL UNIQUE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
PRIMARY KEY (user_id)
);
```
---
## 8. 安全规范
| 领域 | 规范 |
|------|------|
| 传输 | TLS 1.3 + 服务间mTLS |
| 认证 | OAuth 2.1 + JWT短有效期 + Refresh Token |
| 授权 | RBAC |
| 数据加密 | AES-256敏感字段HSM管理密钥 |
| API安全 | Rate Limiting + CORS + CSRF防护 |
| SQL注入 | ORM参数化查询TypeORM / sqlx |
| 审计 | 全链路操作日志,不可篡改 |
---
## 9. 部署架构
```yaml
# Kubernetes部署
apiVersion: apps/v1
kind: Deployment
metadata:
name: issuer-service
spec:
replicas: 3
template:
spec:
containers:
- name: issuer-service
image: genex/issuer-service:latest
resources:
requests: { cpu: "250m", memory: "512Mi" }
limits: { cpu: "1000m", memory: "1Gi" }
env:
- name: DB_HOST
valueFrom:
configMapKeyRef: { name: db-config, key: host }
- name: DB_PASSWORD
valueFrom:
secretKeyRef: { name: db-secrets, key: password }
```
### 多区域部署
| 区域 | 部署 | 角色 |
|------|------|------|
| AWS美国 | 全量服务 + 主数据库 + Genex Chain主验证节点 |
| AWS新加坡 | 亚太服务 + 灾备数据库 + 区域验证节点 |
| 香港 | 监管节点 + 审计接口 |
---
## 10. 监控与可观测性
| 组件 | 工具 | 用途 |
|------|------|------|
| 指标 | Prometheus + Grafana | 服务指标、业务指标 |
| 日志 | ELK Stack | 日志收集分析 |
| 链路追踪 | Jaeger | 分布式调用追踪 |
| 告警 | AlertManager + PagerDuty | 异常告警 |
---
## 11. 手续费与收入计算
### 11.1 交易手续费(核心收入)
```typescript
// src/domain/services/fee-calculation.service.ts
export class FeeCalculationService {
// Maker-Taker模型
private readonly FEE_RATES = {
taker: { buy: 0.005, sell: 0.005 }, // Taker 0.5%
maker: { buy: 0.001, sell: 0.001 }, // Maker 0.1%(做市商激励)
};
// 发行方分层手续费率
private readonly ISSUER_FEE_RATES: Record<IssuerTier, number> = {
silver: 0.015, // 白银 1.5%
gold: 0.012, // 黄金 1.2%
platinum: 0.010, // 铂金 1.0%
diamond: 0.008, // 钻石 0.8%
};
calculateTradeFee(trade: Trade): TradeFees {
const isMaker = (side: 'buyer' | 'seller') =>
trade[side].isMaker;
return {
buyerFee: trade.price * (isMaker('buyer') ? this.FEE_RATES.maker.buy : this.FEE_RATES.taker.buy),
sellerFee: trade.price * (isMaker('seller') ? this.FEE_RATES.maker.sell : this.FEE_RATES.taker.sell),
};
}
calculateIssuanceFee(issuer: Issuer, totalValue: number): number {
// 新入驻首月享黄金层级
const tier = issuer.isFirstMonth ? 'gold' : issuer.tier;
return totalValue * this.ISSUER_FEE_RATES[tier];
}
}
```
### 11.2 Breakage收益计算与分配
```typescript
// src/domain/services/breakage.service.ts
export class BreakageService {
/**
* 券过期后Breakage计算
* 未使用的券面值 → 发行方Breakage收入
* 平台按比例分润(发行服务协议约定)
*/
async processExpiredCoupons(): Promise<void> {
const expired = await this.couponRepo.findExpiredUnprocessed();
for (const coupon of expired) {
const breakageAmount = coupon.faceValue;
const platformShare = breakageAmount * 0.10; // 平台分润10%(可配置)
const issuerShare = breakageAmount - platformShare;
await this.financeService.recordBreakage({
couponId: coupon.id,
issuerId: coupon.issuerId,
totalAmount: breakageAmount,
platformShare,
issuerShare,
expiredAt: coupon.expiryDate,
});
// 更新券状态
await this.couponRepo.markBreakageProcessed(coupon.id);
// 更新发行方信用评分Breakage率因子
this.eventBus.publish(new CouponExpiredEvent(coupon));
}
}
}
// 定时任务:每日批量处理过期券
@Cron('0 2 * * *') // 每天凌晨2点
async handleExpiredCoupons() {
await this.breakageService.processExpiredCoupons();
}
```
### 11.3 退款机制
```typescript
// src/domain/services/refund.service.ts
interface RefundPolicy {
primaryMarket: {
windowDays: number; // 发行方可配退款窗口默认7天
fullRefund: boolean; // 一级市场全额退(含手续费)
};
secondaryMarket: {
requireArbitration: true; // 二级市场需仲裁
feeRefund: false; // 手续费不退
};
}
export class RefundService {
async processRefund(request: RefundRequest): Promise<RefundResult> {
// 已核销/已过期券不可退
if (['redeemed', 'expired'].includes(request.coupon.status)) {
throw new BadRequestException('已核销或已过期券不可退款');
}
// 一级市场退款:发行方退款窗口内
if (request.type === 'primary') {
const withinWindow = this.isWithinRefundWindow(request);
if (!withinWindow) throw new BadRequestException('超出退款期限');
// 调用Settlement合约反向原子交换
return this.chainClient.executeRefund(request);
}
// 二级市场退款:需仲裁裁决
if (request.type === 'secondary') {
return this.disputeService.createRefundCase(request);
}
}
}
```
---
## 12. 做市商系统
### 12.1 做市商准入与管理
```typescript
// src/domain/entities/market-maker.entity.ts
export class MarketMaker {
id: string;
userId: string;
kycLevel: KycLevel; // 必须KYC L3
depositAmount: number; // 最低保证金
status: 'active' | 'suspended' | 'terminated';
obligations: MarketMakerObligations;
}
interface MarketMakerObligations {
minSpreadBps: number; // 最大价差(基点)
minDepthPerSide: number; // 单边最小挂单深度
uptimePercent: number; // 最低在线时间 (95%)
maxResponseMs: number; // 报价响应时间上限
}
```
### 12.2 做市商专用API
```typescript
// 低延迟专用接口10,000 req/min
@Controller('api/v1/mm')
export class MarketMakerController {
@Post('batch-orders')
async batchOrders(@Body() dto: BatchOrderDto) {
// 批量挂单/撤单单次最多100单
}
@Get('orderbook/:couponId')
async getOrderBook(@Param('couponId') id: string) {
// 实时订单簿快照
}
@Ws('mm/stream')
async streamMarketData() {
// WebSocket低延迟行情推送
}
}
```
### 12.3 Spoofing/Layering检测
```typescript
// 做市商行为监控
export class MarketManipulationDetector {
/**
* Spoofing检测大量挂单后短时间内撤单
* Layering检测多层挂单制造虚假深度
*/
detect(orders: OrderActivity[]): ManipulationAlert[] {
const alerts: ManipulationAlert[] = [];
// 挂单→撤单比率异常(>80%撤单率)
const cancelRate = orders.filter(o => o.cancelled).length / orders.length;
if (cancelRate > 0.8) {
alerts.push({ type: 'spoofing', severity: 'high', cancelRate });
}
// 短时间多层挂单检测
const layeringPattern = this.detectLayeringPattern(orders);
if (layeringPattern) alerts.push(layeringPattern);
return alerts;
}
}
```
---
## 13. 三因子定价引擎
```typescript
// src/domain/services/pricing.service.ts
export class PricingService {
/**
* P = F × (1 - dt - rc - lp)
* dt = Time Discount = f(剩余有效期)
* rc = Credit Risk = f(发行方信用评分)
* lp = Liquidity Premium = f(市场供需)
*/
calculateSuggestedPrice(coupon: Coupon, issuer: Issuer, market: MarketData): PriceSuggestion {
const F = coupon.faceValue;
const totalDays = differenceInDays(coupon.expiryDate, coupon.issuedDate);
const remainDays = differenceInDays(coupon.expiryDate, new Date());
// 时间折扣 (0% - 15%)
const dt = ((totalDays - remainDays) / totalDays) * 0.15;
// 信用风险溢价 (0% - 20%)
const CREDIT_MAP: Record<CreditRating, number> = {
AAA: 0, AA: 0.03, A: 0.06, BBB: 0.10, BB: 0.15,
};
const rc = CREDIT_MAP[issuer.creditRating] || 0.20;
// 流动性溢价 (-5% - 10%)
const supplyDemandRatio = (market.sellOrders - market.buyOrders) / (market.totalOrders || 1);
const lp = Math.max(-0.05, Math.min(0.10, supplyDemandRatio * 0.1));
const price = F * (1 - dt - rc - lp);
// Utility Track: 价格上限 = 面值
const cappedPrice = coupon.type === 'utility' ? Math.min(price, F) : price;
return { suggestedPrice: cappedPrice, factors: { dt, rc, lp } };
}
}
```
---
## 14. AI/ML 模型服务
### 14.1 信用评分引擎
```python
# ai-service/models/credit_scoring.py
import lightgbm as lgb
from sklearn.model_selection import cross_val_score
class CreditScoringModel:
"""
发行方信用评分:四因子基础 + ML增强
特征核销率、Breakage率、市场存续月数、用户满意度、历史违约、行业
"""
def __init__(self):
self.model = lgb.LGBMRegressor(
n_estimators=500, learning_rate=0.05,
max_depth=6, num_leaves=31,
)
def predict_credit_score(self, issuer_features: dict) -> float:
# 四因子基础分
base = (0.35 * issuer_features['redemption_rate'] +
0.25 * (1 - issuer_features['breakage_ratio']) +
0.20 * math.log(issuer_features['tenure_months'] + 1) / math.log(37) +
0.20 * issuer_features['user_satisfaction'])
# ML调整基于更多特征
ml_adjustment = self.model.predict([self._extract_features(issuer_features)])[0]
return min(100, max(0, base * 100 * 0.7 + ml_adjustment * 0.3))
```
### 14.2 价格预测模型
```python
# ai-service/models/price_prediction.py
from prophet import Prophet
import torch.nn as nn
class LSTMPricePredictor(nn.Module):
"""LSTM序列预测历史价格→未来价格走势"""
def __init__(self, input_size=5, hidden_size=64, num_layers=2):
super().__init__()
self.lstm = nn.LSTM(input_size, hidden_size, num_layers, batch_first=True)
self.fc = nn.Linear(hidden_size, 1)
def forward(self, x):
out, _ = self.lstm(x)
return self.fc(out[:, -1, :])
class ProphetSeasonalPredictor:
"""Prophet周期性预测节假日/季节性价格模式"""
def predict(self, history: pd.DataFrame, periods: int = 30):
model = Prophet(yearly_seasonality=True, weekly_seasonality=True)
model.fit(history)
future = model.make_future_dataframe(periods=periods)
return model.predict(future)
```
### 14.3 异常检测系统
```python
# ai-service/models/anomaly_detection.py
from sklearn.ensemble import IsolationForest
class TransactionAnomalyDetector:
"""
异常交易检测Isolation Forest + 规则引擎
实时消费Kafka trade.events标记可疑交易
"""
def __init__(self):
self.isolation_forest = IsolationForest(
contamination=0.01, n_estimators=200, random_state=42
)
def detect(self, transaction: dict) -> AnomalyResult:
features = self._extract_features(transaction)
# ML检测
score = self.isolation_forest.decision_function([features])[0]
# 规则引擎检测
rule_alerts = self._apply_rules(transaction)
return AnomalyResult(
ml_score=score,
is_anomaly=score < -0.5 or len(rule_alerts) > 0,
alerts=rule_alerts,
)
def _apply_rules(self, tx: dict) -> list:
alerts = []
if tx['amount'] > 10000: alerts.append('large_amount')
if tx['frequency_1h'] > 20: alerts.append('high_frequency')
if tx['geolocation_change']: alerts.append('geo_anomaly')
return alerts
```
### 14.4 智能推荐引擎P2优先级
```python
# 协同过滤 + 内容推荐 混合推荐
class CouponRecommender:
def recommend(self, user_id: str, top_k: int = 10):
# 协同过滤:相似用户购买历史
cf_scores = self.collaborative_filter(user_id)
# 内容推荐:基于券属性(品牌、类别、折扣率)
content_scores = self.content_based(user_id)
# 混合加权
return self.blend(cf_scores, content_scores, top_k)
```
---
## 15. AML反洗钱系统
### 15.1 AML检测规则引擎
```typescript
// compliance-service/src/domain/services/aml-detection.service.ts
export class AmlDetectionService {
// 已识别洗钱路径检测
private readonly RULES: AmlRule[] = [
// 1. 买券洗钱脏钱买券→P2P转给另一账户→卖出提现
{ name: 'buy_transfer_withdraw', detect: this.detectBuyTransferWithdraw },
// 2. 分散洗钱一个账户→P2P分散转给大量小账户
{ name: 'fan_out', detect: this.detectFanOut },
// 3. 发行方自洗:关联账户自买自卖
{ name: 'self_dealing', detect: this.detectSelfDealing },
// 4. 跨境洗钱A国买→P2P转B国→B国提现
{ name: 'cross_border', detect: this.detectCrossBorder },
// 5. Structuring拆分交易规避阈值
{ name: 'structuring', detect: this.detectStructuring },
];
async detectFanOut(userId: string, window: TimeWindow): Promise<Alert | null> {
const transfers = await this.getP2PTransfers(userId, window);
const uniqueRecipients = new Set(transfers.map(t => t.recipientId));
// 24h内向>10个不同账户P2P转移
if (uniqueRecipients.size > 10) {
return { type: 'fan_out', severity: 'high', details: { recipients: uniqueRecipients.size } };
}
return null;
}
async detectStructuring(userId: string, window: TimeWindow): Promise<Alert | null> {
const txs = await this.getTransactions(userId, window);
// 检测是否有多笔接近$3,000阈值的交易$2,500-$2,999
const nearThreshold = txs.filter(t => t.amount >= 2500 && t.amount < 3000);
if (nearThreshold.length >= 3) {
return { type: 'structuring', severity: 'critical', details: { count: nearThreshold.length } };
}
return null;
}
}
```
### 15.2 交易图谱分析
```typescript
// 构建用户间交易关系图谱
export class TransactionGraphService {
async buildGraph(timeWindow: TimeWindow): Promise<TransactionGraph> {
const edges = await this.tradeRepo.getTransferEdges(timeWindow);
const graph = new Graph();
for (const edge of edges) {
graph.addEdge(edge.sender, edge.receiver, {
amount: edge.amount, timestamp: edge.timestamp,
});
}
// 检测环形转移
const cycles = graph.detectCycles();
// 检测扇入/扇出模式
const fanPatterns = graph.detectFanPatterns(threshold: 10);
// 关联账户聚类
const clusters = graph.communityDetection();
return { graph, cycles, fanPatterns, clusters };
}
}
```
### 15.3 SAR自动生成
```typescript
// 可疑交易报告Suspicious Activity Report
export class SarService {
async generateSar(alert: AmlAlert): Promise<SarReport> {
return {
filingType: 'initial',
subjectInfo: await this.getUserInfo(alert.userId),
suspiciousActivity: {
dateRange: alert.timeWindow,
amount: alert.totalAmount,
instruments: 'Digital Coupon Assets',
description: this.generateNarrative(alert),
},
// FinCEN BSA E-Filing格式
};
}
}
```
---
## 16. OFAC合规服务
```typescript
// compliance-service/src/infrastructure/external/ofac.service.ts
export class OfacService {
private sdnList: Map<string, SdnEntry> = new Map();
// 名单同步24h内更新
@Cron('0 */6 * * *') // 每6小时同步
async syncSdnList(): Promise<void> {
// 主选Chainalysis备选Elliptic/TRM Labs
const entries = await this.chainalysis.getLatestSdnList();
this.sdnList = new Map(entries.map(e => [e.id, e]));
this.logger.log(`OFAC SDN list synced: ${entries.length} entries`);
}
// 注册时筛查
async screenOnRegistration(user: UserRegistrationDto): Promise<OfacScreenResult> {
return this.screenPerson({
name: user.fullName,
nationality: user.nationality,
address: user.address,
dateOfBirth: user.dob,
});
}
// 每笔交易实时筛查
async screenTransaction(buyer: string, seller: string): Promise<OfacScreenResult> {
const buyerResult = await this.screenAddress(buyer);
const sellerResult = await this.screenAddress(seller);
if (buyerResult.isMatch || sellerResult.isMatch) {
// 命中:立即冻结 + 上报
await this.freezeAndReport(buyerResult, sellerResult);
}
return { buyerResult, sellerResult };
}
// P2P转移链上地址筛查
async screenChainAddress(address: string): Promise<boolean> {
return this.chainalysis.checkAddress(address);
}
}
```
---
## 17. Travel Rule合规TRISA/TRP
```typescript
// compliance-service/src/domain/services/travel-rule.service.ts
export class TravelRuleService {
/**
* FATF Travel Rule: ≥$3,000转移需传递身份信息
* 接入TRISA协议实现跨平台信息传递
*/
async processP2PTransfer(transfer: P2PTransferRequest): Promise<void> {
if (transfer.amount >= 3000) {
// 验证双方KYC≥L2
await this.verifyKycLevel(transfer.senderId, KycLevel.L2);
await this.verifyKycLevel(transfer.receiverId, KycLevel.L2);
// 身份信息哈希写入链上
const senderHash = this.hashIdentity(await this.getKycInfo(transfer.senderId));
const receiverHash = this.hashIdentity(await this.getKycInfo(transfer.receiverId));
await this.chainClient.recordTravelRule(
transfer.senderAddress, transfer.receiverAddress,
senderHash, receiverHash,
);
// TRISA跨平台传递如接收方在其他平台
if (transfer.isExternalReceiver) {
await this.trisaClient.sendTravelRuleInfo({
originator: await this.getOriginatorInfo(transfer.senderId),
beneficiary: await this.getBeneficiaryInfo(transfer.receiverId),
});
}
}
}
}
```
---
## 18. 税务合规
```typescript
// compliance-service/src/domain/services/tax.service.ts
export class TaxComplianceService {
// IRS Form 1099-DA / 1099-B 生成
async generate1099(userId: string, taxYear: number): Promise<Tax1099Report> {
const trades = await this.tradeRepo.getUserTrades(userId, taxYear);
const proceeds = trades.reduce((sum, t) => sum + t.sellPrice, 0);
const costBasis = trades.reduce((sum, t) => sum + t.buyPrice, 0);
return {
form: proceeds > 600 ? '1099-DA' : null, // >$600 threshold
recipientTIN: await this.getUserTIN(userId),
grossProceeds: proceeds,
costBasis,
gainOrLoss: proceeds - costBasis,
transactions: trades.map(t => this.formatTaxTransaction(t)),
};
}
// FATCA跨境税务外国账户持有人
async checkFatcaObligation(userId: string): Promise<boolean> {
const user = await this.userRepo.findById(userId);
return user.nationality !== 'US' && user.hasUsSourceIncome;
}
// 发行方Breakage收入税务处理
async generateIssuerTaxReport(issuerId: string, taxYear: number): Promise<IssuerTaxReport> {
const breakageIncome = await this.financeRepo.getBreakageIncome(issuerId, taxYear);
const salesRevenue = await this.financeRepo.getSalesRevenue(issuerId, taxYear);
return { breakageIncome, salesRevenue, totalTaxableIncome: breakageIncome + salesRevenue };
}
}
```
---
## 19. 数据隐私合规CCPA/GDPR
```typescript
// user-service/src/domain/services/privacy.service.ts
export class PrivacyService {
/**
* 用户数据删除流程:
* 链上仅地址和哈希不可删除但不构成PII
* 链下PII全部可删除
*
* 例外AML/BSA法规要求交易记录保留≥5年
*/
async processDeleteRequest(userId: string): Promise<DeleteResult> {
// 检查数据保留义务
const retentionCheck = await this.checkRetentionObligation(userId);
if (retentionCheck.hasActiveObligation) {
return { status: 'deferred', reason: 'AML/BSA 5年保留期未满', deferUntil: retentionCheck.expiresAt };
}
// 1. 删除链下所有PII
await this.userRepo.deletePersonalData(userId); // 姓名、手机号、邮箱、身份证
await this.kycRepo.deleteKycMaterials(userId); // KYC资料人脸、证件照
// 2. 删除映射表记录
await this.mappingRepo.deleteMapping(userId); // 手机号→地址映射
// 3. 链上地址变为匿名(不可逆删除映射后地址无法关联到人)
// 4. Travel Rule链下明文删除链上仅哈希不可逆
return { status: 'completed', deletedAt: new Date() };
}
}
```
---
## 20. 数据留存与审计
```typescript
// 数据保留策略
const DATA_RETENTION_POLICIES = {
transactionRecords: { minYears: 5, source: 'BSA/AML' },
kycDocuments: { minYears: 5, source: 'BSA/CDD' },
sarReports: { minYears: 5, source: 'FinCEN' },
auditLogs: { minYears: 7, source: 'SOX' },
chainData: { minYears: Infinity, source: 'blockchain' },
};
// 审计日志append-only不可篡改
export class AuditLogService {
async log(entry: AuditEntry): Promise<void> {
await this.appendOnlyStore.write({
timestamp: new Date(),
actor: entry.actorId,
action: entry.action,
resource: entry.resource,
details: entry.details,
ipAddress: entry.ip,
hash: this.computeChainHash(entry), // 链式哈希防篡改
});
}
}
```
---
## 21. 券生命周期管理
```typescript
// 券状态流转
enum CouponStatus {
MINTED = 'minted', // 已铸造(链上)
LISTED = 'listed', // 已上架
SOLD = 'sold', // 已售出
IN_CIRCULATION = 'in_circulation', // 流通中(二级市场)
REDEEMED = 'redeemed', // 已兑付
EXPIRED = 'expired', // 已过期
RECALLED = 'recalled', // 已召回
}
// 过期自动处理
@Cron('0 0 * * *') // 每日凌晨
async processExpiredCoupons(): Promise<void> {
const expiring = await this.couponRepo.findExpiringToday();
for (const coupon of expiring) {
await this.couponRepo.updateStatus(coupon.id, CouponStatus.EXPIRED);
// Breakage收益计算
await this.breakageService.calculateAndDistribute(coupon);
// 通知持有人
await this.notificationService.send(coupon.holderId, {
type: 'coupon_expired',
couponName: coupon.name,
});
}
}
```
---
## 22. 争议与纠纷处理
```typescript
// 争议处理流程
interface DisputeCase {
id: string;
type: 'buyer_complaint' | 'seller_complaint' | 'refund_request';
status: 'submitted' | 'evidence_collection' | 'arbitration' | 'resolved' | 'escalated';
buyerId: string;
sellerId: string;
orderId: string;
chainEvidence: ChainEvidence[]; // 链上不可篡改证据
slaDeadline: Date; // 24h响应72h处理
}
export class DisputeService {
async createDispute(dto: CreateDisputeDto): Promise<DisputeCase> {
const chainEvidence = await this.chainClient.getTransactionProof(dto.orderId);
const dispute = DisputeCase.create({ ...dto, chainEvidence });
// SLA24h内响应
await this.slaService.scheduleReminder(dispute.id, '24h');
return dispute;
}
async arbitrate(disputeId: string, decision: ArbitrationDecision): Promise<void> {
if (decision.refundApproved) {
await this.refundService.processRefund(decision.refundDetails);
}
}
}
```
---
## 23. 客服系统
```typescript
// 工单系统
interface Ticket {
id: string;
userId: string;
category: 'transaction' | 'account' | 'coupon' | 'compliance' | 'other';
priority: 'low' | 'medium' | 'high' | 'urgent';
status: 'open' | 'in_progress' | 'waiting_user' | 'resolved' | 'closed';
sla: { responseTime: '24h', resolutionTime: '72h' };
}
// 发行方专属客服通道(铂金/钻石层级)
export class IssuerSupportService {
getDedicatedChannel(issuer: Issuer): SupportChannel {
if (['platinum', 'diamond'].includes(issuer.tier)) {
return { type: 'dedicated', responseTime: '1h', manager: this.getAccountManager(issuer.id) };
}
return { type: 'standard', responseTime: '24h' };
}
}
```
---
## 24. 安全事件响应计划
### 24.1 事件分级
| 级别 | 定义 | 响应时限 | 示例 |
|------|------|---------|------|
| **P0** | 资产被盗/合约漏洞被利用 | 15分钟内启动 | MPC密钥泄露、合约攻击 |
| **P1** | 数据泄露/系统被入侵 | 1小时内响应 | 用户数据泄露、映射表篡改 |
| **P2** | 局部服务异常/可疑活动 | 4小时内响应 | API攻击、异常登录 |
| **P3** | 潜在风险/安全隐患 | 24小时内评估 | 依赖库漏洞 |
### 24.2 P0应急流程
```typescript
// 自动化应急响应
export class IncidentResponseService {
async handleP0Incident(incident: SecurityIncident): Promise<void> {
// 1. 自动触发紧急冻结Governance合约
await this.chainClient.triggerEmergencyFreeze(incident.affectedAddresses);
// 2. 通知安全团队PagerDuty
await this.pagerDuty.trigger({
severity: 'critical',
description: incident.description,
});
// 3. 保全证据
await this.forensics.preserveEvidence({
logs: await this.collectLogs(incident.timeRange),
chainState: await this.chainClient.getStateSnapshot(),
systemSnapshot: await this.infrastructure.getSnapshot(),
});
// 4. 用户通知≤24hCCPA要求72h内通知受影响用户
await this.notificationService.scheduleBreachNotification(incident);
}
}
```
### 24.3 Bug Bounty
| 严重程度 | 奖励范围 | 示例 |
|---------|---------|------|
| Critical | $50K-$100K | 合约资金盗取、MPC密钥泄露 |
| High | $10K-$50K | 权限绕过、数据泄露 |
| Medium | $2K-$10K | 信息泄露、DoS |
| Low | $500-$2K | 低影响漏洞 |
---
## 25. 灾难恢复与业务连续性
### 25.1 DR指标
| 指标 | 目标 |
|------|------|
| RPO恢复点目标 | < 1分钟 |
| RTO恢复时间目标 | < 15分钟 |
### 25.2 备份与故障转移
```yaml
# 数据库备份策略
postgresql:
replication: streaming_replication # 实时同步至备用区域
backup:
full: weekly # 每周全量备份
incremental: every_15_minutes # 每15分钟增量备份
retention: 90_days # 备份保留90天
failover:
automatic: true # 自动故障转移
health_check_interval: 5s
# 链下数据快照
orderbook:
snapshot: every_5_minutes # 订单簿快照
wal: continuous # 预写日志持续记录
# 链上数据:区块链本身分布式存储,天然灾备
genex_chain:
validators: 3 # ≥3自有验证节点不同地理位置
third_party_rpc: [alchemy, quicknode] # 备用RPC节点
```
### 25.3 业务连续性
| 故障场景 | 应对策略 |
|---------|---------|
| 交易系统故障 | 自动切换备用撮合引擎未完成订单状态保护 |
| 链节点故障 | 多节点冗余(≥3个自有 + 第三方RPC备用 |
| 法币通道故障 | 2家支付服务商自动热备切换 |
| MPC密钥服务故障 | 密钥分片跨地理位置存储Fireblocks/Fordefi热备 |
| 年度DR演练 | 每年1次全量灾难恢复演练并记录 |
---
## 26. 映射表安全方案
> 手机号→地址映射表是最高价值安全资产,被篡改将导致资产错误转移。
```typescript
// translate-service/src/security/mapping-security.service.ts
export class MappingSecurityService {
/**
* 映射记录创建/修改需多方签名:
* 平台服务器 + HSM + 第三方审计节点
*/
async createMapping(userId: string, chainAddress: string): Promise<void> {
// 1. MPC多方签名
const signature = await this.mpcSigner.multiSign({
parties: ['platform_server', 'hsm_module', 'audit_node'],
threshold: 2, // 至少2方签名
data: { userId, chainAddress },
});
// 2. 写入加密数据库AES-256HSM管理密钥
await this.encryptedStore.write(userId, chainAddress, signature);
// 3. 记录到append-only审计日志
await this.auditLog.append({
action: 'mapping_created',
userId, chainAddress, signature,
});
}
// 定期链上锚定Merkle Root
@Cron('0 * * * *') // 每小时
async anchorToChain(): Promise<void> {
const merkleRoot = await this.computeMappingMerkleRoot();
await this.chainClient.anchorMerkleRoot(merkleRoot);
}
// 完整性校验
async verifyIntegrity(): Promise<boolean> {
const currentRoot = await this.computeMappingMerkleRoot();
const chainRoot = await this.chainClient.getLatestMerkleRoot();
return currentRoot === chainRoot;
}
}
```
---
## 27. 发行方违约处理
```typescript
// issuer-service/src/domain/services/default-handling.service.ts
export class IssuerDefaultService {
async handleDefault(issuerId: string, severity: 'minor' | 'major' | 'critical'): Promise<void> {
switch (severity) {
case 'minor':
// 降级 + 额度缩减
await this.issuerRepo.downgradeCreditRating(issuerId, 1);
break;
case 'major':
// 冻结发行 + 启用保障资金
await this.issuerRepo.freezeIssuance(issuerId);
if (await this.hasGuaranteeFund(issuerId)) {
await this.activateGuaranteeFund(issuerId);
}
break;
case 'critical':
// 跑路:冻结账户 + 链上标记风险券 + 通知持有人
await this.issuerRepo.freezeAccount(issuerId);
await this.chainClient.markRiskCoupons(issuerId);
await this.notifyAllHolders(issuerId, '发行方异常,请关注券状态');
break;
}
}
}
```
---
## 28. 多币种与法币通道
```typescript
// 多稳定币支持
interface StablecoinConfig {
primary: 'USDC';
secondary: 'USDT';
oracle: 'chainlink'; // 汇率预言机
}
// 法币通道热备
export class FiatGatewayService {
private providers: FiatProvider[] = [
{ name: 'primary_bank', priority: 1, status: 'active' },
{ name: 'backup_processor', priority: 2, status: 'standby' },
];
async processPayment(request: PaymentRequest): Promise<PaymentResult> {
for (const provider of this.providers.sort((a, b) => a.priority - b.priority)) {
try {
if (provider.status === 'active' || provider.status === 'standby') {
return await provider.process(request);
}
} catch (error) {
this.logger.error(`Fiat provider ${provider.name} failed, trying next`);
provider.status = 'failed';
continue; // 自动切换
}
}
throw new ServiceUnavailableException('All fiat providers unavailable');
}
}
// 汇率管理
export class ExchangeRateService {
async getRate(from: string, to: string): Promise<ExchangeRate> {
// Oracle获取实时汇率
const rate = await this.oracleClient.getRate(from, to);
return { rate: rate.value, lockedUntil: addMinutes(new Date(), 15) }; // 锁定15分钟
}
}
```
---
## 29. 链上对账
```typescript
// 链上数据 vs 链下账本对账
export class ReconciliationService {
// 实时对账(链上数据即账本)
async reconcile(): Promise<ReconciliationResult> {
const chainBalances = await this.chainClient.getAllBalances();
const dbBalances = await this.financeRepo.getAllBalances();
const discrepancies: Discrepancy[] = [];
for (const [userId, chainBal] of chainBalances) {
const dbBal = dbBalances.get(userId);
if (Math.abs(chainBal - dbBal) > 0.01) {
discrepancies.push({ userId, chainBalance: chainBal, dbBalance: dbBal });
}
}
if (discrepancies.length > 0) {
await this.alertService.sendAlert('reconciliation_mismatch', discrepancies);
}
return { totalChecked: chainBalances.size, discrepancies };
}
}
```
---
## 30. 容量规划
| 阶段 | 用户规模 | 日交易量 | 基础设施 |
|------|---------|---------|---------|
| Phase 1 (MVP) | 10万 | 50万笔 | 单区域K8s3节点 |
| Phase 2 (商业化) | 100万 | 500万笔 | 双区域K8s + 热备5+节点 |
| Phase 3 (金融化) | 1,000万 | 5,000万笔 | 多区域集群 + GCFN节点 |
### 关键性能指标
| 指标 | 目标 |
|------|------|
| API响应时间P99 | < 200ms |
| 撮合引擎延迟 | < 10ms |
| 翻译层额外耗时 | < 50ms |
| 系统可用性 | > 99.9% SLA |
---
## 31. SDK开发计划
| SDK | 语言/平台 | 功能范围 | 优先级 |
|-----|----------|---------|--------|
| genex-js | JavaScript/Node.js | 全功能(发行、交易、核销、数据查询) | P0 |
| genex-java | Java/Android | 全功能 + Android原生集成 | P0 |
| genex-python | Python | 数据分析、信用查询、批量操作 | P1 |
| genex-swift | Swift/iOS | 移动端核销、用户端功能 | P1 |
| genex-go | Go | 高性能服务端集成、做市商接入 | P2 |
### 开发者门户
- 沙箱环境Testnet API + 测试券 + 测试USDC
- API文档OpenAPI 3.0 + Swagger UI
- SDK快速入门指南
- Webhook事件订阅
---
*文档版本: v2.0*
*基于: Genex 券交易平台 - 软件需求规格说明书 v4.1*
*技术栈: NestJS + Go + Kong + PostgreSQL + Kafka + Redis*
*更新: 补充手续费/Breakage/退款/做市商/定价引擎/AI-ML/AML/OFAC/Travel Rule/税务/隐私/安全IR/DR/映射表安全/多币种/对账/容量规划/SDK*