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

15 KiB
Raw Blame History

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 领域实体

// 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

// 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 撮合引擎

// 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 链上事件监听

// 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用户可理解的操作。

// 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规范

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核心表

-- 用户表
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. 部署架构

# 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