From df10f45e9e06b767cd2766389aed80be51b4ba56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yusuf=20=C4=B0pek?= Date: Fri, 10 Apr 2026 21:48:25 +0300 Subject: [PATCH] feat(onboarding): implement rate limiting for onboarding completion --- app/api/onboarding/complete/route.ts | 10 ++++++++++ lib/rate-limit.ts | 3 +++ 2 files changed, 13 insertions(+) diff --git a/app/api/onboarding/complete/route.ts b/app/api/onboarding/complete/route.ts index 46eba41..f796e3e 100644 --- a/app/api/onboarding/complete/route.ts +++ b/app/api/onboarding/complete/route.ts @@ -1,6 +1,7 @@ import { auth } from '@/lib/auth'; import { db } from '@/lib/db'; import { apiErrors, successResponse } from '@/lib/api-response'; +import { checkRateLimit, rateLimitHeaders, RATE_LIMIT_CONFIGS } from '@/lib/rate-limit'; export async function POST() { const session = await auth(); @@ -8,6 +9,15 @@ export async function POST() { return apiErrors.unauthorized(); } + const cfg = RATE_LIMIT_CONFIGS['onboarding-complete']; + const rl = await checkRateLimit(session.user.id, 'onboarding-complete', cfg); + if (!rl.allowed) { + return new Response( + JSON.stringify({ error: 'Too many requests. Please try again later.' }), + { status: 429, headers: { 'Content-Type': 'application/json', ...rateLimitHeaders(rl, cfg.maxRequests) } } + ); + } + await db.user.update({ where: { id: session.user.id }, data: { onboardingCompletedAt: new Date() }, diff --git a/lib/rate-limit.ts b/lib/rate-limit.ts index 2c06f55..b633b6f 100644 --- a/lib/rate-limit.ts +++ b/lib/rate-limit.ts @@ -70,6 +70,9 @@ export const RATE_LIMIT_CONFIGS: Record = { 'video-download': { windowMs: 60 * 1000, maxRequests: 8 }, // 8 per minute 'video-download-prepare': { windowMs: 60 * 1000, maxRequests: 5 }, // 5 per minute + // Onboarding — one-time action, very strict + 'onboarding-complete': { windowMs: 60 * 60 * 1000, maxRequests: 5 }, // 5 per hour + // Member management 'invite-member': { windowMs: 60 * 60 * 1000, maxRequests: 30 }, // 30 per hour 'manage-member': { windowMs: 60 * 1000, maxRequests: 20 }, // 20 per minute