Add payment module, BFF proxy, hub/dashboard/ops/PSP/merchant screens wired to real APIs, and mark payment-frontend complete in project status. Co-authored-by: Cursor <cursoragent@cursor.com>
120 lines
3.1 KiB
JavaScript
120 lines
3.1 KiB
JavaScript
#!/usr/bin/env node
|
|
/** Validates payment MVP routes and module files exist */
|
|
import fs from "node:fs";
|
|
import path from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
const ROOT = path.join(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
const APP = path.join(ROOT, "app", "payment");
|
|
const MODULE = path.join(ROOT, "modules", "payment");
|
|
const MAX_LINES = 25;
|
|
let errors = [];
|
|
|
|
const MVP_ROUTES = [
|
|
"hub",
|
|
"dashboard",
|
|
"overview",
|
|
"kpis",
|
|
"transactions",
|
|
"ledger",
|
|
"psp",
|
|
"psp/health",
|
|
"providers",
|
|
"merchants",
|
|
"merchants/approvals",
|
|
"requests",
|
|
"callbacks",
|
|
"verification",
|
|
"audit",
|
|
"bundles",
|
|
"feature-toggles",
|
|
"capabilities",
|
|
"settings",
|
|
"metrics",
|
|
"monitoring",
|
|
"api-explorer",
|
|
"openapi",
|
|
];
|
|
|
|
const FEATURE_FILES = [
|
|
"hub.tsx",
|
|
"dashboard.tsx",
|
|
"overview.tsx",
|
|
"kpis.tsx",
|
|
"transactions.tsx",
|
|
"transactionDetail.tsx",
|
|
"ledger.tsx",
|
|
"psp.tsx",
|
|
"gatewayHealth.tsx",
|
|
"providers.tsx",
|
|
"merchants.tsx",
|
|
"merchantDetail.tsx",
|
|
"merchantApprovals.tsx",
|
|
"requests.tsx",
|
|
"requestDetail.tsx",
|
|
"callbacks.tsx",
|
|
"verification.tsx",
|
|
"audit.tsx",
|
|
"bundles.tsx",
|
|
"featureToggles.tsx",
|
|
"capabilities.tsx",
|
|
"settings.tsx",
|
|
"metrics.tsx",
|
|
"monitoring.tsx",
|
|
"apiExplorer.tsx",
|
|
"openapi.tsx",
|
|
];
|
|
|
|
const REQUIRED_FILES = [
|
|
path.join(MODULE, "index.ts"),
|
|
path.join(MODULE, "services", "payment-api.ts"),
|
|
path.join(ROOT, "app", "api", "payment", "[...path]", "route.ts"),
|
|
path.join(APP, "layout.tsx"),
|
|
path.join(APP, "page.tsx"),
|
|
];
|
|
|
|
function walkPages(dir) {
|
|
for (const ent of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
const p = path.join(dir, ent.name);
|
|
if (ent.isDirectory()) walkPages(p);
|
|
else if (ent.name === "page.tsx") checkPage(p);
|
|
}
|
|
}
|
|
|
|
function checkPage(file) {
|
|
const rel = path.relative(APP, file);
|
|
const content = fs.readFileSync(file, "utf8");
|
|
const lines = content.split("\n").length;
|
|
if (rel !== "page.tsx" && lines > MAX_LINES) {
|
|
errors.push(`${rel}: ${lines} lines (max ${MAX_LINES})`);
|
|
}
|
|
if (rel !== "page.tsx" && !content.includes("@/modules/payment/")) {
|
|
errors.push(`${rel}: must import from @/modules/payment/`);
|
|
}
|
|
}
|
|
|
|
for (const route of MVP_ROUTES) {
|
|
for (const file of ["page.tsx", "loading.tsx", "error.tsx"]) {
|
|
const p = path.join(APP, route, file);
|
|
if (!fs.existsSync(p)) errors.push(`missing app/payment/${route}/${file}`);
|
|
}
|
|
}
|
|
|
|
for (const f of FEATURE_FILES) {
|
|
const p = path.join(MODULE, "features", f);
|
|
if (!fs.existsSync(p)) errors.push(`missing modules/payment/features/${f}`);
|
|
}
|
|
|
|
for (const f of REQUIRED_FILES) {
|
|
if (!fs.existsSync(f)) errors.push(`missing ${path.relative(ROOT, f)}`);
|
|
}
|
|
|
|
if (fs.existsSync(APP)) walkPages(APP);
|
|
else errors.push("app/payment not found");
|
|
|
|
if (errors.length) {
|
|
console.error("Payment route validation failed:\n" + errors.map((e) => " - " + e).join("\n"));
|
|
process.exit(1);
|
|
}
|
|
console.log(`Payment routes OK (${MVP_ROUTES.length} MVP routes, ${FEATURE_FILES.length} features)`);
|