refactor: 优化代码结构并修复类型问题
- 移除未使用的TabPane组件 - 修复类型定义和导入方式 - 优化mock数据源的环境变量判断逻辑 - 更新文档结构并归档旧文件 - 添加新的UI组件和Memo组件 - 调整API路径和响应处理
This commit is contained in:
286
docs/ARCH/backend.md
Normal file
286
docs/ARCH/backend.md
Normal file
@@ -0,0 +1,286 @@
|
||||
# 后端架构
|
||||
|
||||
> **入口**: [_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*
|
||||
Reference in New Issue
Block a user