bw-mini-app-server/docs/multi-platform-integration-...

54 KiB
Raw Permalink Blame History

多平台小程序/H5/RN融合统一后台技术方案

项目概述

本项目是一个AI图片/视频生成平台的统一后台服务支持微信、京东、百度、支付宝、字节跳动、QQ、飞书、快手等多个平台的小程序、H5和React Native应用。

核心业务功能

  • AI内容生成: 用户上传图片+提示词,调用大模型生成图片/视频
  • 积分系统: 用户通过看广告获得积分使用AI功能消耗积分
  • 付费订阅: 支持包月付费,获得更多积分和高级功能
  • 多平台统一: 抹平不同平台API差异提供统一的服务接口

技术架构

1. 整体架构设计

┌─────────────────────────────────────────────────────────────┐
│                    客户端层 (Client Layer)                    │
├─────────────────────────────────────────────────────────────┤
│ 微信小程序 │ 支付宝小程序 │ 百度小程序 │ 字节跳动小程序 │ H5 │ RN │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                   API网关层 (API Gateway)                    │
├─────────────────────────────────────────────────────────────┤
│          统一路由 │ 请求验证 │ 限流 │ 积分校验 │ 权限控制     │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                  业务服务层 (Business Layer)                 │
├─────────────────────────────────────────────────────────────┤
│ 用户服务 │ AI生成服务 │ 积分服务 │ 广告服务 │ 订阅服务 │ 文件服务 │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                 平台适配层 (Platform Adapter)                │
├─────────────────────────────────────────────────────────────┤
│  微信API │ 支付宝API │ 百度API │ 字节API │ 京东API │ QQ API  │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                 第三方服务层 (External Services)              │
├─────────────────────────────────────────────────────────────┤
│  大模型API │ 文件存储 │ 广告平台 │ 支付网关 │ CDN服务      │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                   数据存储层 (Data Layer)                    │
├─────────────────────────────────────────────────────────────┤
│      MySQL    │ 文件存储 │ 对象存储                    │
└─────────────────────────────────────────────────────────────┘

2. 核心模块设计

2.1 平台识别模块 (Platform Detection)

  • 功能: 自动识别请求来源平台
  • 实现方式:
    • 通过User-Agent识别
    • 通过自定义Header标识
    • 通过域名/路径前缀区分

2.2 平台适配器模块 (Platform Adapters)

  • 微信适配器: 处理微信小程序/公众号API
  • 支付宝适配器: 处理支付宝小程序API
  • 百度适配器: 处理百度智能小程序API
  • 字节跳动适配器: 处理抖音/今日头条小程序API
  • 京东适配器: 处理京东小程序API
  • QQ适配器: 处理QQ小程序API
  • 飞书适配器: 处理飞书小程序API
  • 快手适配器: 处理快手小程序API

2.3 统一服务接口模块 (Unified Service Interface)

  • 用户管理服务: 统一用户登录、注册、信息管理
  • AI模板管理服务: 统一模板注册、执行、参数验证
  • AI生成服务: 图片/视频生成调用大模型API
  • 积分系统服务: 积分获取、消耗、查询管理
  • 广告服务: 广告展示、观看验证、积分奖励
  • 订阅服务: 包月付费、会员权益管理
  • 文件管理服务: 图片上传、生成内容存储

技术选型

后端技术栈

  • 框架: NestJS (已选择)
  • 数据库: MySQL (主数据库)
  • ORM: TypeORM (数据库操作)

开发工具

  • API文档: Swagger/OpenAPI
  • 代码质量: ESLint + Prettier
  • 测试: Jest
  • 容器化: Docker

核心功能模块

1. 用户认证与授权

1.1 统一登录流程

interface UnifiedLoginRequest {
  platform: PlatformType;
  code: string;
  userInfo?: any;
  encryptedData?: string;
  iv?: string;
}

interface UnifiedLoginResponse {
  token: string;
  refreshToken: string;
  userInfo: UnifiedUserInfo;
  platformSpecific?: any;
}

1.2 平台差异处理

  • 微信: 使用code换取session_key和openid
  • 支付宝: 使用auth_code获取用户信息
  • 百度: 使用authorization_code获取access_token
  • 字节跳动: 使用code获取用户信息
  • 其他平台: 根据各自OAuth流程处理

2. 扩展服务预留

2.1 服务扩展架构

// 预留的服务接口基类
interface BaseService {
  platform: PlatformType;
  userId: string;
  timestamp: Date;
}

// 扩展服务示例接口 (后续实现)
interface ExtensionServiceInterface {
  // 支付服务接口 (预留)
  payment?: PaymentServiceInterface;

  // 推送服务接口 (预留)
  push?: PushServiceInterface;

  // 订单服务接口 (预留)
  order?: OrderServiceInterface;
}

2.2 模块化扩展设计

  • 插件化架构: 支持动态加载新的服务模块
  • 统一接口标准: 所有扩展服务遵循统一的接口规范
  • 平台适配层: 每个服务都有对应的平台适配器
  • 配置驱动: 通过配置文件控制服务的启用和禁用

3. 异步任务处理服务

3.1 数据库异步处理

  • 功能: 使用数据库任务队列替代消息队列
  • 实现方式: 通过数据库表存储待处理任务,定时处理器执行

3.2 业务异步处理

// 用户注册异步处理
async processUserRegistration(userId: string, platform: string) {
  // 用户数据处理
  await this.userService.processRegistration(userId);

  // 发放新用户积分奖励
  await this.creditService.grantNewUserBonus(userId, platform);

  // 同步到各平台
  await this.platformService.syncUserData({ userId, platform });
}

// AI生成任务异步处理
async processAIGenerationTask(taskId: string) {
  // 处理AI生成任务
  await this.generationService.processGenerationTask(taskId);
}

// 广告观看完成异步处理
async processAdWatchCompleted(adWatchId: string, watchDuration: number, adData: any) {
  // 发放广告观看奖励
  await this.adService.completeAdWatch(adWatchId, watchDuration, adData);
}

数据库设计 (MySQL + TypeORM)

1. 用户实体 (User Entity)

import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, OneToMany } from 'typeorm';
import { PlatformUser } from './platform-user.entity';
import { ExtensionData } from './extension-data.entity';
import { UserCredit } from './user-credit.entity';
import { TemplateExecutionEntity } from './template-execution.entity';
import { UserSubscription } from './user-subscription.entity';
import { AdWatch } from './ad-watch.entity';

@Entity('users')
export class User {
  @PrimaryGeneratedColumn('uuid')
  id: string;

  @Column({ unique: true, length: 64 })
  unifiedUserId: string;

  @Column({ length: 100, nullable: true })
  nickname: string;

  @Column({ length: 500, nullable: true })
  avatarUrl: string;

  @Column({ length: 20, nullable: true })
  phone: string;

