# Next.js Upload Guardrail

Scan browser uploads in a Next.js Route Handler before storage, OCR, extraction, or review.

Source URL: https://trymighty.ai/docs/frameworks/next-file-upload

## Goal

Use this page when a browser uploads a file to your Next.js app.

This page proves one product flow:

```text
browser upload -> Next.js server route -> Mighty scan -> store, quarantine, or reject
```

The point is not Next.js itself. The point is keeping the API key server-side and making sure files are scanned before storage, OCR, AI extraction, or review queues trust them.

## When To Use This

Use it for:

- Claim packet uploads.
- Invoice or repair estimate uploads.
- Damage photos uploaded through a web form.
- Support attachments.
- Any file that will later go to OCR, AI extraction, search, or workflow automation.

## Architecture

1. Browser posts the file to your Next.js route.
2. The route forwards the file to Mighty with server-side auth.
3. Mighty returns `ALLOW`, `WARN`, or `BLOCK`.
4. The route stores, quarantines, or rejects the file.
5. Downstream OCR or AI only runs after routing.

## Route Handler

```ts
export const runtime = "nodejs";

export async function POST(request: Request) {
  const incoming = await request.formData();
  const file = incoming.get("file");

  if (!(file instanceof File)) {
    return Response.json({ error: "file is required" }, { status: 400 });
  }

  const mightyForm = new FormData();
  mightyForm.append("file", file);
  mightyForm.append("content_type", "auto");
  mightyForm.append("scan_phase", "input");
  mightyForm.append("mode", "secure");
  mightyForm.append("focus", "both");
  mightyForm.append("data_sensitivity", "tolerant");

  const scanResponse = await fetch("https://gateway.trymighty.ai/v1/scan", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.MIGHTY_API_KEY}`,
    },
    body: mightyForm,
  });

  if (!scanResponse.ok) {
    return Response.json(
      { error: "upload scan failed" },
      { status: scanResponse.status },
    );
  }

  const scan = await scanResponse.json();

  if (scan.action === "BLOCK") {
    return Response.json(
      { error: "upload blocked", scan_id: scan.scan_id },
      { status: 400 },
    );
  }

  if (scan.action === "WARN") {
    await saveUploadForReview(file, scan);
    return Response.json({ status: "review", scan_id: scan.scan_id });
  }

  await saveUploadForProcessing(file, scan);
  return Response.json({ status: "accepted", scan_id: scan.scan_id });
}
```

## Routing Logic

```ts
async function saveUploadForReview(file: File, scan: { scan_id: string }) {
  // Store in quarantine or a restricted bucket.
}

async function saveUploadForProcessing(file: File, scan: { scan_id: string }) {
  // Store normally and enqueue OCR or extraction.
}
```

## Common Mistake

Do not call Mighty directly from the browser. The upload route should proxy the file so your API key stays server-side.

Do not store first and scan later unless the storage location is quarantine-only. The safer default is scan first, then store normally only after routing.

## Acceptance Criteria

- Missing file returns `400`.
- Mighty `BLOCK` prevents normal storage.
- Mighty `WARN` stores to review or quarantine.
- Mighty `ALLOW` stores and continues processing.
- Logs include `scan_id`.

## AI-Agent Prompt

### Add a Next.js upload guardrail

```text
Add Mighty to a Next.js App Router upload endpoint.

Requirements:
- Use runtime=nodejs.
- Parse request.formData().
- Require a file field.
- Forward the file to POST https://gateway.trymighty.ai/v1/scan with multipart form data.
- Use content_type=auto, scan_phase=input, mode=secure, focus=both, data_sensitivity=tolerant.
- Route BLOCK to reject or quarantine.
- Route WARN to quarantine and review.
- Route ALLOW to normal storage and processing.
- Store scan_id and scan_group_id with the upload record.

Acceptance criteria:
- API key only exists server-side.
- Tests cover missing file, ALLOW, WARN, BLOCK, and Mighty error status.
```
