WFDASH-WEBAPP/scripts/perf/dashboard-end-to-end.ts
SJCoetz 12fa65a481 feat: add new order, invoice, and dashboard management tools
- Add server-side `/api/v1/dashboard` endpoint to reduce client-side payload and round trips
- Implement invoice upload and order-item SKU update APIs with complete test suites
- Refactor order and order-items list endpoints (including MCP tools) to support proper PocketBase filter and sort params
- Fix pagination validation for order-items route to clamp page ≥1 and perPage 1-500
- Add redirects in next.config.ts to map underscore collection paths to hyphenated API routes
- Improve buyer tasks page to avoid redundant tab count refetches when switching tabs
- Refactor collection confirm components with editable SKUs and updated accessibility labels
- Add cached admin PocketBase auth to minimize repeated authentication calls
- Add performance testing scripts for dashboard endpoint latency
- Update quotes list route to default to excluding archived counts
- Fix photo strip component text and labels for non-invoice documents
- Refactor sprint page to lazy load supplier/customer data for pricing modal
- Clean up unused imports in test files
- Add full test coverage for all new APIs, services, and components
2026-08-05 23:00:54 +02:00

68 lines
No EOL
2.2 KiB
TypeScript

// Time /api/v1/dashboard end-to-end via the running dev server.
// First mints a PB user-token, then fires 3 cold + 3 warm GETs.
import { performance } from "node:perf_hooks";
import PocketBase from "pocketbase";
async function main() {
const baseUrl = process.env.NEXT_PUBLIC_POCKETBASE_URL || "http://127.0.0.1:8090";
const appUrl = process.env.WFDASH_APP_URL || "http://127.0.0.1:4001";
const email = process.env.PB_ADMIN_EMAIL;
const password = process.env.PB_ADMIN_PASSWORD;
if (!email || !password) {
console.error("Missing PB_ADMIN_EMAIL / PB_ADMIN_PASSWORD");
process.exit(1);
}
const pb = new PocketBase(baseUrl);
// Mint a user-token (the route asserts via /auth-refresh, which
// accepts users-issued tokens).
const userAuth = await pb.collection("users").authWithPassword("david.els1@outlook.com", "1234567890");
const token = userAuth.token;
console.log(`App: ${appUrl}`);
console.log(`PB: ${baseUrl}`);
const cold: number[] = [];
const warm: number[] = [];
for (let i = 0; i < 3; i += 1) {
const t0 = performance.now();
const res = await fetch(`${appUrl}/api/v1/dashboard`, {
headers: { Authorization: token },
cache: "no-store",
});
const body = await res.text();
const t1 = performance.now();
cold.push(t1 - t0);
if (!res.ok) {
console.error(`cold #${i + 1}: HTTP ${res.status} body=${body.slice(0, 200)}`);
continue;
}
console.log(`cold #${i + 1}: ${(t1 - t0).toFixed(0)}ms body=${body.length}B`);
}
for (let i = 0; i < 3; i += 1) {
const t0 = performance.now();
const res = await fetch(`${appUrl}/api/v1/dashboard`, {
headers: { Authorization: token },
cache: "no-store",
});
const t1 = performance.now();
warm.push(t1 - t0);
console.log(`warm #${i + 1}: ${(t1 - t0).toFixed(0)}ms`);
}
const median = (xs: number[]) => {
const sorted = [...xs].sort((a, b) => a - b);
return sorted[Math.floor(sorted.length / 2)];
};
console.log("---");
console.log(`Cold median: ${median(cold).toFixed(0)}ms`);
console.log(`Warm median: ${median(warm).toFixed(0)}ms`);
}
main().catch((e) => {
console.error(e);
process.exit(1);
});