Title

Add SPA 404 monitor + in-app QA Link Audit page

Prompt for Replit

Please implement a simple SPA-safe link audit that runs inside the app, plus wire the runtime 404 monitor fully.

A) Runtime 404 monitor (finish)

We already added data-not-found and a console warning in NotFoundPage.

Also dispatch a spa-404 event (if not already), and log it in one place:
File: client/src/app/spa404-listener.ts

// attach once at app bootstrap
if (typeof window !== 'undefined' && !window.__spa404Bound) {
  window.__spa404Bound = true;
  window.addEventListener('spa-404', (e: any) => {
    const path = e?.detail || window.location.pathname;
    console.warn('[404-event]', path);
    // TODO: send to analytics/provider if available
  });
}


Mount this by importing it in your root (e.g., main.tsx or App.tsx).

B) Hidden QA link audit page (no external deps)

Create a dev-only page that “navigates” a curated list of internal paths using Wouter navigation, waits a tick, and checks for [data-not-found].

File: client/src/pages/dev/LinkAuditPage.tsx

import React from "react";
import { useLocation } from "wouter";

const PATHS: string[] = [
  "/", "/pricing", "/resources", "/faq",
  "/business-development/brand-name-wizard",
  "/business-development/slogan-generator",
  "/business-assets/logo-templates",
  "/brand-development/ai-logo-creator",
  "/brand-development/ai-logo-creator/logo-composer-coffee-cup-v1",
  "/dashboard"
  // add any other important internal routes here
];

export default function LinkAuditPage() {
  const [, nav] = useLocation();
  const [running, setRunning] = React.useState(false);
  const [results, setResults] = React.useState<{path:string; status:"ok"|"not-found";}[]>([]);

  const run = async () => {
    setRunning(true);
    const out: {path:string; status:"ok"|"not-found"}[] = [];
    for (const p of PATHS) {
      // navigate client-side
      nav(p, { replace: true });
      // wait a bit for page to render
      // eslint-disable-next-line no-await-in-loop
      await new Promise(r => setTimeout(r, 350));
      const notFound = !!document.querySelector("[data-not-found]");
      out.push({ path: p, status: notFound ? "not-found" : "ok" });
    }
    setResults(out);
    setRunning(false);
  };

  const exportJson = () => {
    const blob = new Blob([JSON.stringify({ at: new Date().toISOString(), items: results }, null, 2)], { type: "application/json" });
    const url = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = url; a.download = "spa-link-report.json"; a.click();
    URL.revokeObjectURL(url);
  };

  const broken = results.filter(r => r.status === "not-found");

  return (
    <div className="mx-auto max-w-3xl p-6">
      <h1 className="text-xl font-semibold mb-2">SPA Link Audit (In-App)</h1>
      <p className="text-sm text-gray-600 mb-4">Navigates key routes client-side and detects the NotFound page via <code>[data-not-found]</code>.</p>
      <div className="flex gap-2 mb-4">
        <button className="btn btn-primary" onClick={run} disabled={running}>{running ? "Running..." : "Run Audit"}</button>
        <button className="btn btn-outline" onClick={exportJson} disabled={!results.length}>Export JSON</button>
      </div>
      {!!results.length && (
        <div className="text-sm">
          <div className="mb-2">Checked: {results.length} | 404s: {broken.length}</div>
          <ul className="space-y-1">
            {results.map(r => (
              <li key={r.path} className={r.status === "not-found" ? "text-red-600" : "text-emerald-700"}>
                {r.status === "not-found" ? "❌" : "✅"} {r.path}
              </li>
            ))}
          </ul>
        </div>
      )}
    </div>
  );
}


Routes: add a dev-only route (don’t show in nav).

--- a/client/src/App.tsx
+++ b/client/src/App.tsx
@@ -300,6 +300,9 @@
 <Switch>
   {/* existing routes */}
+  {process.env.NODE_ENV !== "production" && (
+    <Route path="/__qa/link-audit" component={LinkAuditPage} />
+  )}
   {/* 404 catch-all at end */}
   <Route><NotFoundPage /></Route>
 </Switch>


Acceptance:

Visiting /__qa/link-audit shows a “Run Audit” button and reports which paths hit NotFound.

NotFoundPage logs [404] and dispatches the spa-404 event; spa404-listener.ts logs [404-event].

No new dependencies; works in Replit environment.

Optional: Add any additional important routes to the PATHS array (e.g., popular logo templates, specific brand-dev subpages).

This gives you believable coverage now:

The server-side audit (linkinator) = static + redirects OK.

The in-app audit page = SPA/client routes OK.

Runtime monitor catches real user 404s in the wild.