Skip to content

Структура API

Ограничение частоты запросов

Стратегия: Token Bucket

Ограничение частоты запросов использует @nestjs/throttler с многоуровневыми лимитами. Для продакшн-развёртываний следует использовать Redis-адаптер для распределённого ограничения частоты между несколькими инстансами.

typescript
// nestjs-throttler с хранилищем в PostgreSQL
@Module({
  imports: [
    ThrottlerModule.forRoot({
      throttlers: [
        { name: 'short', ttl: 1000, limit: 10 },   // 10 запросов/сек
        { name: 'medium', ttl: 60000, limit: 100 }, // 100 запросов/мин
        { name: 'long', ttl: 3600000, limit: 1000 } // 1000 запросов/час
      ],
      storage: new ThrottlerStorageService() // С поддержкой БД
    })
  ]
})

Лимиты по эндпоинтам

Категория эндпоинтовЛимит
Аутентификация (вход, регистрация)5/мин
Сброс пароля3/час
Платёжные webhooks100/сек
API общий100/мин
Административные эндпоинты200/мин

Лимиты финансовых эндпоинтов

ЭндпоинтЛимит
POST /mlm/payouts/request1/мин на пользователя
POST /investment/participations3/мин на пользователя
POST /cart/checkout2/мин на пользователя
PATCH /users/me (реквизиты выплат)3/час на пользователя
POST /admin/commissions/approve10/мин на администратора
POST /admin/payouts/process5/мин на администратора

Реализация

typescript
// Кастомный декоратор для финансовых эндпоинтов
export const FinancialRateLimit = () =>
  applyDecorators(
    Throttle({ default: { limit: 1, ttl: 60000 } }), // 1 в минуту
    UseGuards(ThrottlerGuard),
  );

// Использование в контроллере
@Controller('mlm/payouts')
export class PayoutsController {
  @Post('request')
  @FinancialRateLimit()
  async requestPayout(@CurrentUser() user: User, @Body() dto: PayoutRequestDto) {
    return this.payoutService.createRequest(user.partnerId, dto);
  }
}

Ограничение частоты по пользователю

Для финансовых эндпоинтов ограничение должно быть по пользователю, а не по IP:

typescript
@Injectable()
export class UserThrottlerGuard extends ThrottlerGuard {
  protected async getTracker(req: Request): Promise<string> {
    // Использование ID пользователя для аутентифицированных запросов (предотвращает проблемы с общим IP)
    const user = req.user as AuthenticatedUser;
    if (user?.id) {
      return `user:${user.id}`;
    }
    // Fallback на IP для неаутентифицированных запросов
    return req.ip;
  }
}

Заголовки ограничения частоты

Финансовые эндпоинты включают дополнительные заголовки для прозрачности:

X-RateLimit-Limit: 1
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1705329600
X-RateLimit-Policy: financial

Ответ при превышении лимита

json
{
  "statusCode": 429,
  "message": "Too Many Requests",
  "retryAfter": 45
}

Обзор эндпоинтов

/api/v1
├── /auth
│   ├── POST /register
│   ├── POST /login
│   ├── POST /refresh
│   ├── POST /logout
│   └── POST /2fa/*

├── /users
│   ├── GET /me
│   ├── PATCH /me
│   └── /kyc/*

├── /investment
│   ├── GET /strategies
│   ├── GET /strategies/:id
│   ├── POST /participations
│   ├── GET /participations
│   └── GET /portfolio

├── /products
│   ├── GET /
│   ├── GET /:id
│   ├── GET /categories
│   └── POST /reviews

├── /cart
│   ├── GET /
│   ├── POST /items
│   ├── PATCH /items/:id
│   ├── DELETE /items/:id
│   └── POST /checkout

├── /orders
│   ├── GET /
│   ├── GET /:id
│   └── GET /:id/tracking

├── /mlm
│   ├── /partner
│   │   ├── GET /me
│   │   ├── GET /network
│   │   └── GET /network/stats
│   │
│   ├── /referrals
│   │   ├── GET /links
│   │   ├── POST /links
│   │   └── GET /links/:id/stats
│   │
│   ├── /commissions
│   │   ├── GET /
│   │   ├── GET /summary
│   │   └── GET /history
│   │
│   ├── /ranks
│   │   ├── GET /current
│   │   ├── GET /progress
│   │   └── GET /history
│   │
│   └── /payouts
│       ├── GET /balance
│       ├── POST /request
│       └── GET /history

└── /admin  (Суперадминистратор)
    ├── /users/*
    ├── /partners/*
    ├── /commissions/*
    ├── /products/*
    ├── /strategies/*
    └── /analytics/*

Связанные документы