2026-01-17 12:33:11 +01:00
|
|
|
import { NextRequest, NextResponse } from 'next/server'
|
|
|
|
|
import { statsCollectionService } from '@/lib/services/stats-collection-service'
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* GET /api/cron/cleanup-stats
|
|
|
|
|
* Delete stats snapshots older than 90 days
|
|
|
|
|
*
|
|
|
|
|
* This endpoint is designed to be called by a daily cron job.
|
|
|
|
|
* It should be protected by a secret token in production.
|
|
|
|
|
*
|
|
|
|
|
* Example cron schedule: Once per day at 3am
|
|
|
|
|
* Vercel cron config in vercel.json:
|
|
|
|
|
* {
|
|
|
|
|
* "crons": [
|
|
|
|
|
* { "path": "/api/cron/cleanup-stats", "schedule": "0 3 * * *" }
|
|
|
|
|
* ]
|
|
|
|
|
* }
|
|
|
|
|
*/
|
|
|
|
|
export async function GET(request: NextRequest) {
|
feat: Audit remediation + Stripe webhook + test suites
- Apply 3 Prisma schema changes (Pending2FASession, hubApiKeyHash, SecurityVerificationCode attempts)
- Add Stripe webhook handler (checkout.session.completed -> User + Subscription + Order)
- Add stripe-service, api-key-service, rate-limit middleware
- Add security headers (CSP, HSTS, X-Frame-Options) in next.config.ts
- Harden auth routes, require ADMIN_API_KEY for orchestrator endpoints
- Add Docker auto-migration via startup.sh
- Add 7 unit test suites (api-key, dns, config-generator, automation-worker, permission, security-verification, auth-helpers)
- Fix Prisma 7 compatibility with adapter-pg mock for vitest
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-07 08:02:33 +01:00
|
|
|
// Verify cron secret
|
2026-01-17 12:33:11 +01:00
|
|
|
const cronSecret = process.env.CRON_SECRET
|
feat: Audit remediation + Stripe webhook + test suites
- Apply 3 Prisma schema changes (Pending2FASession, hubApiKeyHash, SecurityVerificationCode attempts)
- Add Stripe webhook handler (checkout.session.completed -> User + Subscription + Order)
- Add stripe-service, api-key-service, rate-limit middleware
- Add security headers (CSP, HSTS, X-Frame-Options) in next.config.ts
- Harden auth routes, require ADMIN_API_KEY for orchestrator endpoints
- Add Docker auto-migration via startup.sh
- Add 7 unit test suites (api-key, dns, config-generator, automation-worker, permission, security-verification, auth-helpers)
- Fix Prisma 7 compatibility with adapter-pg mock for vitest
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-07 08:02:33 +01:00
|
|
|
if (!cronSecret) {
|
|
|
|
|
console.error('[Cron] CRON_SECRET environment variable is not set')
|
|
|
|
|
return NextResponse.json({ error: 'Cron not configured' }, { status: 500 })
|
|
|
|
|
}
|
2026-01-17 12:33:11 +01:00
|
|
|
const authHeader = request.headers.get('authorization')
|
feat: Audit remediation + Stripe webhook + test suites
- Apply 3 Prisma schema changes (Pending2FASession, hubApiKeyHash, SecurityVerificationCode attempts)
- Add Stripe webhook handler (checkout.session.completed -> User + Subscription + Order)
- Add stripe-service, api-key-service, rate-limit middleware
- Add security headers (CSP, HSTS, X-Frame-Options) in next.config.ts
- Harden auth routes, require ADMIN_API_KEY for orchestrator endpoints
- Add Docker auto-migration via startup.sh
- Add 7 unit test suites (api-key, dns, config-generator, automation-worker, permission, security-verification, auth-helpers)
- Fix Prisma 7 compatibility with adapter-pg mock for vitest
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-07 08:02:33 +01:00
|
|
|
if (authHeader !== `Bearer ${cronSecret}`) {
|
2026-01-17 12:33:11 +01:00
|
|
|
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const startTime = Date.now()
|
|
|
|
|
const deletedCount = await statsCollectionService.cleanupOldSnapshots()
|
|
|
|
|
const duration = Date.now() - startTime
|
|
|
|
|
|
|
|
|
|
return NextResponse.json({
|
|
|
|
|
success: true,
|
|
|
|
|
message: `Cleaned up ${deletedCount} old stats snapshots`,
|
|
|
|
|
deleted: deletedCount,
|
|
|
|
|
duration: `${duration}ms`,
|
|
|
|
|
retentionDays: 90,
|
|
|
|
|
timestamp: new Date().toISOString()
|
|
|
|
|
})
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('Cron job failed - cleanup-stats:', error)
|
|
|
|
|
return NextResponse.json(
|
|
|
|
|
{
|
|
|
|
|
error: 'Stats cleanup failed',
|
|
|
|
|
message: error instanceof Error ? error.message : 'Unknown error'
|
|
|
|
|
},
|
|
|
|
|
{ status: 500 }
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Also support POST for flexibility
|
|
|
|
|
export async function POST(request: NextRequest) {
|
|
|
|
|
return GET(request)
|
|
|
|
|
}
|