Files
Andres Resiri 70daeb214a
CI / Quality gate (push) Has been cancelled
Initial project commit for Coolify staging
2026-08-03 10:45:41 -04:00

133 lines
7.4 KiB
TypeScript

import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();
async function main() {
console.log("Seeding audit data...");
const brands = await prisma.brand.findMany();
if (brands.length === 0) { console.log("No brands. Run main seed first."); return; }
for (const brand of brands) {
// Clear existing
await prisma.technicalIssue.deleteMany({ where: { audit: { brandId: brand.id } } });
await prisma.technicalAudit.deleteMany({ where: { brandId: brand.id } });
await prisma.deadPageSource.deleteMany({ where: { deadPage: { brandId: brand.id } } });
await prisma.deadPage.deleteMany({ where: { brandId: brand.id } });
await prisma.performancePageScore.deleteMany({ where: { audit: { brandId: brand.id } } });
await prisma.performanceAudit.deleteMany({ where: { brandId: brand.id } });
// ── Technical Audit ──
await prisma.technicalAudit.create({
data: {
brandId: brand.id,
crawlHealth: 68,
pagesScanned: 1248,
duration: 262,
errorCount: 17,
warningCount: 34,
noticeCount: 12,
passedCount: 89,
issues: {
create: [
{ category: "metadata", severity: "critical", title: "Missing meta description", detail: "14 pages have no meta description tag", pageUrl: "/features", affected: 14 },
{ category: "metadata", severity: "critical", title: "Duplicate title tags", detail: "6 pages share identical title tags", pageUrl: "/products", affected: 6 },
{ category: "links", severity: "critical", title: "Broken internal links", detail: "17 links point to pages that return 404", pageUrl: "/blog", affected: 17 },
{ category: "headings", severity: "medium", title: "Images missing alt text", detail: "31 images have no alt attribute", pageUrl: "/about", affected: 31 },
{ category: "crawl", severity: "medium", title: "Oversized images (>200 KB)", detail: "23 images exceed recommended size", pageUrl: "/products", affected: 23 },
{ category: "metadata", severity: "medium", title: "No structured data", detail: "8 pages have no schema markup", pageUrl: "/services", affected: 8 },
{ category: "crawl", severity: "medium", title: "HTTP links on HTTPS page", detail: "4 mixed content resources detected", pageUrl: "/about", affected: 4 },
{ category: "headings", severity: "low", title: "Missing H1 tag", detail: "3 pages have no H1 element", pageUrl: "/contact", affected: 3 },
{ category: "crawl", severity: "low", title: "Slow page load (>3 s)", detail: "9 pages exceed 3 second load time", pageUrl: "/pricing", affected: 9 },
{ category: "indexability", severity: "low", title: "Missing canonical tags", detail: "11 pages have no canonical URL", pageUrl: "/blog", affected: 11 },
{ category: "redirects", severity: "medium", title: "Redirect chains", detail: "3 URLs have 2+ redirects before final", pageUrl: "/old-pricing", affected: 3 },
{ category: "indexability", severity: "medium", title: "Noindex on important pages", detail: "2 service pages accidentally blocked", pageUrl: "/services/seo", affected: 2 },
],
},
},
});
console.log(` Technical audit: 12 issues for ${brand.name}`);
// ── Dead 404 Pages ──
const deadPages = [
{ deadUrl: "/old-pricing", priority: "high", suggestedFix: "Redirect to /pricing", sources: [{ sourceUrl: "/about", anchorText: "our pricing" }, { sourceUrl: "/blog/launch", anchorText: "pricing page" }] },
{ deadUrl: "/blog/2022/launch", priority: "medium", suggestedFix: "Redirect to /blog", sources: [{ sourceUrl: "/blog", anchorText: "launch post" }] },
{ deadUrl: "/products/legacy", priority: "medium", suggestedFix: "Redirect to /products", sources: [{ sourceUrl: "/features", anchorText: "legacy product" }, { sourceUrl: "/about", anchorText: "our first product" }] },
{ deadUrl: "/team/jane-old-bio", priority: "low", suggestedFix: "Redirect to /about#team", sources: [{ sourceUrl: "/blog/team-update", anchorText: "Jane's bio" }] },
{ deadUrl: "/downloads/brochure-v1", priority: "low", suggestedFix: "Remove links or upload new version", sources: [{ sourceUrl: "/contact", anchorText: "download brochure" }] },
];
for (const dp of deadPages) {
await prisma.deadPage.create({
data: {
brandId: brand.id,
deadUrl: dp.deadUrl,
priority: dp.priority,
suggestedFix: dp.suggestedFix,
sources: { create: dp.sources },
},
});
}
console.log(` Dead pages: ${deadPages.length} for ${brand.name}`);
// ── Performance Audit (mobile) ──
const mobilePages = [
{ pageUrl: "/", performance: 64, accessibility: 89, bestPractices: 78, seo: 92, lcpMs: 3800, inpMs: 280, clsVal: 0.04, fcpMs: 2100, ttfbMs: 620 },
{ pageUrl: "/about", performance: 72, accessibility: 91, bestPractices: 83, seo: 95, lcpMs: 2900, inpMs: 180, clsVal: 0.02, fcpMs: 1800, ttfbMs: 540 },
{ pageUrl: "/pricing", performance: 45, accessibility: 78, bestPractices: 72, seo: 88, lcpMs: 5100, inpMs: 420, clsVal: 0.18, fcpMs: 3200, ttfbMs: 890 },
{ pageUrl: "/blog", performance: 81, accessibility: 93, bestPractices: 89, seo: 97, lcpMs: 1800, inpMs: 120, clsVal: 0.01, fcpMs: 1100, ttfbMs: 380 },
{ pageUrl: "/contact", performance: 91, accessibility: 95, bestPractices: 92, seo: 98, lcpMs: 1100, inpMs: 90, clsVal: 0.00, fcpMs: 800, ttfbMs: 340 },
{ pageUrl: "/products", performance: 52, accessibility: 82, bestPractices: 75, seo: 85, lcpMs: 4400, inpMs: 350, clsVal: 0.12, fcpMs: 2800, ttfbMs: 720 },
{ pageUrl: "/features", performance: 58, accessibility: 84, bestPractices: 77, seo: 87, lcpMs: 4000, inpMs: 310, clsVal: 0.09, fcpMs: 2500, ttfbMs: 680 },
{ pageUrl: "/login", performance: 93, accessibility: 96, bestPractices: 91, seo: 90, lcpMs: 900, inpMs: 70, clsVal: 0.00, fcpMs: 600, ttfbMs: 280 },
];
await prisma.performanceAudit.create({
data: {
brandId: brand.id,
device: "mobile",
pages: {
create: mobilePages.map((p) => ({
...p,
device: "mobile",
status: p.performance >= 90 ? "pass" : p.performance >= 50 ? "average" : "fail",
})),
},
},
});
console.log(` Performance audit: ${mobilePages.length} pages (mobile) for ${brand.name}`);
// ── Performance Audit (desktop) ──
const desktopPages = mobilePages.map((p) => ({
...p,
performance: Math.min(100, p.performance + 20),
lcpMs: Math.round(p.lcpMs * 0.5),
inpMs: Math.round(p.inpMs * 0.5),
clsVal: Math.round(p.clsVal * 0.5 * 100) / 100,
fcpMs: Math.round(p.fcpMs * 0.5),
ttfbMs: Math.round(p.ttfbMs * 0.6),
}));
await prisma.performanceAudit.create({
data: {
brandId: brand.id,
device: "desktop",
pages: {
create: desktopPages.map((p) => ({
...p,
device: "desktop",
status: p.performance >= 90 ? "pass" : p.performance >= 50 ? "average" : "fail",
})),
},
},
});
console.log(` Performance audit: ${desktopPages.length} pages (desktop) for ${brand.name}`);
}
console.log("Audit seeding complete!");
}
main()
.catch((e) => { console.error(e); process.exit(1); })
.finally(() => prisma.$disconnect());