L3 Auftragsimport: Prüfmaske, Upload, API und Lane-Bericht

- /imports: Upload per Drag & Drop/Dateiauswahl mit Fortschritt, Liste mit Status, Neu verarbeiten
- /imports/[id]: Originaldokument + Prüfmaske (Kunde, Objekt, Ansprechpartner, Auftrag, Positionen),
  unsichere Felder markiert, Kunden-/Objektentscheidung, Bestätigen/Verwerfen
- Datei-Route für die Vorschau, Server Actions (moduleGuard("imports"))
- API: POST /api/v1/work-orders/import, GET /api/v1/imports/[id], POST /api/v1/imports/[id]/confirm
- Texte messages/{de,en}/imports.json, Bericht docs/craftvia/lanes/import.md

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-14 12:21:15 +02:00
co-authored by Claude Opus 5
parent 12a764786a
commit cf012d40c2
16 changed files with 1612 additions and 3 deletions
@@ -0,0 +1,22 @@
import { confirmImport } from "@/server/services/imports/confirm";
import { apiError, importsApiContext } from "../../_context";
/**
* POST /api/v1/imports/[id]/confirm — JSON body = review form (src/lib/imports/review.ts
* `reviewFormSchema`). Creates/assigns customer, site, contact and the work order. Lane L3.
*/
export async function POST(req: Request, { params }: { params: Promise<{ id: string }> }) {
try {
const ctx = await importsApiContext("import:write", "work_order:write");
const { id } = await params;
let body: unknown;
try {
body = await req.json();
} catch {
return Response.json({ error: "invalid", message: "json_required" }, { status: 400 });
}
return Response.json(await confirmImport(ctx, id, body));
} catch (err) {
return apiError(err);
}
}
+13
View File
@@ -0,0 +1,13 @@
import { getImportDetail } from "@/server/services/imports/queries";
import { apiError, importsApiContext } from "../_context";
/** GET /api/v1/imports/[id] — import status, extraction (with confidences), candidates. Lane L3. */
export async function GET(_req: Request, { params }: { params: Promise<{ id: string }> }) {
try {
const ctx = await importsApiContext("import:write");
const { id } = await params;
return Response.json(await getImportDetail(ctx, id));
} catch (err) {
return apiError(err);
}
}