  @Column({ length: 100, nullable: true })
  email: string;

  @Column({ type: 'smallint', default: 1 })
  status: number;

  @CreateDateColumn()
  createdAt: Date;

  @UpdateDateColumn()
  updatedAt: Date;

  @OneToMany(() => PlatformUser, platformUser => platformUser.user)
  platformUsers: PlatformUser[];

  @OneToMany(() => ExtensionData, extensionData => extensionData.user)
  extensionData: ExtensionData[];

  @OneToMany(() => UserCredit, userCredit => userCredit.user)
  credits: UserCredit[];

  @OneToMany(() => TemplateExecutionEntity, execution => execution.userId)
  templateExecutions: TemplateExecutionEntity[];

  @OneToMany(() => UserSubscription, userSubscription => userSubscription.user)
  subscriptions: UserSubscription[];

  @OneToMany(() => AdWatch, adWatch => adWatch.user)
  adWatches: AdWatch[];

  // 注意: 现在使用 TemplateExecutionEntity 实体管理模板执行记录
}

2. 平台用户关联实体 (PlatformUser Entity)

import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, ManyToOne, JoinColumn, Index } from 'typeorm';
import { User } from './user.entity';

export enum PlatformType {
  WECHAT = 'wechat',
  ALIPAY = 'alipay',
  BAIDU = 'baidu',
  BYTEDANCE = 'bytedance',
  JD = 'jd',
  QQ = 'qq',
  FEISHU = 'feishu',
  KUAISHOU = 'kuaishou',
  H5 = 'h5',
  RN = 'rn'
}

@Entity('platform_users')
@Index(['platform', 'platformUserId'], { unique: true })
export class PlatformUser {
  @PrimaryGeneratedColumn('uuid')
  id: string;

  @Column()
  userId: string;

  @Column({
    type: 'enum',
    enum: PlatformType
  })
  platform: PlatformType;

  @Column({ length: 100 })
  platformUserId: string;

  @Column({ type: 'json', nullable: true })
  platformData: any;

  @Column({ length: 500, nullable: true })
  accessToken: string;

  @Column({ length: 500, nullable: true })
  refreshToken: string;

  @Column({ type: 'timestamp', nullable: true })
  expiresAt: Date;

  @CreateDateColumn()
  createdAt: Date;

  @UpdateDateColumn()
  updatedAt: Date;

  @ManyToOne(() => User, user => user.platformUsers, { onDelete: 'CASCADE' })
  @JoinColumn({ name: 'userId' })
  user: User;
}

3. 扩展数据实体 (Extension Entity - 预留)

import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, ManyToOne, JoinColumn } from 'typeorm';
import { User } from './user.entity';
import { PlatformType } from './platform-user.entity';

// 通用扩展数据实体 (用于存储各种扩展功能的数据)
@Entity('extension_data')
export class ExtensionData {
  @PrimaryGeneratedColumn('uuid')
  id: string;

  @Column()
  userId: string;

  @Column({
    type: 'enum',
    enum: PlatformType
  })
  platform: PlatformType;

  @Column({ length: 50 })
  dataType: string; // 'order', 'payment', 'push', 'custom' 等

  @Column({ length: 100, nullable: true })
  referenceId: string; // 外部引用ID

  @Column({ type: 'json' })
  data: any; // 灵活的JSON数据存储

  @Column({ type: 'json', nullable: true })
  metadata: any; // 元数据

  @Column({ length: 20, default: 'active' })
  status: string;

  @CreateDateColumn()
  createdAt: Date;

  @UpdateDateColumn()
  updatedAt: Date;

  @ManyToOne(() => User, user => user.extensionData, { onDelete: 'CASCADE' })
  @JoinColumn({ name: 'userId' })
  user: User;
}

4. 用户积分实体 (UserCredit Entity)

import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, ManyToOne, JoinColumn } from 'typeorm';
import { User } from './user.entity';
import { PlatformType } from './platform-user.entity';

export enum CreditType {
  REWARD = 'reward',      // 奖励获得
  CONSUME = 'consume',    // 消费扣除
  PURCHASE = 'purchase',  // 购买获得
  REFUND = 'refund'       // 退款返还
}

export enum CreditSource {
  AD_WATCH = 'ad_watch',           // 看广告
  SUBSCRIPTION = 'subscription',    // 订阅赠送
  AI_GENERATION = 'ai_generation',  // AI生成消费
  MANUAL = 'manual'                // 手动调整
}

@Entity('user_credits')
export class UserCredit {
  @PrimaryGeneratedColumn('uuid')
  id: string;

  @Column()
  userId: string;

  @Column({
    type: 'enum',
    enum: PlatformType
  })
  platform: PlatformType;

  @Column({
    type: 'enum',
    enum: CreditType
  })
  type: CreditType;

  @Column({
    type: 'enum',
    enum: CreditSource
  })
  source: CreditSource;

  @Column({ type: 'integer' })
  amount: number; // 正数为增加,负数为扣除

  @Column({ type: 'integer' })
  balance: number; // 操作后余额

  @Column({ length: 200, nullable: true })
  description: string;

  @Column({ length: 100, nullable: true })
  referenceId: string; // 关联的业务ID如广告ID、任务ID等

  @Column({ type: 'json', nullable: true })
  metadata: any;

  @CreateDateColumn()
  createdAt: Date;

  @UpdateDateColumn()
  updatedAt: Date;

  @ManyToOne(() => User, user => user.credits, { onDelete: 'CASCADE' })
  @JoinColumn({ name: 'userId' })
  user: User;
}

5. AI生成任务实体 (GenerationTask Entity)

import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, ManyToOne, JoinColumn } from 'typeorm';
import { User } from './user.entity';
import { PlatformType } from './platform-user.entity';

export enum GenerationType {
  IMAGE = 'image',
  VIDEO = 'video'
}

export enum TaskStatus {
  PENDING = 'pending',     // 等待处理
  PROCESSING = 'processing', // 处理中
  COMPLETED = 'completed', // 已完成
  FAILED = 'failed',       // 失败
  CANCELLED = 'cancelled'  // 已取消
}

@Entity('generation_tasks')
export class GenerationTask {
  @PrimaryGeneratedColumn('uuid')
  id: string;

  @Column()
  userId: string;

  @Column({
    type: 'enum',
    enum: PlatformType
  })
  platform: PlatformType;

  @Column({
    type: 'enum',
    enum: GenerationType
  })
  type: GenerationType;

  @Column({ type: 'text' })
  prompt: string; // 用户输入的提示词

  @Column({ length: 500, nullable: true })
  inputImageUrl: string; // 输入图片URL

  @Column({ length: 500, nullable: true })
  outputUrl: string; // 生成结果URL

  @Column({ length: 500, nullable: true })
  thumbnailUrl: string; // 缩略图URL

