workspace-v1/shared/catalog/rate-limiting/IMPLEMENTATION.md
rckrdmrd cb4c0681d3 feat(workspace): Add new projects and update architecture
New projects created:
- michangarrito (marketplace mobile)
- template-saas (SaaS template)
- clinica-dental (dental ERP)
- clinica-veterinaria (veterinary ERP)

Architecture updates:
- Move catalog from core/ to shared/
- Add MCP servers structure and templates
- Add git management scripts
- Update SUBREPOSITORIOS.md with 15 new repos
- Update .gitignore for new projects

Repository infrastructure:
- 4 main repositories
- 11 subrepositorios
- Gitea remotes configured

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-07 04:43:28 -06:00

402 lines
8.1 KiB
Markdown

# Guía de Implementación: Rate Limiting
**Versión:** 1.0.0
**Tiempo estimado:** 30 min - 1 hora
**Complejidad:** Baja
---
## Pre-requisitos
- [ ] Proyecto NestJS existente
- [ ] (Opcional) Redis para producción
---
## Paso 1: Instalar Dependencias
```bash
npm install @nestjs/throttler
# Para producción con Redis (opcional)
npm install @nestjs/throttler-storage-redis redis
```
---
## Paso 2: Configurar Módulo
### Opción A: Configuración Simple
```typescript
// src/app.module.ts
import { Module } from '@nestjs/common';
import { ThrottlerModule, ThrottlerGuard } from '@nestjs/throttler';
import { APP_GUARD } from '@nestjs/core';
@Module({
imports: [
ThrottlerModule.forRoot([{
ttl: 60000, // 60 segundos
limit: 100, // 100 requests por minuto
}]),
],
providers: [
{
provide: APP_GUARD,
useClass: ThrottlerGuard,
},
],
})
export class AppModule {}
```
### Opción B: Configuración con Ambiente
```typescript
// src/app.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { ThrottlerModule, ThrottlerGuard } from '@nestjs/throttler';
import { APP_GUARD } from '@nestjs/core';
@Module({
imports: [
ConfigModule.forRoot(),
ThrottlerModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (config: ConfigService) => ([{
ttl: config.get<number>('THROTTLE_TTL', 60000),
limit: config.get<number>('THROTTLE_LIMIT', 100),
}]),
}),
],
providers: [
{
provide: APP_GUARD,
useClass: ThrottlerGuard,
},
],
})
export class AppModule {}
```
---
## Paso 3: Variables de Entorno
```env
# .env
THROTTLE_TTL=60000
THROTTLE_LIMIT=100
```
---
## Paso 4: Personalizar por Endpoint
### Limitar endpoint específico
```typescript
// src/modules/auth/controllers/auth.controller.ts
import { Controller, Post, Body } from '@nestjs/common';
import { Throttle } from '@nestjs/throttler';
@Controller('auth')
export class AuthController {
// Solo 5 intentos de login por minuto
@Throttle({ default: { limit: 5, ttl: 60000 } })
@Post('login')
async login(@Body() dto: LoginDto) {
return this.authService.login(dto);
}
// Solo 3 registros por hora (anti-spam)
@Throttle({ default: { limit: 3, ttl: 3600000 } })
@Post('register')
async register(@Body() dto: RegisterDto) {
return this.authService.register(dto);
}
}
```
### Excluir endpoint del rate limiting
```typescript
import { SkipThrottle } from '@nestjs/throttler';
@Controller('health')
export class HealthController {
@SkipThrottle()
@Get()
check() {
return { status: 'ok' };
}
}
```
---
## Paso 5: Rate Limiting por Usuario (Opcional)
```typescript
// src/common/guards/custom-throttler.guard.ts
import { Injectable, ExecutionContext } from '@nestjs/common';
import { ThrottlerGuard } from '@nestjs/throttler';
@Injectable()
export class CustomThrottlerGuard extends ThrottlerGuard {
protected async getTracker(req: Record<string, any>): Promise<string> {
// Si hay usuario autenticado, limitar por usuario
if (req.user?.id) {
return `user-${req.user.id}`;
}
// Si no, limitar por IP
return req.ip;
}
// Opcional: Personalizar mensaje de error
protected throwThrottlingException(): void {
throw new HttpException(
{
statusCode: 429,
message: 'Demasiadas solicitudes. Intente de nuevo más tarde.',
error: 'Too Many Requests',
},
HttpStatus.TOO_MANY_REQUESTS,
);
}
}
```
Registrar en app.module.ts:
```typescript
providers: [
{
provide: APP_GUARD,
useClass: CustomThrottlerGuard, // En lugar de ThrottlerGuard
},
],
```
---
## Paso 6: Múltiples Límites (Opcional)
```typescript
// src/app.module.ts
ThrottlerModule.forRoot([
{
name: 'short',
ttl: 1000, // 1 segundo
limit: 3, // Máximo 3 por segundo (anti-DDoS básico)
},
{
name: 'medium',
ttl: 10000, // 10 segundos
limit: 20, // Máximo 20 por 10 segundos
},
{
name: 'long',
ttl: 60000, // 1 minuto
limit: 100, // Máximo 100 por minuto
},
])
```
Usar en endpoint:
```typescript
@Throttle({
short: { limit: 1, ttl: 1000 },
long: { limit: 10, ttl: 60000 },
})
@Post('heavy-operation')
async heavyOperation() {
// ...
}
```
---
## Paso 7: Redis para Producción (Opcional)
```bash
npm install @nestjs/throttler-storage-redis ioredis
```
```typescript
// src/app.module.ts
import { ThrottlerStorageRedisService } from '@nestjs/throttler-storage-redis';
import Redis from 'ioredis';
ThrottlerModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (config: ConfigService) => ({
throttlers: [{
ttl: config.get('THROTTLE_TTL', 60000),
limit: config.get('THROTTLE_LIMIT', 100),
}],
storage: new ThrottlerStorageRedisService(
new Redis({
host: config.get('REDIS_HOST', 'localhost'),
port: config.get('REDIS_PORT', 6379),
password: config.get('REDIS_PASSWORD'),
}),
),
}),
})
```
Variables de entorno adicionales:
```env
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=
```
---
## Paso 8: Logging de Rate Limits (Opcional)
```typescript
// src/common/guards/throttler-logger.guard.ts
import { Injectable, ExecutionContext, Logger } from '@nestjs/common';
import { ThrottlerGuard } from '@nestjs/throttler';
@Injectable()
export class ThrottlerLoggerGuard extends ThrottlerGuard {
private readonly logger = new Logger('RateLimit');
protected async handleRequest(
context: ExecutionContext,
limit: number,
ttl: number,
throttler: any,
getTracker: any,
generateKey: any,
): Promise<boolean> {
const result = await super.handleRequest(
context,
limit,
ttl,
throttler,
getTracker,
generateKey,
);
if (!result) {
const req = context.switchToHttp().getRequest();
this.logger.warn(
`Rate limit exceeded: ${req.ip} - ${req.method} ${req.url}`,
);
}
return result;
}
}
```
---
## Configuraciones Recomendadas
### Desarrollo
```typescript
ThrottlerModule.forRoot([{
ttl: 60000,
limit: 1000, // Alto para no molestar durante desarrollo
}])
```
### Producción
```typescript
ThrottlerModule.forRoot([
{ name: 'short', ttl: 1000, limit: 10 },
{ name: 'long', ttl: 60000, limit: 100 },
])
```
### Por tipo de endpoint
| Tipo | Límite Recomendado |
|------|-------------------|
| Login | 5 por minuto |
| Registro | 3 por hora |
| API pública | 100 por minuto |
| API autenticada | 1000 por minuto |
| Operaciones costosas | 10 por minuto |
| Webhooks | Sin límite (SkipThrottle) |
| Health check | Sin límite (SkipThrottle) |
---
## Checklist de Implementación
- [ ] @nestjs/throttler instalado
- [ ] ThrottlerModule configurado en AppModule
- [ ] ThrottlerGuard registrado como APP_GUARD
- [ ] Variables de entorno configuradas
- [ ] Límites ajustados para endpoints críticos (login, register)
- [ ] Endpoints públicos excluidos (health, webhooks)
- [ ] Redis configurado (producción)
- [ ] Build pasa sin errores
- [ ] Test manual: verificar respuesta 429
---
## Verificar Funcionamiento
```bash
# Test simple con curl
for i in {1..10}; do curl -s -o /dev/null -w "%{http_code}\n" http://localhost:3000/api/test; done
# Debería mostrar 200 hasta el límite, luego 429
```
---
## Troubleshooting
### Error: "ThrottlerModule is not imported"
Asegurarse de importar `ThrottlerModule.forRoot()` en AppModule.
### Rate limiting no funciona
Verificar que `ThrottlerGuard` esté registrado como `APP_GUARD`.
### 429 en todos los requests
El límite es muy bajo. Aumentar `limit` en configuración.
### Memory leaks en producción
Usar Redis como storage en lugar de memoria.
---
## Código de Referencia
Estructura típica:
```
src/
├── app.module.ts # ThrottlerModule configurado
├── common/
│ └── guards/
│ └── custom-throttler.guard.ts # Guard personalizado
└── modules/
└── auth/
└── controllers/
└── auth.controller.ts # @Throttle en endpoints
```
---
**Versión:** 1.0.0
**Sistema:** SIMCO Catálogo