# 后端架构

> **入口**: [_index.md](_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 服务模板

```typescript
/**
 * [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 权限中间件

```typescript
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 使用方式

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

---

## 6. 任务队列

### 6.1 队列定义

```typescript
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 任务添加

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

---

## 7. 错误处理

### 7.1 错误类型

```typescript
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 错误处理中间件

```typescript
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*