  @Column({
    type: 'enum',
    enum: TaskStatus,
    default: TaskStatus.PENDING
  })
  status: TaskStatus;

  @Column({ type: 'integer' })
  creditCost: number; // 消耗的积分

  @Column({ length: 100, nullable: true })
  aiModelId: string; // 使用的AI模型ID

  @Column({ type: 'json', nullable: true })
  parameters: any; // 生成参数

  @Column({ type: 'text', nullable: true })
  errorMessage: string; // 错误信息

  @Column({ type: 'integer', nullable: true })
  processingTime: number; // 处理时间(秒)

  @CreateDateColumn()
  createdAt: Date;

  @UpdateDateColumn()
  updatedAt: Date;

  @ManyToOne(() => User, user => user.generationTasks, { onDelete: 'CASCADE' })
  @JoinColumn({ name: 'userId' })
  user: User;
}

6. 用户订阅实体 (UserSubscription Entity)

import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, ManyToOne, JoinColumn } from 'typeorm';
import { User } from './user.entity';
import { PlatformType } from './platform-user.entity';

export enum SubscriptionPlan {
  BASIC = 'basic',       // 基础版
  PREMIUM = 'premium',   // 高级版
  PRO = 'pro'           // 专业版
}

export enum SubscriptionStatus {
  ACTIVE = 'active',       // 激活中
  EXPIRED = 'expired',     // 已过期
  CANCELLED = 'cancelled', // 已取消
  PENDING = 'pending'      // 待激活
}

@Entity('user_subscriptions')
export class UserSubscription {
  @PrimaryGeneratedColumn('uuid')
  id: string;

  @Column()
  userId: string;

  @Column({
    type: 'enum',
    enum: PlatformType
  })
  platform: PlatformType;

  @Column({
    type: 'enum',
    enum: SubscriptionPlan
  })
  plan: SubscriptionPlan;

  @Column({
    type: 'enum',
    enum: SubscriptionStatus,
    default: SubscriptionStatus.PENDING
  })
  status: SubscriptionStatus;

  @Column({ type: 'timestamp' })
  startDate: Date;

  @Column({ type: 'timestamp' })
  endDate: Date;

  @Column({ type: 'decimal', precision: 10, scale: 2 })
  price: number; // 订阅价格

  @Column({ length: 10, default: 'CNY' })
  currency: string;

  @Column({ type: 'integer' })
  monthlyCredits: number; // 每月赠送积分

  @Column({ length: 100, nullable: true })
  paymentId: string; // 支付订单ID

  @Column({ type: 'json', nullable: true })
  features: any; // 订阅特权

  @Column({ type: 'boolean', default: true })
  autoRenew: boolean; // 自动续费

  @CreateDateColumn()
  createdAt: Date;

  @UpdateDateColumn()
  updatedAt: Date;

  @ManyToOne(() => User, user => user.subscriptions, { onDelete: 'CASCADE' })
  @JoinColumn({ name: 'userId' })
  user: User;
}

7. 广告观看记录实体 (AdWatch Entity)

import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, ManyToOne, JoinColumn } from 'typeorm';
import { User } from './user.entity';
import { PlatformType } from './platform-user.entity';

export enum AdType {
  BANNER = 'banner',         // 横幅广告
  INTERSTITIAL = 'interstitial', // 插屏广告
  REWARDED = 'rewarded',     // 激励视频广告
  NATIVE = 'native'          // 原生广告
}

export enum AdStatus {
  STARTED = 'started',       // 开始观看
  COMPLETED = 'completed',   // 观看完成
  SKIPPED = 'skipped',       // 跳过
  FAILED = 'failed'          // 失败
}

@Entity('ad_watches')
export class AdWatch {
  @PrimaryGeneratedColumn('uuid')
  id: string;

  @Column()
  userId: string;

  @Column({
    type: 'enum',
    enum: PlatformType
  })
  platform: PlatformType;

  @Column({
    type: 'enum',
    enum: AdType
  })
  adType: AdType;

  @Column({ length: 100 })
  adId: string; // 广告ID

  @Column({ length: 100, nullable: true })
  adUnitId: string; // 广告位ID

  @Column({
    type: 'enum',
    enum: AdStatus
  })
  status: AdStatus;

  @Column({ type: 'integer', nullable: true })
  watchDuration: number; // 观看时长(秒)

  @Column({ type: 'integer', nullable: true })
  rewardCredits: number; // 奖励积分

  @Column({ type: 'json', nullable: true })
  adData: any; // 广告相关数据

  @CreateDateColumn()
  createdAt: Date;

  @UpdateDateColumn()
  updatedAt: Date;

  @ManyToOne(() => User, user => user.adWatches, { onDelete: 'CASCADE' })
  @JoinColumn({ name: 'userId' })
  user: User;
}

8. 模板执行记录系统说明

重要说明: 本项目采用混合式模板管理系统,使用数据库存储模板配置和执行记录。

8.1 模板系统架构

  • 模板定义: 通过 N8nTemplateEntity 存储模板配置
  • 模板管理: 通过 N8nTemplateFactoryService 管理模板实例化
  • 执行记录: 通过 TemplateExecutionEntity 表记录AI生成任务的完整过程

8.2 TemplateExecutionEntity 实体结构

// 现在使用专门的模板执行记录实体
@Entity('template_executions')
export class TemplateExecutionEntity {
  @PrimaryGeneratedColumn()
  id: number;

  @Column({ name: 'template_id' })
  templateId: number;

  @Column({ name: 'user_id' })
  userId: string;

  @Column({ type: 'enum', enum: PlatformType })
  platform: PlatformType;

  @Column({ type: 'enum', enum: ExecutionType })
  type: ExecutionType;

  @Column({ type: 'text' })
  prompt: string;

  @Column({ name: 'output_url', length: 500, nullable: true })
  outputUrl: string;

  @Column({ type: 'enum', enum: ExecutionStatus, default: ExecutionStatus.PENDING })
  status: ExecutionStatus;

  @Column({ name: 'credit_cost', default: 0 })
  creditCost: number;

  @ManyToOne(() => N8nTemplateEntity)
  @JoinColumn({ name: 'template_id' })
  template: N8nTemplateEntity;
}

4. TypeORM配置

// src/config/database.config.ts
import { TypeOrmModuleOptions } from '@nestjs/typeorm';
import { ConfigService } from '@nestjs/config';

