smithery/fortiumpartners

NestJS Framework

Node.js/TypeScript backend framework with dependency injection and modular architecture

Installation

$ npx skills add smithery/fortiumpartners --skill nestjs-framework

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from smithery/fortiumpartners · top by installs.

npx skills add smithery/fortiumpartners

Browse all from smithery/fortiumpartners

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Skill metadata

Parsed from SKILL.md frontmatter.

Version1.0.0

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 13,114 B
  • docs SUMMARY.md 111 B

History

  1. First recorded snapshot · 0 installs

SKILL.md

NestJS Framework Skill

Quick Reference

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%

Essential Patterns

Module Architecture

// 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:

  • Clear module boundaries and responsibilities
  • Export only what other modules need
  • Import shared modules (AuthModule, DatabaseModule)
  • Use token-based providers for abstraction

Dependency Injection

// 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:

  • Use constructor injection for all dependencies
  • Inject interfaces/tokens, not concrete implementations
  • Keep services focused on single responsibility
  • Emit events for cross-cutting concerns

DTO Validation

// users/dto/create-user.dto.ts
export class CreateUserDto {
  @ApiProperty({ example: '[email protected]' })
  @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:

  • All inputs validated with class-validator decorators
  • API documentation via @ApiProperty
  • Custom error messages for user clarity
  • Optional fields with @IsOptional()

Repository Pattern

// 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:

  • Encapsulate all database operations
  • Throw domain-specific exceptions
  • Use TypeORM query builder for complex queries
  • Keep repositories focused on data access only

Controller Best Practices

// 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:

  • @ApiTags for logical grouping
  • @ApiOperation for endpoint description
  • @ApiResponse for status codes + types
  • ValidationPipe for DTO validation
  • Guards for authentication/authorization
  • Transform responses with DTOs

Authentication & Authorization

// 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:

  • JWT strategy with Passport.js
  • Role-based access control with custom decorators
  • Guard composition for complex rules
  • Secure password hashing (bcrypt, argon2)

Exception Handling

// 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:

  • Global exception filter for consistency
  • Domain-specific exceptions (UserNotFoundException)
  • Include correlation IDs for debugging
  • Log errors with appropriate severity

Testing

// 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: '[email protected]', 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: '[email protected]', password: 'Pass123!' };
      repository.findByEmail.mockResolvedValue({ id: 1 });

      await expect(service.createUser(dto)).rejects.toThrow(ConflictException);
    });
  });
});

Test Strategy:

  • Unit tests for services (≥80% coverage)
  • Integration tests for repositories
  • E2E tests for critical workflows (≥60% coverage)
  • Mock external dependencies
  • Test error paths and edge cases

Common Anti-Patterns

❌ Don't: Tight Coupling

// Bad: Direct dependency on implementation
@Injectable()
export class UserService {
  async createUser(email: string, password: string) {
    const hashed = await bcrypt.hash(password, 10); // Tight coupling!
    // ...
  }
}

✅ Do: Abstraction

// 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);
    // ...
  }
}

❌ Don't: No Input Validation

// Bad: No validation, any type
@Post()
async create(@Body() body: any) {
  return this.service.create(body);
}

✅ Do: DTO Validation

// Good: Strong typing + validation
@Post()
async create(@Body(ValidationPipe) dto: CreateUserDto): Promise<UserResponseDto> {
  return this.service.create(dto);
}

❌ Don't: Expose Sensitive Data

// Bad: Returns password field!
@Get(':id')
async findOne(@Param('id') id: string) {
  return this.userService.findOne(id); // Contains password
}

✅ Do: Transform Responses

// 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
}

Performance Patterns

Caching

@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;
  }
}

Background Jobs

// 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 });

Query Optimization

// 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'],
});

Integration Checklist

  • Module properly structured with clear boundaries
  • All dependencies injected via constructor
  • DTOs with class-validator decorators
  • Repository pattern for data access
  • Guards for authentication/authorization
  • Exception filters for consistent errors
  • OpenAPI/Swagger documentation
  • Unit tests ≥80% coverage
  • Integration tests for API endpoints
  • E2E tests for critical paths
  • Caching for frequently accessed data
  • Background jobs for async operations
  • Health check endpoint

Quick Commands

# 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

See Also

  • [REFERENCE.md](./REFERENCE.md) - Comprehensive guide with microservices, GraphQL, advanced patterns
  • [templates/](./templates/) - Code generation templates
  • [examples/](./examples/) - Real-world implementation examples