457 lines
15 KiB
Markdown
457 lines
15 KiB
Markdown
# 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 Architecture(NestJS服务)
|
||
|
||
### 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 | 异常告警 |
|
||
|
||
---
|
||
|
||
*文档版本: v1.0*
|
||
*基于: Genex 券交易平台 - 软件需求规格说明书 v4.1*
|
||
*技术栈: NestJS + Go + Kong + PostgreSQL + Kafka + Redis*
|