export const getDatabaseConfig = (configService: ConfigService): TypeOrmModuleOptions => ({
  type: 'mysql',
  host: configService.get('DB_HOST', 'localhost'),
  port: configService.get('DB_PORT', 3306),
  username: configService.get('DB_USERNAME', 'root'),
  password: configService.get('DB_PASSWORD', 'password'),
  database: configService.get('DB_DATABASE', 'mini_app_platform'),
  entities: [__dirname + '/../**/*.entity{.ts,.js}'],
  migrations: [__dirname + '/../migrations/*{.ts,.js}'],
  synchronize: configService.get('NODE_ENV') === 'development',
  logging: configService.get('NODE_ENV') === 'development',
  ssl: configService.get('NODE_ENV') === 'production' ? { rejectUnauthorized: false } : false,
  extra: {
    max: 20, // 连接池最大连接数
    idleTimeoutMillis: 30000, // 空闲连接超时时间
    connectionTimeoutMillis: 2000, // 连接超时时间
  },
});

5. 数据库迁移示例

// src/migrations/001-create-initial-tables.ts
import { MigrationInterface, QueryRunner } from 'typeorm';

export class CreateInitialTables1703001000000 implements MigrationInterface {
  name = 'CreateInitialTables1703001000000';

  public async up(queryRunner: QueryRunner): Promise<void> {
    // 创建用户表
    await queryRunner.query(`
      CREATE TABLE "users" (
        "id" uuid NOT NULL DEFAULT uuid_generate_v4(),
        "unifiedUserId" character varying(64) NOT NULL,
        "nickname" character varying(100),
        "avatarUrl" character varying(500),
        "phone" character varying(20),
        "email" character varying(100),
        "status" smallint NOT NULL DEFAULT '1',
        "createdAt" TIMESTAMP NOT NULL DEFAULT now(),
        "updatedAt" TIMESTAMP NOT NULL DEFAULT now(),
        CONSTRAINT "UQ_users_unifiedUserId" UNIQUE ("unifiedUserId"),
        CONSTRAINT "PK_users_id" PRIMARY KEY ("id")
      )
    `);

    // 创建平台用户关联表
    await queryRunner.query(`
      CREATE TYPE "platform_type" AS ENUM(
        'wechat', 'alipay', 'baidu', 'bytedance',
        'jd', 'qq', 'feishu', 'kuaishou', 'h5', 'rn'
      )
    `);

    await queryRunner.query(`
      CREATE TABLE "platform_users" (
        "id" uuid NOT NULL DEFAULT uuid_generate_v4(),
        "userId" uuid NOT NULL,
        "platform" "platform_type" NOT NULL,
        "platformUserId" character varying(100) NOT NULL,
        "platformData" json,
        "accessToken" character varying(500),
        "refreshToken" character varying(500),
        "expiresAt" TIMESTAMP,
        "createdAt" TIMESTAMP NOT NULL DEFAULT now(),
        "updatedAt" TIMESTAMP NOT NULL DEFAULT now(),
        CONSTRAINT "UQ_platform_users_platform_platformUserId" UNIQUE ("platform", "platformUserId"),
        CONSTRAINT "PK_platform_users_id" PRIMARY KEY ("id"),
        CONSTRAINT "FK_platform_users_userId" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE CASCADE
      )
    `);

    // 创建扩展数据表
    await queryRunner.query(`
      CREATE TABLE "extension_data" (
        "id" uuid NOT NULL DEFAULT uuid_generate_v4(),
        "userId" uuid NOT NULL,
        "platform" "platform_type" NOT NULL,
        "dataType" character varying(50) NOT NULL,
        "referenceId" character varying(100),
        "data" json NOT NULL,
        "metadata" json,
        "status" character varying(20) NOT NULL DEFAULT 'active',
        "createdAt" TIMESTAMP NOT NULL DEFAULT now(),
        "updatedAt" TIMESTAMP NOT NULL DEFAULT now(),
        CONSTRAINT "PK_extension_data_id" PRIMARY KEY ("id"),
        CONSTRAINT "FK_extension_data_userId" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE CASCADE
      )
    `);

    // 创建用户积分表
    await queryRunner.query(`
      CREATE TYPE "credit_type" AS ENUM('reward', 'consume', 'purchase', 'refund')
    `);

    await queryRunner.query(`
      CREATE TYPE "credit_source" AS ENUM('ad_watch', 'subscription', 'ai_generation', 'manual')
    `);

    await queryRunner.query(`
      CREATE TABLE "user_credits" (
        "id" uuid NOT NULL DEFAULT uuid_generate_v4(),
        "userId" uuid NOT NULL,
        "platform" "platform_type" NOT NULL,
        "type" "credit_type" NOT NULL,
        "source" "credit_source" NOT NULL,
        "amount" integer NOT NULL,
        "balance" integer NOT NULL,
        "description" character varying(200),
        "referenceId" character varying(100),
        "metadata" json,
        "createdAt" TIMESTAMP NOT NULL DEFAULT now(),
        "updatedAt" TIMESTAMP NOT NULL DEFAULT now(),
        CONSTRAINT "PK_user_credits_id" PRIMARY KEY ("id"),
        CONSTRAINT "FK_user_credits_userId" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE CASCADE
      )
    `);

    // 创建AI生成任务表
    await queryRunner.query(`
      CREATE TYPE "generation_type" AS ENUM('image', 'video')
    `);

    await queryRunner.query(`
      CREATE TYPE "task_status" AS ENUM('pending', 'processing', 'completed', 'failed', 'cancelled')
    `);

    await queryRunner.query(`
      CREATE TABLE "generation_tasks" (
        "id" uuid NOT NULL DEFAULT uuid_generate_v4(),
        "userId" uuid NOT NULL,
        "platform" "platform_type" NOT NULL,
        "type" "generation_type" NOT NULL,
        "prompt" text NOT NULL,
        "inputImageUrl" character varying(500),
        "outputUrl" character varying(500),
        "thumbnailUrl" character varying(500),
        "status" "task_status" NOT NULL DEFAULT 'pending',
        "creditCost" integer NOT NULL,
        "aiModelId" character varying(100),
        "parameters" json,
        "errorMessage" text,
        "processingTime" integer,
        "createdAt" TIMESTAMP NOT NULL DEFAULT now(),
        "updatedAt" TIMESTAMP NOT NULL DEFAULT now(),
        CONSTRAINT "PK_generation_tasks_id" PRIMARY KEY ("id"),
        CONSTRAINT "FK_generation_tasks_userId" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE CASCADE
      )
    `);

    // 创建用户订阅表
    await queryRunner.query(`
      CREATE TYPE "subscription_plan" AS ENUM('basic', 'premium', 'pro')
    `);

    await queryRunner.query(`
      CREATE TYPE "subscription_status" AS ENUM('active', 'expired', 'cancelled', 'pending')
    `);

    await queryRunner.query(`
      CREATE TABLE "user_subscriptions" (
        "id" uuid NOT NULL DEFAULT uuid_generate_v4(),
        "userId" uuid NOT NULL,
        "platform" "platform_type" NOT NULL,
        "plan" "subscription_plan" NOT NULL,
        "status" "subscription_status" NOT NULL DEFAULT 'pending',
        "startDate" TIMESTAMP NOT NULL,
        "endDate" TIMESTAMP NOT NULL,
        "price" decimal(10,2) NOT NULL,
        "currency" character varying(10) NOT NULL DEFAULT 'CNY',
        "monthlyCredits" integer NOT NULL,
        "paymentId" character varying(100),
        "features" json,
        "autoRenew" boolean NOT NULL DEFAULT true,
        "createdAt" TIMESTAMP NOT NULL DEFAULT now(),
        "updatedAt" TIMESTAMP NOT NULL DEFAULT now(),
        CONSTRAINT "PK_user_subscriptions_id" PRIMARY KEY ("id"),
        CONSTRAINT "FK_user_subscriptions_userId" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE CASCADE
      )
    `);

    // 创建广告观看记录表
    await queryRunner.query(`
      CREATE TYPE "ad_type" AS ENUM('banner', 'interstitial', 'rewarded', 'native')
    `);

    await queryRunner.query(`
      CREATE TYPE "ad_status" AS ENUM('started', 'completed', 'skipped', 'failed')
    `);

    await queryRunner.query(`
      CREATE TABLE "ad_watches" (
        "id" uuid NOT NULL DEFAULT uuid_generate_v4(),
        "userId" uuid NOT NULL,
        "platform" "platform_type" NOT NULL,
        "adType" "ad_type" NOT NULL,
        "adId" character varying(100) NOT NULL,
        "adUnitId" character varying(100),
        "status" "ad_status" NOT NULL,
        "watchDuration" integer,
        "rewardCredits" integer,
        "adData" json,
        "createdAt" TIMESTAMP NOT NULL DEFAULT now(),
        "updatedAt" TIMESTAMP NOT NULL DEFAULT now(),
        CONSTRAINT "PK_ad_watches_id" PRIMARY KEY ("id"),
        CONSTRAINT "FK_ad_watches_userId" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE CASCADE
      )
    `);

    // 创建N8N模板配置表
    await queryRunner.query(`
      CREATE TABLE "n8n_templates" (
        "id" bigint NOT NULL AUTO_INCREMENT,
        "code" varchar(100) NOT NULL UNIQUE,
        "name" varchar(200) NOT NULL,
        "description" text,
        "creditCost" int NOT NULL DEFAULT 0,
        "version" varchar(50) NOT NULL,
        "inputExampleUrl" text,
        "outputExampleUrl" text,
        "tags" json,
        "templateType" enum('image', 'video') NOT NULL,
        "templateClass" varchar(100) NOT NULL,
        "imageModel" varchar(100),
        "imagePrompt" text,
        "videoModel" varchar(100),
        "videoPrompt" text,
        "duration" int,
        "aspectRatio" varchar(20),
        "isActive" boolean DEFAULT TRUE,
        "sortOrder" int DEFAULT 0,
        "createdAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        "updatedAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
        CONSTRAINT "PK_n8n_templates_id" PRIMARY KEY ("id")
      )
    `);

    // 创建模板执行记录表
    await queryRunner.query(`
      CREATE TYPE "execution_status" AS ENUM('pending', 'processing', 'completed', 'failed', 'cancelled')
    `);

    await queryRunner.query(`
      CREATE TYPE "execution_type" AS ENUM('image', 'video')
    `);

    await queryRunner.query(`
      CREATE TABLE "template_executions" (
        "id" bigint NOT NULL AUTO_INCREMENT,
        "templateId" bigint NOT NULL,
        "userId" uuid NOT NULL,
        "platform" "platform_type" NOT NULL,
        "type" "execution_type" NOT NULL,
        "prompt" text NOT NULL,
        "inputImageUrl" varchar(500),
        "outputUrl" varchar(500),
        "thumbnailUrl" varchar(500),
        "status" "execution_status" DEFAULT 'pending',
        "progress" int DEFAULT 0,
        "errorMessage" text,
        "executionResult" json,
        "creditCost" int DEFAULT 0,
        "creditTransactionId" varchar(100),
        "inputParams" json,
        "executionConfig" json,
        "startedAt" TIMESTAMP NULL,
        "completedAt" TIMESTAMP NULL,
        "executionDuration" int,
        "createdAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        "updatedAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
        CONSTRAINT "PK_template_executions_id" PRIMARY KEY ("id"),
        CONSTRAINT "FK_template_executions_templateId" FOREIGN KEY ("templateId") REFERENCES "n8n_templates"("id") ON DELETE CASCADE,
        CONSTRAINT "FK_template_executions_userId" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE CASCADE
      )
    `);

    // 创建索引
    await queryRunner.query(`CREATE INDEX "IDX_platform_users_platform" ON "platform_users" ("platform")`);
    await queryRunner.query(`CREATE INDEX "IDX_platform_users_userId" ON "platform_users" ("userId")`);
    await queryRunner.query(`CREATE INDEX "IDX_extension_data_userId" ON "extension_data" ("userId")`);
    await queryRunner.query(`CREATE INDEX "IDX_extension_data_platform" ON "extension_data" ("platform")`);
    await queryRunner.query(`CREATE INDEX "IDX_extension_data_dataType" ON "extension_data" ("dataType")`);
    await queryRunner.query(`CREATE INDEX "IDX_extension_data_referenceId" ON "extension_data" ("referenceId")`);
    await queryRunner.query(`CREATE INDEX "IDX_extension_data_status" ON "extension_data" ("status")`);
    await queryRunner.query(`CREATE INDEX "IDX_extension_data_createdAt" ON "extension_data" ("createdAt")`);

    // 用户积分表索引
    await queryRunner.query(`CREATE INDEX "IDX_user_credits_userId" ON "user_credits" ("userId")`);
    await queryRunner.query(`CREATE INDEX "IDX_user_credits_platform" ON "user_credits" ("platform")`);
    await queryRunner.query(`CREATE INDEX "IDX_user_credits_type" ON "user_credits" ("type")`);
    await queryRunner.query(`CREATE INDEX "IDX_user_credits_source" ON "user_credits" ("source")`);
    await queryRunner.query(`CREATE INDEX "IDX_user_credits_createdAt" ON "user_credits" ("createdAt")`);

    // AI生成任务表索引
    await queryRunner.query(`CREATE INDEX "IDX_generation_tasks_userId" ON "generation_tasks" ("userId")`);
    await queryRunner.query(`CREATE INDEX "IDX_generation_tasks_platform" ON "generation_tasks" ("platform")`);
    await queryRunner.query(`CREATE INDEX "IDX_generation_tasks_type" ON "generation_tasks" ("type")`);
    await queryRunner.query(`CREATE INDEX "IDX_generation_tasks_status" ON "generation_tasks" ("status")`);
    await queryRunner.query(`CREATE INDEX "IDX_generation_tasks_createdAt" ON "generation_tasks" ("createdAt")`);

    // 用户订阅表索引
    await queryRunner.query(`CREATE INDEX "IDX_user_subscriptions_userId" ON "user_subscriptions" ("userId")`);
    await queryRunner.query(`CREATE INDEX "IDX_user_subscriptions_platform" ON "user_subscriptions" ("platform")`);
    await queryRunner.query(`CREATE INDEX "IDX_user_subscriptions_status" ON "user_subscriptions" ("status")`);
    await queryRunner.query(`CREATE INDEX "IDX_user_subscriptions_endDate" ON "user_subscriptions" ("endDate")`);

    // 广告观看记录表索引
    await queryRunner.query(`CREATE INDEX "IDX_ad_watches_userId" ON "ad_watches" ("userId")`);
    await queryRunner.query(`CREATE INDEX "IDX_ad_watches_platform" ON "ad_watches" ("platform")`);
    await queryRunner.query(`CREATE INDEX "IDX_ad_watches_adType" ON "ad_watches" ("adType")`);
    await queryRunner.query(`CREATE INDEX "IDX_ad_watches_status" ON "ad_watches" ("status")`);
    await queryRunner.query(`CREATE INDEX "IDX_ad_watches_createdAt" ON "ad_watches" ("createdAt")`);

    // N8n模板表索引
    await queryRunner.query(`CREATE INDEX "IDX_n8n_templates_code" ON "n8n_templates" ("code")`);
    await queryRunner.query(`CREATE INDEX "IDX_n8n_templates_templateType" ON "n8n_templates" ("templateType")`);
    await queryRunner.query(`CREATE INDEX "IDX_n8n_templates_templateClass" ON "n8n_templates" ("templateClass")`);
    await queryRunner.query(`CREATE INDEX "IDX_n8n_templates_isActive" ON "n8n_templates" ("isActive")`);

    // 模板执行记录表索引
    await queryRunner.query(`CREATE INDEX "IDX_template_executions_templateId" ON "template_executions" ("templateId")`);
    await queryRunner.query(`CREATE INDEX "IDX_template_executions_userId" ON "template_executions" ("userId")`);
    await queryRunner.query(`CREATE INDEX "IDX_template_executions_platform" ON "template_executions" ("platform")`);
    await queryRunner.query(`CREATE INDEX "IDX_template_executions_status" ON "template_executions" ("status")`);
    await queryRunner.query(`CREATE INDEX "IDX_template_executions_type" ON "template_executions" ("type")`);
    await queryRunner.query(`CREATE INDEX "IDX_template_executions_creditTransactionId" ON "template_executions" ("creditTransactionId")`);
  }

