Improve audit pipeline and outreach review

This commit is contained in:
2026-06-08 22:16:32 +02:00
parent ff18fc202e
commit 1695110e0a
34 changed files with 2792 additions and 238 deletions

View File

@@ -72,6 +72,20 @@ export type AuditEvidenceInput = {
}>;
pageSpeedCustomerImplications: string[];
selectedSkills: AuditUsedSkill[];
evidenceLedger: AuditEvidenceLedgerEntry[];
};
export type AuditEvidenceLedgerEntry = {
id: string;
type:
| "crawl_page"
| "technical_check"
| "screenshot"
| "pagespeed"
| "jina_excerpt";
label: string;
sourceUrl?: string;
summary: string;
};
export type AuditEvidenceInputArgs = {
@@ -96,6 +110,7 @@ const EXTERNAL_MARKDOWN_LIMIT = 4_000;
const V3_LOCAL_AUDIT_PRIORITY = new Map(
[
"visual-design",
"impeccable-critique",
"contact-conversion",
"local-seo-basics",
"performance-experience",
@@ -113,6 +128,32 @@ const PAGESPEED_NOISE_PATTERN =
/\b(?:raw\s*storage\s*id|rawstorageid|lighthouse|pagespeed|score)\b/i;
const MACHINE_TOKEN_PATTERN = /\b[a-z\d_-]{24,}\b/i;
function stableEvidencePart(value: unknown) {
const normalized = trimAndNormalize(String(value ?? "").toLowerCase())
.replace(/^https?:\/\//, "")
.replace(/^www\./, "")
.replace(/[^a-z0-9]+/g, "-")
.replace(/^-+|-+$/g, "")
.slice(0, 80);
return normalized || "source";
}
function evidenceId(type: AuditEvidenceLedgerEntry["type"], ...parts: unknown[]) {
return [type, ...parts.map(stableEvidencePart)].join(":");
}
function addEvidenceLedgerEntry(
ledger: AuditEvidenceLedgerEntry[],
entry: AuditEvidenceLedgerEntry,
) {
if (!entry.summary || ledger.some((current) => current.id === entry.id)) {
return;
}
ledger.push(entry);
}
function trimAndNormalize(input: unknown): string {
if (typeof input !== "string") {
return "";
@@ -555,6 +596,7 @@ export function buildAuditEvidenceInput(
const pageSpeedInputs = args.pageSpeedInputs ?? [];
const skillRegistry = args.skillRegistry ?? [];
const externalMarkdown = sanitizeExternalMarkdown(args.externalMarkdown);
const evidenceLedger: AuditEvidenceLedgerEntry[] = [];
const companyContext: string[] = [];
const checkedPages: string[] = [];
@@ -620,6 +662,22 @@ export function buildAuditEvidenceInput(
}
addUniqueCapped(checkedPages, label, CHECKED_PAGES_LIMIT);
addEvidenceLedgerEntry(evidenceLedger, {
id: evidenceId("crawl_page", page.finalUrl ?? page.sourceUrl, page.pageKind),
type: "crawl_page",
label,
...(page.finalUrl ?? page.sourceUrl ? { sourceUrl: page.finalUrl ?? page.sourceUrl ?? undefined } : {}),
summary: sanitizeCustomerText(
[
title ? `Titel: ${title}` : "",
page.metaDescription ? `Meta: ${page.metaDescription}` : "",
page.visibleTextExcerpt ?? page.visibleText ?? "",
]
.filter(Boolean)
.join(" | "),
260,
),
});
}
if (checkedPages.length === 0 && lead.companyName) {
@@ -634,6 +692,44 @@ export function buildAuditEvidenceInput(
const pageSpeedInputsOutput = buildPageSpeedAuditInputs(pageSpeedInputs);
const pageSpeedCustomerImplications: string[] = [];
for (const check of technicalChecks) {
const summary = [
check.usesHttps === true ? "HTTPS vorhanden" : "",
check.usesHttps === false ? "HTTPS fehlt" : "",
check.missingTitle === true ? "Title fehlt" : "",
check.missingMetaDescription === true ? "Meta-Description fehlt" : "",
check.hasVisibleContactPath === true ? "Kontaktpfad sichtbar" : "",
check.brokenInternalLinkCount !== undefined
? `Interne Linkfehler: ${check.brokenInternalLinkCount}`
: "",
]
.filter(Boolean)
.join(" | ");
addEvidenceLedgerEntry(evidenceLedger, {
id: evidenceId("technical_check", check.finalUrl ?? check.sourceUrl),
type: "technical_check",
label: `Technik: ${toSafePath(check.finalUrl ?? check.sourceUrl ?? "") || "Seite"}`,
...(check.finalUrl ?? check.sourceUrl ? { sourceUrl: check.finalUrl ?? check.sourceUrl ?? undefined } : {}),
summary: sanitizeCustomerText(summary, 260),
});
}
for (const screenshot of screenshots) {
addEvidenceLedgerEntry(evidenceLedger, {
id: evidenceId(
"screenshot",
screenshot.storageId,
screenshot.viewport,
screenshot.sourceUrl,
),
type: "screenshot",
label: `${screenshot.viewport === "desktop" ? "Desktop" : "Mobil"} Screenshot`,
sourceUrl: screenshot.sourceUrl,
summary: `${screenshot.viewport} Screenshot ${screenshot.width}x${screenshot.height}`,
});
}
for (const implication of pageSpeedInputsOutput.customerImplications) {
addUniqueCapped(
pageSpeedCustomerImplications,
@@ -643,6 +739,32 @@ export function buildAuditEvidenceInput(
);
}
for (const input of pageSpeedInputs) {
const implication = pageSpeedInputsOutput.customerImplications.find(Boolean);
addEvidenceLedgerEntry(evidenceLedger, {
id: evidenceId("pagespeed", input.strategy, input.sourceUrl, input.status),
type: "pagespeed",
label: `PageSpeed ${input.strategy}`,
sourceUrl: input.sourceUrl,
summary: sanitizeCustomerText(
implication ??
(input.status === "succeeded"
? "PageSpeed-Messung erfolgreich"
: "PageSpeed-Messung nicht verfügbar"),
260,
),
});
}
if (externalMarkdown) {
addEvidenceLedgerEntry(evidenceLedger, {
id: evidenceId("jina_excerpt", externalMarkdown.slice(0, 80)),
type: "jina_excerpt",
label: "Jina Reader Auszug",
summary: sanitizeCustomerText(externalMarkdown, 260),
});
}
const selectedSkills = extractSkills(skillRegistry, {
...signals.evidenceText,
marketing: false,
@@ -687,5 +809,6 @@ export function buildAuditEvidenceInput(
PAGESPEED_SIGNAL_LIMIT,
),
selectedSkills,
evidenceLedger,
};
}