Files
craftvia/src/app/api/v1/work-orders/[id]/route.ts
T
msolarczekandClaude Opus 5 fb993a7730 L10b Betrieb & Aufräumen: /api/v1 über gemeinsamen Adapter, einheitliches Fehlerformat, Rate Limiting
Aufräumpunkt a: Die lane-lokalen API-Kontexte (imports/_context.ts, sync/api-context.ts,
reports/http.ts, work-orders/_http.ts mit moduleGuard) sind entfernt. Alle v1-Routen laufen über
requireApiContext (DB-autoritative Rechte, 401/403) und withApi/toErrorResponse (respond.ts):
- Fehlerformat überall { error: { code, message, details? } }; invalid und blocked → 422,
  conflict → 409, payload_too_large → 413, rate_limited → 429 + Retry-After.
- Same-Origin-Prüfung in withApi für jede Mutation vor der Anmeldung (vorher fehlte sie bei
  imports, reports und work-orders).
- Rate Limiting je Nutzer mit rate-limit.ts: api (API_RATE_LIMIT_PER_MINUTE, 300/min) und
  apiField für sync/uploads/field (API_FIELD_RATE_LIMIT_PER_MINUTE, 1200/min).
- Clients angepasst: Import-Uploader liest das neue Fehlerformat, Upload/Outbox werten 422 als
  endgültig ungültig (429 bleibt transient mit Backoff).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 18:19:19 +02:00

26 lines
1.4 KiB
TypeScript

import type { UpdateWorkOrderInput } from "@/lib/work-orders/schemas";
import { requireApiContext } from "@/server/api/context";
import { json, optionalVersion, readJsonObject, withApi } from "@/server/api/respond";
import { computeCompletionBlockers } from "@/server/services/work-orders/completion";
import { availableTransitions, getWorkOrderDetail } from "@/server/services/work-orders/detail";
import { updateWorkOrder } from "@/server/services/work-orders/update";
type Params = { params: Promise<{ id: string }> };
/** GET /api/v1/work-orders/[id] — detail incl. transitions available to the caller and completion blockers. */
export const GET = withApi(async (_req: Request, { params }: Params) => {
const ctx = await requireApiContext("work_orders");
const { id } = await params;
const wo = await getWorkOrderDetail(ctx, id);
const blockers = await computeCompletionBlockers(ctx, id);
return json({ workOrder: wo, availableTransitions: availableTransitions(ctx, wo.status), completionBlockers: blockers });
});
/** PATCH /api/v1/work-orders/[id] — body: partial master data + optional baseVersion (409 on mismatch). */
export const PATCH = withApi(async (req: Request, { params }: Params) => {
const ctx = await requireApiContext("work_orders");
const { id } = await params;
const { baseVersion, ...patch } = await readJsonObject(req);
return json(await updateWorkOrder(ctx, id, patch as UpdateWorkOrderInput, optionalVersion(baseVersion)));
});