  public async down(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.query(`DROP TABLE "template_executions"`);
    await queryRunner.query(`DROP TABLE "n8n_templates"`);
    await queryRunner.query(`DROP TABLE "ad_watches"`);
    await queryRunner.query(`DROP TABLE "user_subscriptions"`);
    await queryRunner.query(`DROP TABLE "user_credits"`);
    await queryRunner.query(`DROP TABLE "extension_data"`);
    await queryRunner.query(`DROP TABLE "platform_users"`);
    await queryRunner.query(`DROP TABLE "users"`);
    await queryRunner.query(`DROP TYPE "execution_type"`);
    await queryRunner.query(`DROP TYPE "execution_status"`);
    await queryRunner.query(`DROP TYPE "ad_status"`);
    await queryRunner.query(`DROP TYPE "ad_type"`);
    await queryRunner.query(`DROP TYPE "subscription_status"`);
    await queryRunner.query(`DROP TYPE "subscription_plan"`);
    await queryRunner.query(`DROP TYPE "credit_source"`);
    await queryRunner.query(`DROP TYPE "credit_type"`);
    await queryRunner.query(`DROP TYPE "platform_type"`);
  }
}

6. Repository模式示例

// src/repositories/user.repository.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from '../entities/user.entity';
import { PlatformUser, PlatformType } from '../entities/platform-user.entity';
import { ExtensionData } from '../entities/extension-data.entity';

