mega-plant/proxy.ts
David 8f3a74cf6e Job cards oil path, Fuel tab diesel-only, Mechanic role, Plant Register QR column
- Job cards scanner: oil QR books litres + vehicle (no odo/photo), bundled onto the
  vehicle's job card (open job now, or the next job started the same day)
- Fuel tab is diesel only; /api/clock/oil-out added
- Users: Full / Clock-in user / Mechanic; mechanics see only Fuel + Job cards
- Plant Register: QR code column (double-click to set), kept across re-seeds and
  used when matching scans

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-22 13:44:01 +02:00

37 lines
2.4 KiB
TypeScript

import { NextRequest, NextResponse } from "next/server";
import { clockAuthDestination } from "@/lib/clock-pwa";
import { sessionFromToken } from "@/lib/auth-service";
import { SESSION_COOKIE, authDestination } from "@/lib/auth-policy";
export async function proxy(request: NextRequest) {
const path = request.nextUrl.pathname;
if (path === "/api/health" || path === "/api/auth/logout" || path === "/login" || path === "/clock/login" || path === "/clock.webmanifest") return NextResponse.next();
let session;
try {
session = await sessionFromToken(request.cookies.get(SESSION_COOKIE)?.value || "");
} catch {
return path.startsWith("/api/")
? NextResponse.json({ error: "Account service is temporarily unavailable." }, { status: 503 })
: new NextResponse("Account service is temporarily unavailable. Please reload to try again.", { status: 503, headers: { "Content-Type": "text/plain; charset=utf-8", "Cache-Control": "no-store" } });
}
const clockPath=path==="/clock"||path.startsWith("/clock/")||path.startsWith("/api/clock/");
const destination = clockPath?clockAuthDestination(session):authDestination(session);
// Logout is a server action and remains available during first-login onboarding.
if ((path === "/change-password" || path === "/clock/change-password") && session) return NextResponse.next();
if (destination !== (clockPath?"/clock":"/")) {
if (path.startsWith("/api/")) return NextResponse.json({ error: !session ? "Please sign in." : session.passwordChanged ? "This account only has access to the clock app." : "Change your starter password first." }, { status: session ? 403 : 401 });
return NextResponse.redirect(new URL(destination, request.url));
}
// A mechanic has no clock in/out: send the scanner page to Job cards and refuse its API.
if (clockPath && session?.access === "mechanic") {
if (path === "/clock") return NextResponse.redirect(new URL("/clock/job-cards", request.url));
if (path === "/api/clock/scan") return NextResponse.json({ error: "Mechanics cannot clock in or out." }, { status: 403 });
}
const response = NextResponse.next();
response.headers.set("Cache-Control", "private, no-store");
return response;
}
export const config = {
matcher: ["/((?!_next/static|_next/image|brand/|icons/|favicon\\.ico|manifest\\.json|sw\\.js|workbox-[^/]+\\.js|swe-worker-[^/]+\\.js|worker-[^/]+\\.js).*)"],
};