# 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 { 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 { 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*