@Injectable()
export class UserRepository {
  constructor(
    @InjectRepository(User)
    private readonly userRepository: Repository<User>,
    @InjectRepository(PlatformUser)
    private readonly platformUserRepository: Repository<PlatformUser>,
    @InjectRepository(ExtensionData)
    private readonly extensionDataRepository: Repository<ExtensionData>,
  ) {}

  async findByUnifiedUserId(unifiedUserId: string): Promise<User | null> {
    return this.userRepository.findOne({
      where: { unifiedUserId },
      relations: ['platformUsers', 'extensionData'],
    });
  }

  async findByPlatformUser(platform: PlatformType, platformUserId: string): Promise<User | null> {
    const platformUser = await this.platformUserRepository.findOne({
      where: { platform, platformUserId },
      relations: ['user'],
    });
    return platformUser?.user || null;
  }

  async createUser(userData: Partial<User>): Promise<User> {
    const user = this.userRepository.create(userData);
    return this.userRepository.save(user);
  }

  async createPlatformUser(platformUserData: Partial<PlatformUser>): Promise<PlatformUser> {
    const platformUser = this.platformUserRepository.create(platformUserData);
    return this.platformUserRepository.save(platformUser);
  }

  async updatePlatformUser(
    platform: PlatformType,
    platformUserId: string,
    updateData: Partial<PlatformUser>
  ): Promise<PlatformUser> {
    await this.platformUserRepository.update(
      { platform, platformUserId },
      updateData
    );
    return this.platformUserRepository.findOne({
      where: { platform, platformUserId },
    });
  }

  // 扩展数据操作方法
  async createExtensionData(extensionData: Partial<ExtensionData>): Promise<ExtensionData> {
    const data = this.extensionDataRepository.create(extensionData);
    return this.extensionDataRepository.save(data);
  }

  async findExtensionData(
    userId: string,
    dataType: string,
    platform?: PlatformType
  ): Promise<ExtensionData[]> {
    const where: any = { userId, dataType };
    if (platform) {
      where.platform = platform;
    }
    return this.extensionDataRepository.find({ where });
  }

  async updateExtensionData(
    id: string,
    updateData: Partial<ExtensionData>
  ): Promise<ExtensionData> {
    await this.extensionDataRepository.update(id, updateData);
    return this.extensionDataRepository.findOne({ where: { id } });
  }
}

API设计规范

1. 统一请求格式

interface UnifiedRequest<T = any> {
  platform: PlatformType;
  version: string;
  timestamp: number;
  signature?: string;
  data: T;
}

2. 统一响应格式

interface UnifiedResponse<T = any> {
  code: number;
  message: string;
  data: T;
  timestamp: number;
  traceId: string;
}

3. 错误码规范

  • 1000-1999: 系统级错误
  • 2000-2999: 业务级错误
  • 3000-3999: 平台特定错误
  • 4000-4999: 客户端错误
  • 5000-5999: 服务端错误

