- Create src/lib/redis.ts (singleton client) and src/lib/cache.ts (cachedQuery with graceful degradation on Redis failure) - Wrap all 12 API routes and 7 RSC pages with cachedQuery (TTLs: 120s-900s by data type — dashboard 3min, inventory/orders/shipments 5min, BOL/order-ack/traveler 10min, ship-to 15min, avail-coils 2min) - Fix redundant connection pools in dashboard.ts and shipments.ts (were creating their own sql.connect instead of using shared pool) - Add pool tuning to epicor.ts (max:15, min:2, 60s idle, 30s acquire) - Parallelize session checks (getQuestSession + getActiveCompany + isSubUser) with Promise.all across all inventory and orders pages - Add loading.tsx skeletons for dashboard, inventory detail, orders, and shipments pages for instant shell rendering via Next.js streaming Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
54 lines
1.6 KiB
TypeScript
54 lines
1.6 KiB
TypeScript
import { NextResponse } from 'next/server';
|
|
import { getBOLDetail } from '@/services/shipments';
|
|
import { getQuestSession, getActiveCompany } from '@/lib/permissions';
|
|
import { cachedQuery } from '@/lib/cache';
|
|
|
|
export const dynamic = 'force-dynamic';
|
|
|
|
export async function GET(
|
|
_request: Request,
|
|
{ params }: { params: Promise<{ bol: string }> }
|
|
) {
|
|
const session = await getQuestSession();
|
|
const activeCompany = await getActiveCompany();
|
|
|
|
if (!session || !activeCompany) {
|
|
return NextResponse.json({ error: 'No active company' }, { status: 401 });
|
|
}
|
|
|
|
const { bol } = await params;
|
|
const bolNum = parseInt(bol, 10);
|
|
if (isNaN(bolNum)) {
|
|
return NextResponse.json({ error: 'Invalid BOL number' }, { status: 400 });
|
|
}
|
|
|
|
const custId = activeCompany.epicor_cust_id;
|
|
|
|
try {
|
|
const data = await cachedQuery(
|
|
{ key: `bol:${custId}:${bolNum}`, ttlSeconds: 600 },
|
|
() => getBOLDetail(bolNum, custId)
|
|
);
|
|
|
|
if (!data) {
|
|
return NextResponse.json({ error: 'BOL not found' }, { status: 404 });
|
|
}
|
|
|
|
return NextResponse.json({ data });
|
|
} catch (err) {
|
|
const message = err instanceof Error ? err.message : String(err);
|
|
let details = '';
|
|
|
|
// Extract original error from EpicorQueryError
|
|
if (err && typeof err === 'object' && 'originalError' in err) {
|
|
const originalError = err.originalError;
|
|
details = originalError instanceof Error ? originalError.message : String(originalError);
|
|
}
|
|
|
|
console.error('BOL detail error:', err);
|
|
return NextResponse.json(
|
|
{ error: message, details },
|
|
{ status: 500 }
|
|
);
|
|
}
|
|
}
|