/** * Admin-triggered storage migration. Same code path as `scripts/migrate-storage.ts` * (both delegate to `runMigration()` in `@/lib/storage/migrate`). Body: * { from: 's3'|'filesystem', to: 's3'|'filesystem', dryRun?: boolean } * * Super-admin only. The `/[portSlug]/admin` segment is already gated; this * route enforces the same constraint defensively. */ import { NextResponse } from 'next/server'; import { z } from 'zod'; import { withAuth } from '@/lib/api/helpers'; import { parseBody } from '@/lib/api/route-helpers'; import { errorResponse, ForbiddenError } from '@/lib/errors'; import { runMigration } from '@/lib/storage/migrate'; const schema = z.object({ from: z.enum(['s3', 'filesystem']), to: z.enum(['s3', 'filesystem']), dryRun: z.boolean().default(false), }); export const runtime = 'nodejs'; export const POST = withAuth(async (req, ctx) => { try { if (!ctx.isSuperAdmin) { throw new ForbiddenError('Super admin only'); } const body = await parseBody(req, schema); if (body.from === body.to) { return NextResponse.json({ error: 'from and to must differ' }, { status: 400 }); } const result = await runMigration({ ...body, userId: ctx.userId }); return NextResponse.json({ data: result }); } catch (error) { return errorResponse(error); } });