Files
goodgo-platform/apps/api/src/modules/shared/infrastructure/index.ts
Ho Ngoc Hai 3be66f72df feat(listings): rate limit feature-listing via @nestjs/throttler (TEC-2930)
- Wire ThrottlerModule to a Redis-backed storage (shared across API
  instances) using @nest-lab/throttler-storage-redis.
- Add FeatureListingThrottlerGuard that tracks per-user when JWT is
  present, falling back to the real client IP behind the reverse proxy —
  keeps per-user and per-IP buckets independent.
- Apply @Throttle({ default: { limit: 10, ttl: 60_000 } }) + the guard
  to POST /listings/:id/feature and document 429 in Swagger.
- Integration test (feature-listing-throttle.integration.spec.ts)
  verifies: 10 reqs pass / 11th returns 429 with Retry-After, separate
  IPs keep their own quotas, and the tracker key logic.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-20 08:31:26 +07:00

43 lines
2.1 KiB
TypeScript

export { Cacheable, type CacheableOptions } from './decorators/cacheable.decorator';
export { CircuitBreaker, CircuitOpenError, CircuitState, type CircuitBreakerOptions } from './circuit-breaker';
export { encryptField, decryptField, isEncrypted, type FieldEncryptionConfig } from './field-encryption';
export {
FieldEncryptionService,
PII_FIELD_MAP,
type EncryptionKeyConfig,
type ModelEncryptionConfig,
type ModelEncryptionFieldConfig,
} from './field-encryption.service';
export { createEncryptionExtension } from './encryption-middleware';
export { PrismaService } from './prisma.service';
export { RedisService } from './redis.service';
export { RedisIoAdapter } from './redis-io.adapter';
export { CacheService, CachePrefix, CacheTTL } from './cache.service';
export { LoggerService } from './logger.service';
export { EventBusService } from './event-bus.service';
export { GlobalExceptionFilter } from './filters/global-exception.filter';
export { CorrelationIdMiddleware } from './middleware/correlation-id.middleware';
export { RequestLoggingMiddleware } from './middleware/request-logging.middleware';
export { SanitizeInputMiddleware } from './middleware/sanitize-input.middleware';
export { CsrfMiddleware } from './middleware/csrf.middleware';
export { maskPii } from './pii-masker';
export { ThrottlerBehindProxyGuard } from './guards/throttler-behind-proxy.guard';
export { FeatureListingThrottlerGuard } from './guards/feature-listing-throttler.guard';
export {
UserRateLimitGuard,
DEFAULT_ROLE_LIMITS,
DEFAULT_WINDOW_SECONDS,
USER_RATE_LIMIT_KEY,
type UserRateLimitOptions,
} from './guards/user-rate-limit.guard';
export { UserRateLimit } from './decorators/user-rate-limit.decorator';
export {
EndpointRateLimit,
ENDPOINT_RATE_LIMIT_KEY,
type EndpointRateLimitOptions,
} from './decorators/endpoint-rate-limit.decorator';
export { EndpointRateLimitGuard } from './guards/endpoint-rate-limit.guard';
export { FileValidationPipe } from './pipes/file-validation.pipe';
export type { FileValidationOptions, UploadedFile } from './pipes/file-validation.pipe';
export { validateEnv, validateJwtSecret } from './env-validation';