---
description: NestJS 后端开发规范和最佳实践
globs: ["**/server/**/*", "**/api/**/*", "**/*.controller.ts", "**/*.service.ts"]
alwaysApply: false
---

# NestJS 开发规范

## 🏗️ 模块与依赖注入

### 服务定义规范
```typescript
// ✅ 所有服务必须使用 @Injectable() 装饰器
import { Injectable, Logger } from '@nestjs/common';

@Injectable()
export class UserService {
  private readonly logger = new Logger(UserService.name);
  
  constructor(
    private readonly userRepository: IUserRepository,
    private readonly emailService: IEmailService,
  ) {}
  
  async createUser(createUserDto: CreateUserDto): Promise<IUser> {
    this.logger.log(`开始创建用户: ${createUserDto.email}`);
    
    try {
      const user = await this.userRepository.save(createUserDto);
      await this.emailService.sendWelcomeEmail(user.email);
      
      this.logger.log(`用户创建成功: ${user.id}`);
      return user;
    } catch (error) {
      this.logger.error(`创建用户失败: ${error.message}`, error.stack);
      throw error;
    }
  }
}

// ❌ 错误示例 - 缺少 @Injectable()
export class UserService {
  constructor(private readonly userRepository: IUserRepository) {}
}
```

### 控制器规范
```typescript
// ✅ 控制器与服务依赖通过构造函数注入
import { Controller, Post, Body, Get, Param } from '@nestjs/common';
import { UserService } from './user.service';
import { CreateUserDto } from './dto/create-user.dto';

@Controller('users')
export class UserController {
  constructor(private readonly userService: UserService) {}
  
  @Post()
  async createUser(@Body() createUserDto: CreateUserDto): Promise<IUser> {
    return this.userService.createUser(createUserDto);
  }
  
  @Get(':id')
  async getUser(@Param('id') id: string): Promise<IUser> {
    return this.userService.findById(id);
  }
}

// ❌ 错误示例 - 使用属性注入
@Controller('users')
export class UserController {
  @Inject() private userService: UserService;
}
```

### 模块定义规范
```typescript
// ✅ 模块定义必须明确指定 providers、imports、controllers
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { UserController } from './user.controller';
import { UserService } from './user.service';
import { User } from './entities/user.entity';

@Module({
  imports: [
    TypeOrmModule.forFeature([User]),
  ],
  providers: [UserService],
  controllers: [UserController],
  exports: [UserService], // 导出供其他模块使用
})
export class UserModule {}
```

## ⚡ 性能优化装饰器

### 缓存装饰器
```typescript
// ✅ 使用 @Cacheable 装饰器缓存频繁访问的数据库查询
import { Cacheable } from '@nestjs/cache';

@Injectable()
export class UserService {
  @Cacheable({
    key: (userId: string) => `user:${userId}`,
    ttl: 30000, // 30秒缓存
  })
  async findById(userId: string): Promise<IUser | null> {
    return this.userRepository.findById(userId);
  }
  
  @Cacheable({
    key: () => 'all-users',
    ttl: 60000, // 1分钟缓存
  })
  async findAll(): Promise<IUser[]> {
    return this.userRepository.findAll();
  }
}
```

### 批量处理装饰器
```typescript
// ✅ 使用 @BatchProcess 装饰器处理批量操作
import { BatchProcess } from '@nestjs/batch';

@Injectable()
export class OrderService {
  @BatchProcess({ 
    chunkSize: 100, 
    delay: 100,
    concurrency: 5 
  })
  async processOrders(orders: Order[]): Promise<void> {
    // 批量处理订单逻辑
    for (const order of orders) {
      await this.processOrder(order);
    }
  }
  
  private async processOrder(order: Order): Promise<void> {
    // 单个订单处理逻辑
  }
}
```

## 🔒 安全与验证

### 认证授权
```typescript
// ✅ 使用 @nestjs/auth + JWT 实现认证授权
import { UseGuards } from '@nestjs/common';
import { JwtAuthGuard } from './guards/jwt-auth.guard';
import { RolesGuard } from './guards/roles.guard';
import { Roles } from './decorators/roles.decorator';

@Controller('users')
@UseGuards(JwtAuthGuard, RolesGuard)
export class UserController {
  @Get('admin')
  @Roles('admin')
  getAdminData() {
    return { message: '管理员专用数据' };
  }
  
  @Get('profile')
  getProfile(@Request() req) {
    return req.user;
  }
}
```

### 输入验证
```typescript
// ✅ 使用 ValidationPipe 验证请求体
import { IsEmail, IsString, MinLength, IsOptional } from 'class-validator';

export class CreateUserDto {
  @IsEmail()
  email: string;

  @IsString()
  @MinLength(8)
  password: string;

  @IsString()
  @IsOptional()
  firstName?: string;

  @IsString()
  @IsOptional()
  lastName?: string;
}

// ✅ 全局验证管道配置
import { ValidationPipe } from '@nestjs/common';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  
  app.useGlobalPipes(new ValidationPipe({
    whitelist: true, // 移除未定义的属性
    forbidNonWhitelisted: true, // 禁止未定义的属性
    transform: true, // 自动类型转换
  }));
  
  await app.listen(3000);
}
```

## 🗄️ 数据库集成

### TypeORM 实体定义
```typescript
// ✅ 实体定义规范
import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn } from 'typeorm';

@Entity('users')
export class User {
  @PrimaryGeneratedColumn('uuid')
  id: string;

  @Column({ unique: true })
  email: string;

  @Column()
  password: string;

  @Column({ nullable: true })
  firstName: string;

  @Column({ nullable: true })
  lastName: string;

  @Column({ default: 'user' })
  role: string;

  @CreateDateColumn()
  createdAt: Date;

  @UpdateDateColumn()
  updatedAt: Date;
}
```

### Repository 模式
```typescript
// ✅ Repository 接口定义
export interface IUserRepository {
  findById(id: string): Promise<User | null>;
  findByEmail(email: string): Promise<User | null>;
  findAll(): Promise<User[]>;
  save(user: User): Promise<User>;
  update(id: string, updates: Partial<User>): Promise<User>;
  delete(id: string): Promise<void>;
}

// ✅ Repository 实现
@Injectable()
export class UserRepository implements IUserRepository {
  constructor(
    @InjectRepository(User)
    private readonly repository: Repository<User>,
  ) {}

  async findById(id: string): Promise<User | null> {
    return this.repository.findOne({ where: { id } });
  }

  async findByEmail(email: string): Promise<User | null> {
    return this.repository.findOne({ where: { email } });
  }

  async findAll(): Promise<User[]> {
    return this.repository.find();
  }

  async save(user: User): Promise<User> {
    return this.repository.save(user);
  }

  async update(id: string, updates: Partial<User>): Promise<User> {
    await this.repository.update(id, updates);
    return this.findById(id);
  }

  async delete(id: string): Promise<void> {
    await this.repository.delete(id);
  }
}
```