Files
makemd/docs/ARCH/backend.md
wurenzhi 2b86715c09 refactor: 优化代码结构并修复类型问题
- 移除未使用的TabPane组件
- 修复类型定义和导入方式
- 优化mock数据源的环境变量判断逻辑
- 更新文档结构并归档旧文件
- 添加新的UI组件和Memo组件
- 调整API路径和响应处理
2026-03-23 12:41:35 +08:00

7.1 KiB

后端架构

入口: _index.md


1. 技术栈

技术 版本 用途
Node.js 18.x 运行时
Express 4.x Web框架
TypeScript 5.x 类型系统
Knex.js 3.x 数据库ORM
Redis 6.x 缓存/队列
BullMQ 4.x 任务队列

2. 目录结构

server/src/
├── api/                # API层
│   ├── routes/         # 路由定义
│   ├── controllers/    # 控制器
│   └── middlewares/    # 中间件
├── services/           # 服务层
│   ├── ProductService.ts
│   ├── OrderService.ts
│   └── ...
├── models/             # 数据模型
├── repositories/       # 数据访问层
├── core/               # 核心模块
│   ├── connectors/     # 平台连接器
│   └── orchestrator/   # 编排器
├── utils/              # 工具函数
├── types/              # 类型定义
└── config/             # 配置文件

3. 分层架构

┌─────────────────────────────────────────────────────────────┐
│                      API层 (Controller)                     │
│  - 请求处理                                                  │
│  - 参数校验                                                  │
│  - 权限检查                                                  │
└─────────────────────────┬───────────────────────────────────┘
                          │
                          ↓
┌─────────────────────────────────────────────────────────────┐
│                     服务层 (Service)                        │
│  - 业务逻辑                                                  │
│  - 事务管理                                                  │
│  - 状态流转                                                  │
└─────────────────────────┬───────────────────────────────────┘
                          │
                          ↓
┌─────────────────────────────────────────────────────────────┐
│                   数据访问层 (Repository)                   │
│  - 数据库操作                                                │
│  - 缓存操作                                                  │
│  - 外部API调用                                               │
└─────────────────────────────────────────────────────────────┘

4. 服务层设计

4.1 服务模板

/**
 * [BE-P001] 商品服务
 * @description 商品主数据管理
 */
export class ProductService {
  private static TABLE_NAME = 'cf_product';

  static async list(params: ListParams): Promise<Product[]> {
    const query = db(this.TABLE_NAME)
      .where('tenant_id', params.tenantId);

    if (params.status) {
      query.where('status', params.status);
    }

    return query;
  }

  static async get(id: string): Promise<Product | null> {
    return db(this.TABLE_NAME).where({ id }).first();
  }

  static async create(data: CreateProductRequest): Promise<Product> {
    const [product] = await db(this.TABLE_NAME)
      .insert({
        ...data,
        id: generateId(),
        created_at: new Date(),
        updated_at: new Date(),
      })
      .returning('*');

    return product;
  }

  static async update(id: string, data: UpdateProductRequest): Promise<Product> {
    const [product] = await db(this.TABLE_NAME)
      .where({ id })
      .update({
        ...data,
        updated_at: new Date(),
      })
      .returning('*');

    return product;
  }
}

4.2 服务命名规范

后缀 说明 示例
Service 业务服务 ProductService
Repository 数据访问 ProductRepository
Connector 平台连接 ShopifyConnector
Orchestrator 编排器 PublishOrchestrator

5. 中间件

5.1 权限中间件

export const authorize = (permission: string) => {
  return async (ctx: Context, next: Next) => {
    const { user } = ctx.state;

    if (!user) {
      throw new UnauthorizedError('未登录');
    }

    const hasPermission = await checkPermission(user, permission);
    if (!hasPermission) {
      throw new ForbiddenError('无权限');
    }

    await next();
  };
};

5.2 使用方式

router.get(
  '/api/v1/products',
  authorize('product:read'),
  ProductController.list
);

6. 任务队列

6.1 队列定义

import { Queue, Worker } from 'bullmq';

export const collectionQueue = new Queue('collection', {
  connection: redis,
});

export const collectionWorker = new Worker(
  'collection',
  async (job) => {
    const { platform, shopId, type } = job.data;
    
    // 执行采集任务
    const result = await CollectionAdapterService.executeCollectionTask(
      platform,
      shopId,
      type
    );
    
    return result;
  },
  { connection: redis, concurrency: 10 }
);

6.2 任务添加

await collectionQueue.add('collect-products', {
  platform: 'SHOPIFY',
  shopId: 'shop-001',
  type: 'product',
});

7. 错误处理

7.1 错误类型

export class AppError extends Error {
  constructor(
    public code: string,
    public message: string,
    public statusCode: number = 500
  ) {
    super(message);
  }
}

export class ValidationError extends AppError {
  constructor(message: string) {
    super('VAL_INVALID_PARAM', message, 400);
  }
}

export class UnauthorizedError extends AppError {
  constructor(message: string) {
    super('AUTH_UNAUTHORIZED', message, 401);
  }
}

export class ForbiddenError extends AppError {
  constructor(message: string) {
    super('AUTH_FORBIDDEN', message, 403);
  }
}

export class NotFoundError extends AppError {
  constructor(message: string) {
    super('BIZ_NOT_FOUND', message, 404);
  }
}

7.2 错误处理中间件

export const errorHandler = async (ctx: Context, next: Next) => {
  try {
    await next();
  } catch (error) {
    if (error instanceof AppError) {
      ctx.status = error.statusCode;
      ctx.body = {
        success: false,
        error: {
          code: error.code,
          message: error.message,
        },
      };
    } else {
      ctx.status = 500;
      ctx.body = {
        success: false,
        error: {
          code: 'SYS_INTERNAL_ERROR',
          message: '内部服务器错误',
        },
      };
    }
  }
};

最后更新: 2026-03-22