library-picturebook-activity/.cursor/rules/backend-architecture.mdc
aid 418aa57ea8 Day4: 超管端设计优化 + UGC绘本创作社区P0实现
一、超管端设计优化
- 文档管理SOP体系建立,docs目录重组
- 统一用户管理:跨租户全局视角,合并用户管理+公众用户
- 活动监管全模块重构:全部活动(统计卡片+阶段筛选+SuperDetail详情页)、报名数据/作品数据/评审进度(两层合一扁平列表)、成果发布(去Tab+统计+隐藏写操作)
- 菜单精简:移除评委管理/评审规则/通知管理
- Bug修复:租户编辑丢失隐藏菜单、pageSize限制、主色统一

二、UGC绘本创作社区P0
- 数据库:10张新表(user_works/user_work_pages/work_tags等)
- 子女账号独立化:Child升级为独立User,家长切换+独立登录
- 用户作品库:CRUD+发布审核,8个API
- AI创作流程:提交→生成→保存到作品库,4个API
- 作品广场:首页改造为推荐流,标签+搜索+排序
- 内容审核(超管端):作品审核+作品管理+标签管理
- 活动联动:WorkSelector作品选择器
- 布局改造:底部5Tab(发现/创作/活动/作品库/我的)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 22:20:25 +08:00

222 lines
4.6 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
description: NestJS 后端架构规范和模块结构
globs:
- "backend/**/*.ts"
alwaysApply: false
---
# 后端架构规范
## 模块结构
每个功能模块应包含:
- `module.ts` - 模块定义
- `controller.ts` - 控制器
- `service.ts` - 服务层
- `dto/` - 数据传输对象目录
### 命名规范
- 模块命名使用复数形式:`users`, `roles`, `contests`
- 子模块放在父模块目录下:`contests/works/`, `contests/teams/`
### 目录结构示例
```
src/
├── contests/
│ ├── contests.module.ts
│ ├── contests/
│ │ ├── contests.module.ts
│ │ ├── contests.controller.ts
│ │ ├── contests.service.ts
│ │ └── dto/
│ ├── works/
│ │ ├── works.module.ts
│ │ ├── works.controller.ts
│ │ ├── works.service.ts
│ │ └── dto/
│ └── teams/
│ └── ...
```
## 服务层 (Service)
### 基本规范
- 使用 `@Injectable()` 装饰器
- 构造函数注入依赖,使用 `private readonly`
- 所有数据库操作通过 PrismaService
- **禁止直接使用 SQL**
### 标准方法命名
- `create` - 创建
- `findAll` - 查询列表(支持分页)
- `findOne` - 查询单个
- `update` - 更新
- `remove` - 删除(软删除或级联)
### 示例
```typescript
@Injectable()
export class UsersService {
constructor(private readonly prisma: PrismaService) {}
async create(createDto: CreateUserDto, tenantId: number) {
return this.prisma.user.create({
data: {
...createDto,
tenantId,
},
});
}
async findAll(tenantId: number, skip?: number, take?: number) {
return this.prisma.user.findMany({
where: { tenantId, validState: 1 },
skip,
take,
include: {
roles: {
include: { role: true },
},
},
});
}
}
```
## 控制器层 (Controller)
### 基本规范
- 使用 `@Controller()` 装饰器,路径使用复数形式
- 所有路由默认需要认证(除非使用 `@Public()` 装饰器)
- 使用 REST 风格的 HTTP 方法装饰器
### 装饰器使用
```typescript
@Controller("users")
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Post()
@RequirePermission("user:create")
async create(
@Body() createDto: CreateUserDto,
@CurrentTenantId() tenantId: number,
@CurrentUser() user: any
) {
return this.usersService.create(createDto, tenantId);
}
@Get()
@RequirePermission("user:read")
async findAll(
@CurrentTenantId() tenantId: number,
@Query("skip") skip?: number,
@Query("take") take?: number
) {
return this.usersService.findAll(tenantId, skip, take);
}
@Public()
@Get("public-info")
async getPublicInfo() {
return { version: "1.0.0" };
}
}
```
### 常用装饰器
- `@CurrentTenantId()` - 获取当前租户ID
- `@CurrentUser()` - 获取当前用户信息
- `@RequirePermission('module:action')` - 权限检查
- `@Public()` - 公开接口,无需认证
## DTO 规范
### 命名规范
- 创建:`CreateXxxDto`
- 更新:`UpdateXxxDto`
- 查询:`QueryXxxDto`
### 验证规则
使用 `class-validator` 装饰器:
```typescript
import {
IsString,
IsEmail,
IsOptional,
IsArray,
IsNumber,
} from "class-validator";
export class CreateUserDto {
@IsString()
username: string;
@IsString()
password: string;
@IsString()
nickname: string;
@IsEmail()
@IsOptional()
email?: string;
@IsArray()
@IsNumber({}, { each: true })
@IsOptional()
roleIds?: number[];
}
```
## 错误处理
使用 NestJS 内置异常,消息使用中文:
```typescript
import {
NotFoundException,
BadRequestException,
UnauthorizedException,
ForbiddenException,
} from "@nestjs/common";
// 示例
if (!user) {
throw new NotFoundException("用户不存在");
}
if (!isValid) {
throw new BadRequestException("数据验证失败");
}
```
## 权限控制
权限字符串格式:`模块:操作`
```typescript
@RequirePermission('contest:create') // 创建竞赛
@RequirePermission('user:update') // 更新用户
@RequirePermission('role:delete') // 删除角色
```
## 代码风格
- 导入顺序NestJS 核心 → 第三方库 → 本地模块
- 使用 async/await避免 Promise.then()
- 使用解构赋值提高代码可读性
- 复杂逻辑必须添加注释