部署架构

1. 微服务部署

# docker-compose.yml 示例
version: '3.8'
services:
  api-gateway:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"

  main-service:
    build: .
    environment:
      - NODE_ENV=production
      - DB_HOST=mysql
      - DB_PORT=3306
      - DB_USERNAME=${MYSQL_USER}
      - DB_PASSWORD=${MYSQL_PASSWORD}
      - DB_DATABASE=${MYSQL_DB}
    depends_on:
      - mysql

  mysql:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_USER: ${MYSQL_USER}
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}
      MYSQL_DATABASE: ${MYSQL_DB}
    volumes:
      - mysql_data:/var/lib/mysql
    ports:
      - "3306:3306"

volumes:
  mysql_data:

2. 负载均衡配置

  • 使用Nginx作为反向代理
  • 支持多实例部署
  • 健康检查和自动故障转移

API文档配置 (Swagger/OpenAPI)

1. Swagger配置

// src/config/swagger.config.ts
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import { INestApplication } from '@nestjs/common';

export function setupSwagger(app: INestApplication): void {
  const config = new DocumentBuilder()
    .setTitle('多平台小程序统一后台API')
    .setDescription('支持微信、支付宝、百度、字节跳动等多平台的统一后台服务')
    .setVersion('1.0.0')
    .addBearerAuth(
      {
        type: 'http',
        scheme: 'bearer',
        bearerFormat: 'JWT',
        name: 'JWT',
        description: 'Enter JWT token',
        in: 'header',
      },
      'JWT-auth',
    )
    .addTag('用户管理', '用户注册、登录、信息管理')
    .addTag('平台适配', '各平台特定接口和数据同步')
    .addTag('扩展服务', '预留的扩展功能接口')
    .addServer('http://localhost:3000', '开发环境')
    .addServer('https://api.example.com', '生产环境')
    .build();

  const document = SwaggerModule.createDocument(app, config);
  SwaggerModule.setup('api/docs', app, document, {
    swaggerOptions: {
      persistAuthorization: true,
      tagsSorter: 'alpha',
      operationsSorter: 'alpha',
    },
    customSiteTitle: '多平台API文档',
    customfavIcon: '/favicon.ico',
    customJs: [
      'https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/4.15.5/swagger-ui-bundle.min.js',
      'https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/4.15.5/swagger-ui-standalone-preset.min.js',
    ],
    customCssUrl: [
      'https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/4.15.5/swagger-ui.min.css',
    ],
  });
}

2. DTO示例 (带Swagger装饰器)

// src/dto/user-login.dto.ts
import { ApiProperty } from '@nestjs/swagger';
import { IsString, IsEnum, IsOptional } from 'class-validator';
import { PlatformType } from '../entities/platform-user.entity';

export class UserLoginDto {
  @ApiProperty({
    description: '平台类型',
    enum: PlatformType,
    example: PlatformType.WECHAT,
  })
  @IsEnum(PlatformType)
  platform: PlatformType;

  @ApiProperty({
    description: '平台授权码',
    example: '081234567890abcdef',
  })
  @IsString()
  code: string;

  @ApiProperty({
    description: '加密用户数据',
    required: false,
    example: 'encrypted_user_data_string',
  })
  @IsOptional()
  @IsString()
  encryptedData?: string;

  @ApiProperty({
    description: '加密向量',
    required: false,
    example: 'iv_string',
  })
  @IsOptional()
  @IsString()
  iv?: string;
}

export class UserLoginResponseDto {
  @ApiProperty({
    description: 'JWT访问令牌',
    example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
  })
  token: string;

  @ApiProperty({
    description: '刷新令牌',
    example: 'refresh_token_string',
  })
  refreshToken: string;

  @ApiProperty({
    description: '用户信息',
    type: 'object',
    example: {
      id: 'user-uuid',
      nickname: '用户昵称',
      avatarUrl: 'https://example.com/avatar.jpg',
    },
  })
  userInfo: any;
}

3. Controller示例 (带Swagger装饰器)

// src/controllers/user.controller.ts
import { Controller, Post, Body, Get, UseGuards } from '@nestjs/common';
import {
  ApiTags,
  ApiOperation,
  ApiResponse,
  ApiBearerAuth,
  ApiBody,
} from '@nestjs/swagger';
import { UserLoginDto, UserLoginResponseDto } from '../dto/user-login.dto';
import { JwtAuthGuard } from '../guards/jwt-auth.guard';
import { CurrentUser } from '../decorators/current-user.decorator';

@ApiTags('用户管理')
@Controller('api/v1/users')
export class UserController {
  @Post('login')
  @ApiOperation({
    summary: '用户登录',
    description: '支持多平台用户登录返回JWT令牌',
  })
  @ApiBody({
    type: UserLoginDto,
    description: '登录请求参数',
  })
  @ApiResponse({
    status: 200,
    description: '登录成功',
    type: UserLoginResponseDto,
  })
  @ApiResponse({
    status: 400,
    description: '请求参数错误',
    schema: {
      type: 'object',
      properties: {
        code: { type: 'number', example: 400 },
        message: { type: 'string', example: '请求参数错误' },
        data: { type: 'null' },
      },
    },
  })
  @ApiResponse({
    status: 401,
    description: '授权失败',
    schema: {
      type: 'object',
      properties: {
        code: { type: 'number', example: 401 },
        message: { type: 'string', example: '平台授权失败' },
        data: { type: 'null' },
      },
    },
  })
  async login(@Body() loginDto: UserLoginDto) {
    return this.userService.login(loginDto);
  }

  @Get('profile')
  @UseGuards(JwtAuthGuard)
  @ApiBearerAuth('JWT-auth')
  @ApiOperation({
    summary: '获取用户信息',
    description: '获取当前登录用户的详细信息',
  })
  @ApiResponse({
    status: 200,
    description: '获取成功',
    schema: {
      type: 'object',
      properties: {
        code: { type: 'number', example: 200 },
        message: { type: 'string', example: '获取成功' },
        data: {
          type: 'object',
          properties: {
            id: { type: 'string', example: 'user-uuid' },
            nickname: { type: 'string', example: '用户昵称' },
            avatarUrl: { type: 'string', example: 'https://example.com/avatar.jpg' },
            phone: { type: 'string', example: '13800138000' },
            email: { type: 'string', example: 'user@example.com' },
          },
        },
      },
    },
  })
  @ApiResponse({
    status: 401,
    description: '未授权',
    schema: {
      type: 'object',
      properties: {
        code: { type: 'number', example: 401 },
        message: { type: 'string', example: '未授权访问' },
        data: { type: 'null' },
      },
    },
  })
  async getProfile(@CurrentUser() user: any) {
    return this.userService.getProfile(user.id);
  }
}

4. 扩展服务接口文档示例

