원클릭으로
nestjs-framework
Node.js/TypeScript backend framework with dependency injection and modular architecture
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Node.js/TypeScript backend framework with dependency injection and modular architecture
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Multi-signal framework detection with confidence scoring for 6 major frameworks
Execute and generate ExUnit tests for Elixir projects with setup callbacks, describe blocks, and async testing support
Automatically detect test frameworks (Jest, pytest, RSpec, xUnit) in projects by analyzing configuration files and dependencies
Execute and generate pytest tests for Python projects with fixtures, parametrization, and mocking support
Execute and generate RSpec tests for Ruby projects with let bindings, before hooks, and mocking support
Execute and generate xUnit tests for C#/.NET projects with FluentAssertions and Moq support
| name | NestJS Framework |
| version | 1.0.0 |
| framework_versions | {"min":"8.0.0","max":"11.x","recommended":"10.4.0"} |
| compatible_agents | {"backend-developer":">=3.0.0","tech-lead-orchestrator":">=2.5.0"} |
| description | Node.js/TypeScript backend framework with dependency injection and modular architecture |
| frameworks | ["nestjs"] |
| languages | ["typescript","javascript"] |
| category | backend |
| updated | "2025-10-22T00:00:00.000Z" |
When to Use: Building scalable Node.js/TypeScript backend applications with modular architecture
Core Strengths: Dependency injection, modular design, enterprise patterns, comprehensive testing
Target Coverage: Services ≥80%, Controllers ≥70%, E2E ≥60%, Overall ≥75%
// users/users.module.ts
@Module({
imports: [TypeOrmModule.forFeature([User]), AuthModule],
controllers: [UserController],
providers: [
UserService,
UserRepository,
{ provide: 'USER_REPOSITORY', useClass: UserRepository },
],
exports: [UserService],
})
export class UsersModule {}
Key Principles:
// users/services/user.service.ts
@Injectable()
export class UserService {
constructor(
@Inject('USER_REPOSITORY') private readonly userRepository: UserRepository,
private readonly hashingService: HashingService,
private readonly eventEmitter: EventEmitter2,
) {}
async createUser(dto: CreateUserDto): Promise<User> {
const hashedPassword = await this.hashingService.hash(dto.password);
const user = await this.userRepository.create({
...dto,
password: hashedPassword,
});
this.eventEmitter.emit('user.created', user);
return user;
}
}
Best Practices:
// users/dto/create-user.dto.ts
export class CreateUserDto {
@ApiProperty({ example: 'john@example.com' })
@IsEmail({}, { message: 'Invalid email format' })
email: string;
@ApiProperty({ example: 'StrongP@ss123', minLength: 8 })
@IsString()
@MinLength(8)
@Matches(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])/, {
message: 'Password must contain uppercase, lowercase, number, symbol'
})
password: string;
@ApiProperty({ example: 'John Doe', required: false })
@IsOptional()
@MaxLength(100)
name?: string;
}
Validation Rules:
// users/repositories/user.repository.ts
@Injectable()
export class UserRepository {
constructor(
@InjectRepository(User) private readonly repository: Repository<User>
) {}
async findByEmail(email: string): Promise<User | null> {
return this.repository.findOne({ where: { email } });
}
async findById(id: number): Promise<User> {
const user = await this.repository.findOne({ where: { id } });
if (!user) throw new NotFoundException('User not found');
return user;
}
async create(data: Partial<User>): Promise<User> {
const user = this.repository.create(data);
return this.repository.save(user);
}
}
Repository Guidelines:
// users/controllers/user.controller.ts
@ApiTags('users')
@Controller('users')
@UseInterceptors(ClassSerializerInterceptor)
export class UserController {
constructor(private readonly userService: UserService) {}
@Post()
@HttpCode(HttpStatus.CREATED)
@ApiOperation({ summary: 'Create new user' })
@ApiResponse({ status: 201, type: UserResponseDto })
@ApiResponse({ status: 400, description: 'Validation failed' })
async create(
@Body(ValidationPipe) dto: CreateUserDto
): Promise<UserResponseDto> {
const user = await this.userService.create(dto);
return plainToInstance(UserResponseDto, user);
}
@Get(':id')
@UseGuards(JwtAuthGuard)
@ApiParam({ name: 'id', type: 'number' })
async findOne(
@Param('id', ParseIntPipe) id: number
): Promise<UserResponseDto> {
const user = await this.userService.findById(id);
return plainToInstance(UserResponseDto, user);
}
}
Controller Checklist:
// auth/guards/jwt-auth.guard.ts
@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {
handleRequest(err, user, info) {
if (err || !user) {
throw new UnauthorizedException('Invalid or expired token');
}
return user;
}
}
// auth/guards/roles.guard.ts
@Injectable()
export class RolesGuard implements CanActivate {
constructor(private reflector: Reflector) {}
canActivate(context: ExecutionContext): boolean {
const requiredRoles = this.reflector.get<Role[]>('roles', context.getHandler());
if (!requiredRoles) return true;
const request = context.switchToHttp().getRequest();
const user = request.user;
return requiredRoles.some(role => user.roles?.includes(role));
}
}
// Usage in controller
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles(Role.ADMIN)
@Delete(':id')
async delete(@Param('id') id: number): Promise<void> {
await this.userService.delete(id);
}
Auth Patterns:
// common/filters/http-exception.filter.ts
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
const status = exception.getStatus();
const exceptionResponse = exception.getResponse();
response.status(status).json({
statusCode: status,
timestamp: new Date().toISOString(),
path: ctx.getRequest().url,
message: typeof exceptionResponse === 'string'
? exceptionResponse
: (exceptionResponse as any).message,
});
}
}
// Usage in main.ts
app.useGlobalFilters(new HttpExceptionFilter());
Error Strategy:
// users/services/user.service.spec.ts
describe('UserService', () => {
let service: UserService;
let repository: MockType<UserRepository>;
let hashingService: MockType<HashingService>;
beforeEach(async () => {
const module = await Test.createTestingModule({
providers: [
UserService,
{
provide: 'USER_REPOSITORY',
useFactory: mockRepository,
},
{
provide: HashingService,
useFactory: mockHashingService,
},
],
}).compile();
service = module.get<UserService>(UserService);
repository = module.get('USER_REPOSITORY');
hashingService = module.get(HashingService);
});
describe('createUser', () => {
it('should hash password and create user', async () => {
const dto = { email: 'test@test.com', password: 'Pass123!' };
const hashedPassword = 'hashed_password';
hashingService.hash.mockResolvedValue(hashedPassword);
repository.findByEmail.mockResolvedValue(null);
repository.create.mockResolvedValue({ id: 1, ...dto, password: hashedPassword });
const result = await service.createUser(dto);
expect(hashingService.hash).toHaveBeenCalledWith(dto.password);
expect(repository.create).toHaveBeenCalledWith({
...dto,
password: hashedPassword,
});
expect(result.id).toBe(1);
});
it('should throw ConflictException if user exists', async () => {
const dto = { email: 'test@test.com', password: 'Pass123!' };
repository.findByEmail.mockResolvedValue({ id: 1 });
await expect(service.createUser(dto)).rejects.toThrow(ConflictException);
});
});
});
Test Strategy:
// Bad: Direct dependency on implementation
@Injectable()
export class UserService {
async createUser(email: string, password: string) {
const hashed = await bcrypt.hash(password, 10); // Tight coupling!
// ...
}
}
// Good: Depend on abstraction
@Injectable()
export class UserService {
constructor(private readonly hashingService: HashingService) {}
async createUser(dto: CreateUserDto) {
const hashed = await this.hashingService.hash(dto.password);
// ...
}
}
// Bad: No validation, any type
@Post()
async create(@Body() body: any) {
return this.service.create(body);
}
// Good: Strong typing + validation
@Post()
async create(@Body(ValidationPipe) dto: CreateUserDto): Promise<UserResponseDto> {
return this.service.create(dto);
}
// Bad: Returns password field!
@Get(':id')
async findOne(@Param('id') id: string) {
return this.userService.findOne(id); // Contains password
}
// Good: Use response DTO with @Exclude()
@Get(':id')
@UseInterceptors(ClassSerializerInterceptor)
async findOne(@Param('id', ParseIntPipe) id: number): Promise<UserResponseDto> {
const user = await this.userService.findById(id);
return plainToInstance(UserResponseDto, user); // Excludes password
}
@Injectable()
export class UserService {
constructor(
@Inject(CACHE_MANAGER) private cacheManager: Cache,
private userRepository: UserRepository,
) {}
async findById(id: number): Promise<User> {
const cacheKey = `user:${id}`;
const cached = await this.cacheManager.get<User>(cacheKey);
if (cached) return cached;
const user = await this.userRepository.findById(id);
await this.cacheManager.set(cacheKey, user, 3600); // 1 hour TTL
return user;
}
}
// users/processors/email.processor.ts
@Processor('email')
export class EmailProcessor {
@Process('welcome')
async sendWelcomeEmail(job: Job<{ email: string; name: string }>) {
const { email, name } = job.data;
await this.emailService.sendWelcome(email, name);
}
}
// In service
await this.emailQueue.add('welcome', { email: user.email, name: user.name });
// Bad: N+1 query problem
const users = await this.repository.find();
for (const user of users) {
user.orders = await this.orderRepository.findByUserId(user.id);
}
// Good: Use relations
const users = await this.repository.find({
relations: ['orders'],
});
# Generate resources
nest g module users
nest g controller users
nest g service users
# Generate complete CRUD
nest g resource users
# Run tests
npm run test # Unit tests
npm run test:e2e # E2E tests
npm run test:cov # Coverage report
# Build and run
npm run build
npm run start:dev # Watch mode
npm run start:prod # Production