| name | geo-nestjs-patterns |
| description | GEO系统 NestJS 开发模式和最佳实践。用于创建控制器、服务、实体时遵循项目规范。触发词:GEO系统, NestJS, 控制器, 服务, 实体, TypeORM, 认证, 权限, RBAC。 |
| license | MIT |
GEO系统 NestJS 开发模式
本 Skill 包含 GEO系统 的标准开发模式,确保代码风格一致性和安全性。
项目架构
packages/
├── api/ # NestJS 后端 (端口 3001)
│ ├── src/
│ │ ├── entities/ # TypeORM 实体
│ │ ├── modules/ # 功能模块
│ │ └── services/ # 共享服务
│ └── data/ # SQLite 数据库
└── web/ # React 前端 (端口 3000)
角色权限体系 (RBAC)
export enum UserRole {
USER = "user",
PROVIDER = "provider",
REVIEWER = "reviewer",
ADMIN = "admin",
SUPER_ADMIN = "super_admin",
}
权限层级
- SUPER_ADMIN: 全部权限,包括修改系统模板、管理所有用户
- ADMIN: 用户管理、平台审核、数据统计
- REVIEWER: 平台审核
- PROVIDER: 提交平台、管理自己的资源
- USER: 使用工具、管理自己的数据
控制器模式 (Controller)
标准控制器结构
import {
Controller,
Get,
Post,
Put,
Delete,
Body,
Param,
Query,
UseGuards,
ForbiddenException,
NotFoundException,
} from "@nestjs/common";
import { JwtAuthGuard } from "../auth/guards/jwt-auth.guard";
import { RolesGuard } from "../auth/guards/roles.guard";
import { Roles } from "../auth/decorators/roles.decorator";
import { CurrentUser } from "../auth/decorators/current-user.decorator";
import { User, UserRole } from "../../entities/user.entity";
@Controller("resource")
@UseGuards(JwtAuthGuard)
export class ResourceController {
constructor(private readonly resourceService: ResourceService) {}
@Get()
async findAll(@CurrentUser() user: User) {
return {
success: true,
data: await this.resourceService.findAll(user.id),
};
}
@Get(":id")
async findOne(@Param("id") id: string, @CurrentUser() user: User) {
const resource = await this.resourceService.findOne(id);
if (resource.userId && resource.userId !== user.id) {
throw new ForbiddenException("无权访问此资源");
}
return { success: true, data: resource };
}
@Get("admin/all")
@UseGuards(RolesGuard)
@Roles(UserRole.ADMIN, UserRole.SUPER_ADMIN)
async findAllAdmin() {
return { success: true, data: await this.resourceService.findAllAdmin() };
}
}
API 响应格式
return {
success: true,
data: result,
message: "操作成功",
};
return {
success: true,
data: items,
total: count,
page: page,
limit: limit,
};
throw new NotFoundException("资源不存在");
throw new ForbiddenException("无权操作");
throw new BadRequestException("参数错误");
服务模式 (Service)
标准服务结构
import {
Injectable,
NotFoundException,
ForbiddenException,
} from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { Repository } from "typeorm";
import { Resource } from "../../entities/resource.entity";
@Injectable()
export class ResourceService {
constructor(
@InjectRepository(Resource)
private resourceRepository: Repository<Resource>,
) {}
async findAll(userId: string): Promise<Resource[]> {
return this.resourceRepository.find({
where: { userId },
order: { createdAt: "DESC" },
});
}
async create(dto: CreateDto, userId: string): Promise<Resource> {
const entity = this.resourceRepository.create({
...dto,
userId,
});
return this.resourceRepository.save(entity);
}
async update(id: string, dto: UpdateDto, userId: string): Promise<Resource> {
const entity = await this.resourceRepository.findOne({ where: { id } });
if (!entity) {
throw new NotFoundException("资源不存在");
}
if (entity.userId !== userId) {
throw new ForbiddenException("无权修改此资源");
}
Object.assign(entity, dto);
return this.resourceRepository.save(entity);
}
async remove(id: string, userId: string): Promise<void> {
const entity = await this.resourceRepository.findOne({ where: { id } });
if (!entity) {
throw new NotFoundException("资源不存在");
}
if (entity.userId !== userId) {
throw new ForbiddenException("无权删除此资源");
}
await this.resourceRepository.delete(id);
}
}
实体模式 (Entity)
标准实体结构
import {
Entity,
Column,
PrimaryGeneratedColumn,
CreateDateColumn,
UpdateDateColumn,
ManyToOne,
JoinColumn,
} from "typeorm";
import { User } from "./user.entity";
@Entity("resources")
export class Resource {
@PrimaryGeneratedColumn("uuid")
id: string;
@Column()
name: string;
@Column({ nullable: true })
description: string;
@Column({ nullable: true })
userId: string;
@ManyToOne(() => User, { onDelete: "CASCADE" })
@JoinColumn({ name: "userId" })
user: User;
@Column({ default: false })
isSystem: boolean;
@CreateDateColumn()
createdAt: Date;
@UpdateDateColumn()
updatedAt: Date;
}
枚举定义
export enum ResourceStatus {
DRAFT = 'draft',
ACTIVE = 'active',
ARCHIVED = 'archived',
}
@Column({
type: 'varchar',
default: ResourceStatus.DRAFT,
})
status: ResourceStatus;
JSON 字段
@Column({ type: 'simple-json', nullable: true })
metadata: Record<string, any>;
@Column({ type: 'simple-array', nullable: true })
tags: string[];
模块注册
标准模块结构
import { Module } from "@nestjs/common";
import { TypeOrmModule } from "@nestjs/typeorm";
import { ResourceController } from "./resource.controller";
import { ResourceService } from "./resource.service";
import { Resource } from "../../entities/resource.entity";
@Module({
imports: [TypeOrmModule.forFeature([Resource])],
controllers: [ResourceController],
providers: [ResourceService],
exports: [ResourceService],
})
export class ResourceModule {}
在 AppModule 注册
@Module({
imports: [
TypeOrmModule.forRoot({
entities: [Resource],
}),
ResourceModule,
],
})
export class AppModule {}
安全模式
认证守卫使用
@Controller('resource')
@UseGuards(JwtAuthGuard)
export class ResourceController {}
@Post()
@UseGuards(JwtAuthGuard)
async create() {}
@Delete(':id')
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles(UserRole.ADMIN, UserRole.SUPER_ADMIN)
async remove() {}
系统资源保护
async update(id: string, dto: UpdateDto, isSuperAdmin: boolean): Promise<Resource> {
const entity = await this.findOne(id);
if (entity.isSystem && !isSuperAdmin) {
throw new ForbiddenException('只有超级管理员可以修改系统资源');
}
}
输入验证 (DTO)
import {
IsString,
IsOptional,
IsEnum,
MinLength,
MaxLength,
} from "class-validator";
export class CreateResourceDto {
@IsString()
@MinLength(2)
@MaxLength(100)
name: string;
@IsOptional()
@IsString()
@MaxLength(500)
description?: string;
@IsOptional()
@IsEnum(ResourceStatus)
status?: ResourceStatus;
}
错误处理
使用 NestJS 异常类
import {
NotFoundException,
BadRequestException,
ForbiddenException,
UnauthorizedException,
ConflictException,
} from "@nestjs/common";
throw new NotFoundException("用户不存在");
throw new ForbiddenException("无权访问此资源");
throw new BadRequestException("邮箱格式不正确");
throw new Error("用户不存在");
数据库查询
TypeORM 常用查询
const items = await this.repository.find({
where: { userId, status: "active" },
order: { createdAt: "DESC" },
take: 10,
skip: 0,
});
const item = await this.repository.findOne({
where: { id },
relations: ["user", "category"],
});
const items = await this.repository
.createQueryBuilder("r")
.where("r.userId = :userId", { userId })
.andWhere("r.status = :status", { status: "active" })
.leftJoinAndSelect("r.user", "user")
.orderBy("r.createdAt", "DESC")
.getMany();
const count = await this.repository.count({ where: { userId } });
const exists = await this.repository.exist({ where: { email } });
检查清单
新功能开发
安全检查