// src/controllers/extension.controller.ts
import { Controller, Post, Body, Get, Param, Query } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse, ApiParam, ApiQuery } from '@nestjs/swagger';

@ApiTags('扩展服务')
@Controller('api/v1/extensions')
export class ExtensionController {
  @Post('data')
  @ApiOperation({
    summary: '创建扩展数据',
    description: '为用户创建扩展功能数据,支持多种数据类型',
  })
  @ApiResponse({
    status: 200,
    description: '数据创建成功',
    schema: {
      type: 'object',
      properties: {
        code: { type: 'number', example: 200 },
        message: { type: 'string', example: '数据创建成功' },
        data: {
          type: 'object',
          properties: {
            id: { type: 'string', example: 'ext_123456789' },
            userId: { type: 'string', example: 'user_123456789' },
            dataType: { type: 'string', example: 'custom' },
            referenceId: { type: 'string', example: 'ref_123456789' },
            status: { type: 'string', example: 'active' },
          },
        },
      },
    },
  })
  async createExtensionData(@Body() extensionDto: any) {
    return this.extensionService.createData(extensionDto);
  }

  @Get('data/:userId')
  @ApiOperation({
    summary: '查询用户扩展数据',
    description: '根据用户ID查询扩展数据',
  })
  @ApiParam({
    name: 'userId',
    description: '用户ID',
    example: 'user_123456789',
  })
  @ApiQuery({
    name: 'dataType',
    description: '数据类型',
    required: false,
    example: 'custom',
  })
  @ApiResponse({
    status: 200,
    description: '查询成功',
    schema: {
      type: 'object',
      properties: {
        code: { type: 'number', example: 200 },
        message: { type: 'string', example: '查询成功' },
        data: {
          type: 'array',
          items: {
            type: 'object',
            properties: {
              id: { type: 'string', example: 'ext_123456789' },
              dataType: { type: 'string', example: 'custom' },
              data: { type: 'object', description: '扩展数据内容' },
              createdAt: { type: 'string', example: '2023-12-01T10:00:00Z' },
            },
          },
        },
      },
    },
  })
  async getExtensionData(
    @Param('userId') userId: string,
    @Query('dataType') dataType?: string
  ) {
    return this.extensionService.getUserData(userId, dataType);
  }
}

5. 在main.ts中启用Swagger

// src/main.ts
import { NestFactory } from '@nestjs/core';
import { ValidationPipe } from '@nestjs/common';
import { AppModule } from './app.module';
import { setupSwagger } from './config/swagger.config';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  // 启用全局验证管道
  app.useGlobalPipes(new ValidationPipe({
    whitelist: true,
    forbidNonWhitelisted: true,
    transform: true,
  }));

  // 设置API前缀
  app.setGlobalPrefix('api/v1');

  // 启用CORS
  app.enableCors();

  // 设置Swagger文档
  setupSwagger(app);

  await app.listen(3000);

  console.log('🚀 应用启动成功!');
  console.log('📖 API文档地址: http://localhost:3000/api/docs');
}
bootstrap();

安全策略

1. 数据安全

  • 敏感数据加密存储
  • 传输过程HTTPS加密
  • 定期数据备份

2. 接口安全

  • API签名验证
  • 请求频率限制
  • IP白名单机制

3. 平台安全

  • 各平台密钥安全管理
  • 定期密钥轮换
  • 权限最小化原则

开发计划

Phase 1: 基础架构搭建 (4周)

  • 项目架构设计和技术选型
  • 基础框架搭建 (NestJS + TypeORM)
  • PostgreSQL数据库设计和初始化
  • TypeORM实体定义和迁移脚本
  • 基础中间件开发 (认证、日志、异常处理)
  • Docker容器化配置

Phase 2: 核心业务功能开发 (10周)

  • 平台识别和适配器开发
  • 用户认证服务
  • AI模板管理系统 (模板注册、参数验证、执行引擎)
  • AI提供商适配器 (Stability AI、RunwayML等)
  • 积分系统开发 (积分获取、消耗、查询)
  • 广告服务集成 (观看验证、奖励发放)
  • AI生成服务开发 (任务管理、模型调用)
  • 文件存储服务 (图片上传、结果存储)

Phase 3: 高级功能开发 (6周)

  • 订阅服务开发 (包月付费、会员权益)
  • 预定义模板开发 (换装、抠图、风格转换等)
  • 模板版本管理和回滚机制
  • 文件处理优化 (压缩、缩略图生成)
  • 任务队列优化 (失败重试、状态监控)
  • API文档完善
  • 管理后台开发 (模板管理界面)

Phase 4: 测试和优化 (3周)

  • 单元测试和集成测试
  • 性能测试和优化
  • 安全测试
  • API文档和使用指南完善

Phase 5: 部署和上线 (2周)

  • 生产环境部署
  • 基础功能验证
  • 性能调优
  • 正式上线

后续扩展计划 (按需开发)

  • 更多AI模型集成 (DALL-E、Midjourney API)
  • 高级图像处理 (风格转换、图像修复)
  • 社交功能 (作品分享、用户互动)
  • 数据分析和报表 (用户行为、生成统计)
  • 更多平台适配器 (快手、飞书等)
  • 内容审核系统 (AI生成内容安全检测)

总结

本方案为AI图片/视频生成平台提供了完整的多平台统一后台解决方案,通过模块化设计和标准化接口,既满足了当前的核心业务需求,又为未来的功能扩展预留了充分的空间。

🎯 核心业务价值

💡 AI生成能力

  • 统一模板管理: 通过模板系统抹平不同AI模型的调用差异
  • 多模态生成: 支持图片和视频生成,满足不同用户需求
  • 智能任务管理: 异步处理,支持大规模并发生成任务
  • 模型适配: 灵活对接多种AI服务提供商 (Stability AI、RunwayML等)
  • 参数验证: 完整的输入参数验证和类型转换
  • 版本管理: 支持模板版本控制和平滑升级

💰 商业模式支持

  • 积分经济: 完整的积分获取、消耗、管理体系
  • 广告变现: 多种广告类型,灵活的奖励机制
  • 订阅服务: 包月付费,会员权益管理
  • 成本控制: 基于积分的使用限制有效控制AI调用成本

🔧 技术优势

  1. 统一性: 抹平8大平台API差异和AI模型调用差异统一的开发体验
  2. 可扩展性: 模块化架构支持快速添加新功能、平台和AI模型
  3. 模板化: 通过模板系统标准化AI调用简化前端集成
  4. 高性能: PostgreSQL 数据库,支持高并发处理
  5. 数据安全: JSONB灵活存储完整的数据备份和恢复机制
  6. 异步处理: 基于数据库任务队列的异步处理,提升用户体验
  7. 类型安全: TypeScript + TypeORM编译时错误检查
  8. 智能缓存: 活跃模板缓存,提升模板执行性能