71 lines
2.3 KiB
TypeScript
71 lines
2.3 KiB
TypeScript
/**
|
||
* Optional, dev-only SEO sanity check - NOT part of the build or deploy
|
||
* pipeline, never blocks production. Run manually:
|
||
*
|
||
* npm run seo:check
|
||
*
|
||
* Only ever warns; exits 0 regardless of findings (a content gap here isn't
|
||
* a broken deploy).
|
||
*/
|
||
import { getPayload } from "payload";
|
||
import config from "../payload.config";
|
||
|
||
let warnings = 0;
|
||
|
||
function warn(message: string) {
|
||
warnings++;
|
||
console.warn(` ⚠ ${message}`);
|
||
}
|
||
|
||
async function checkCollection(
|
||
payload: Awaited<ReturnType<typeof getPayload>>,
|
||
collection: "offers" | "events" | "posts",
|
||
label: string,
|
||
) {
|
||
console.log(`${label}:`);
|
||
const { docs } = await payload.find({ collection, limit: 500, depth: 0 });
|
||
|
||
const slugCounts = new Map<string, number>();
|
||
for (const doc of docs as { slug?: string | null; title?: string }[]) {
|
||
if (doc.slug) slugCounts.set(doc.slug, (slugCounts.get(doc.slug) ?? 0) + 1);
|
||
}
|
||
for (const [slug, count] of slugCounts) {
|
||
if (count > 1) warn(`Slug „${slug}“ kommt ${count}× vor.`);
|
||
}
|
||
|
||
for (const doc of docs as { slug?: string | null; title?: string; seo?: { description?: string | null } | null }[]) {
|
||
if (!doc.title?.trim()) warn(`Dokument ohne Titel (slug: ${doc.slug ?? "-"}).`);
|
||
if (!doc.slug?.trim()) warn(`Dokument ohne Slug: „${doc.title ?? "-"}“.`);
|
||
}
|
||
|
||
if (docs.length === 0) console.log(" (keine Einträge)");
|
||
}
|
||
|
||
async function checkMedia(payload: Awaited<ReturnType<typeof getPayload>>) {
|
||
console.log("Medien (Alt-Texte):");
|
||
const { docs } = await payload.find({ collection: "media", limit: 1000, depth: 0 });
|
||
const missingAlt = (docs as { alt?: string; filename?: string }[]).filter((doc) => !doc.alt?.trim());
|
||
if (missingAlt.length === 0) {
|
||
console.log(" Alle Bilder haben einen Alt-Text.");
|
||
} else {
|
||
for (const doc of missingAlt) warn(`Bild ohne Alt-Text: ${doc.filename ?? "unbekannt"}`);
|
||
}
|
||
}
|
||
|
||
async function run() {
|
||
const payload = await getPayload({ config });
|
||
|
||
await checkCollection(payload, "offers", "Angebote");
|
||
await checkCollection(payload, "events", "Termine");
|
||
await checkCollection(payload, "posts", "Aktuelles");
|
||
await checkMedia(payload);
|
||
|
||
console.log(`\n${warnings === 0 ? "Keine Auffälligkeiten gefunden." : `${warnings} Hinweis(e) gefunden - siehe oben.`}`);
|
||
process.exit(0);
|
||
}
|
||
|
||
run().catch((err) => {
|
||
console.error(err);
|
||
process.exit(0);
|
||
});
|