147 lines
3.2 KiB
Plaintext
147 lines
3.2 KiB
Plaintext
---
|
||
description: 后端工程师规范 - API、Service、Repository 分层架构
|
||
alwaysApply: false
|
||
---
|
||
|
||
# 后端工程师规范
|
||
|
||
## 一、分层架构(必须遵循)
|
||
|
||
```
|
||
API Route → Service → Repository → Database
|
||
↓ ↓
|
||
Cache DTO
|
||
```
|
||
|
||
---
|
||
|
||
## 二、API 路由规范
|
||
|
||
### 正确写法
|
||
```typescript
|
||
export async function GET(request: NextRequest) {
|
||
return handleRequest(request, async (ctx) => {
|
||
const data = await xxxService.getXxx(ctx)
|
||
return jsonSuccess(data)
|
||
})
|
||
}
|
||
```
|
||
|
||
### 禁止写法
|
||
```typescript
|
||
// ❌ 禁止在 API 中直接写 Prisma
|
||
export async function GET(request: NextRequest) {
|
||
const data = await prisma.xxx.findMany() // 禁止!
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 三、Service 层规范
|
||
|
||
### 职责
|
||
1. 调用 Repository 获取数据
|
||
2. 业务逻辑处理
|
||
3. 权限检查
|
||
4. 缓存读写
|
||
5. 转换为 DTO
|
||
|
||
### 模板
|
||
```typescript
|
||
async getXxx(ctx: ServiceContext): Promise<XxxDTO> {
|
||
// 1. 检查缓存
|
||
const cached = await this.cache.get(CacheKeys.xxx(id))
|
||
if (cached) return cached
|
||
|
||
// 2. 调用 Repository
|
||
const entity = await this.repository.findById(id)
|
||
|
||
// 3. 权限检查
|
||
this.checkPermission(entity, ctx.user)
|
||
|
||
// 4. 转换 DTO
|
||
const dto = toXxxDTO(entity)
|
||
|
||
// 5. 写入缓存
|
||
await this.cache.set(CacheKeys.xxx(id), dto, CACHE_TTL.MEDIUM)
|
||
|
||
return dto
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 四、Repository 层规范
|
||
|
||
### 职责
|
||
只负责数据访问,不含业务逻辑
|
||
|
||
### 模板
|
||
```typescript
|
||
async findById(id: string): Promise<Entity | null> {
|
||
return this.prisma.xxx.findUnique({ where: { id, deletedAt: null } })
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 五、必须使用的工具
|
||
|
||
| 工具 | 用途 | 示例 |
|
||
|------|------|------|
|
||
| `handleRequest` | 统一请求处理 | `handleRequest(request, async (ctx) => {...})` |
|
||
| `jsonSuccess` | 成功响应 | `return jsonSuccess(data)` |
|
||
| `jsonError` | 错误响应 | `return jsonError(error)` |
|
||
| `AppError` | 抛出错误 | `throw new AppError(ErrorCode.XXX_NOT_FOUND)` |
|
||
| `CacheKeys` | 缓存键管理 | `CacheKeys.product(id)` |
|
||
| `$transaction` | 事务处理 | `prisma.$transaction(async (tx) => {...})` |
|
||
|
||
---
|
||
|
||
## 六、API 响应格式
|
||
|
||
| 操作类型 | 格式 |
|
||
|----------|------|
|
||
| 列表查询 | `{ items: [], pagination: { page, limit, total, hasMore } }` |
|
||
| 详情/创建/更新 | `{ data: {...} }` |
|
||
| 删除 | `{ success: true }` |
|
||
| 错误 | `{ error: { code, message } }` |
|
||
|
||
---
|
||
|
||
## 七、目录结构
|
||
|
||
```
|
||
src/server/
|
||
├── core/ # 响应、错误码、常量
|
||
├── repositories/ # 数据访问层
|
||
├── services/ # 业务逻辑层
|
||
├── dto/ # 数据传输对象
|
||
├── validators/ # 输入验证(Zod)
|
||
└── cache/ # 缓存层
|
||
```
|
||
|
||
---
|
||
|
||
## 八、事务处理
|
||
|
||
多表操作必须使用事务:
|
||
|
||
```typescript
|
||
const result = await prisma.$transaction(async (tx) => {
|
||
const product = await tx.product.create({ data: {...} })
|
||
const panels = await tx.panel.createMany({ data: [...] })
|
||
return { product, panels }
|
||
})
|
||
```
|
||
|
||
---
|
||
|
||
## 九、缓存策略
|
||
|
||
| 数据类型 | TTL | 失效策略 |
|
||
|---------|-----|---------|
|
||
| 用户信息 | 5分钟 | 更新时失效 |
|
||
| 产品详情 | 5分钟 | 更新/删除时失效 |
|
||
| 产品列表 | 2分钟 | 任何变更失效 |
|