A site audit that used to take a day
now runs in four minutes.

Stewards.Digital rebuilds websites for 501(c)(3) organizations as fixed-price, quick-turnaround projects — and this is the pipeline that makes that economical. A nonprofit asks for a review; an automated crawler and a language model produce a structured audit of their site; that audit becomes a private URL they can open the same afternoon. No engineer is copying findings into a slide deck.

The sample above is a complete, real portal rendered from a fictional organization's audit record — the same code path a client sees.

From a form submission to a live portal.

Five stages. Four of them run without anyone watching.

  1. Request arrives

    Human

    A nonprofit submits the audit form. The browser posts to a server route rather than a third-party endpoint, so the form target is not a string in the client bundle.

    Next.js route handler

  2. The site gets crawled

    Automated

    Headless Chromium loads the organization's real site and captures what a visitor actually sees — rendered DOM, computed styles, contrast ratios, mobile layout, and console errors.

    Python · Playwright

  3. Findings get classified

    Automated

    Claude reads that capture and returns structured findings — each one a severity, a plain-language title, and an explanation written for a board member rather than a developer.

    Claude API

  4. The audit is stored

    Automated

    An import script validates the required fields, writes the document to MongoDB, and mints a portal ID from 12 random bytes so the URL cannot be guessed or walked.

    MongoDB Atlas

  5. The portal goes live

    Automated

    A server component reads the audit and renders it on request — no build, no deploy. Contact details are projected out of the query, so they never reach the page.

    React Server Component

  • ~4 minper audit, start to finish
  • $0.03–0.08model cost per audit
  • 0deploys required to publish one

Every choice cost something.

The tradeoffs are the interesting part, so they are written down rather than smoothed over.

  • Two rendering strategies in one app

    The marketing site is prerendered and served from the CDN. Each client portal is a server component that queries MongoDB per request and is never prerendered, never cached, never indexed.

    What it costThe portal pays a database round trip on every request and cannot be served from an edge cache. Accepted, because prerendering a portal would write a named organization's audit into the build output and push it to every CDN node.

  • Contact details are excluded by the type system

    Audits carry contact information, but the portal renders a PublicAudit — a type with the contact field removed — and the database query projects it away before it is read.

    What it costTwo places to widen instead of one whenever the portal legitimately needs a new field. That friction is the point: a UI change cannot start leaking a phone number by accident.

  • Accessibility is a build gate, not a checklist

    axe-core runs against the landing page and a portal on every push, on desktop and mobile viewports, and fails the build on serious or critical violations.

    What it costAutomated tooling catches roughly a third of real accessibility defects and skips aria-hidden subtrees entirely — a contrast bug in a decorative mock survived a green build here and had to be caught by eye. The gate raises the floor; it does not certify compliance.

  • Audits are data, not deploys

    Audit results are documents in MongoDB, keyed by an unguessable portal ID. Running an audit for a new organization mints a live URL immediately.

    What it costA hard dependency on the database: if it is unreachable, portals fail while the marketing site stays up. And with no schema, a malformed write is only caught when someone opens the page — so the import script validates what the database will not.

The site has to pass what it sells.

This business sells WCAG 2.1 AA compliance, so its own site failing that standard is not an option. It did, before this was enforced — grey-on-red navigation text at 1.69:1, form errors signalled by colour alone, no keyboard focus indicator, and no navigation at all below 900 pixels.

  • 13 specs, 25 runs

    Every spec runs against a production build on both desktop and mobile viewports, covering the real journeys — lead capture success and failure, portal rendering, unknown portal codes, mobile navigation.

  • Accessibility assertions

    axe-core scans gate the build, alongside explicit checks that form errors are announced to assistive technology, that focus moves to the first invalid field, and that a skip link is the first thing a keyboard user reaches.

  • Typecheck, lint, build, test

    Every push, with no escape hatches — TypeScript and lint errors fail the build rather than being suppressed. Tests run against fixtures, so continuous integration never touches real client data.

What it runs on.

Application
Next.js 15 App Router · React 19 · TypeScript (strict)
Audit engine
Python · Playwright · Claude API
Data
MongoDB Atlas
Testing
Playwright · axe-core · Cucumber/BDD
Delivery
GitHub Actions · Vercel

Built and maintained by Andre Spencer. The application repository is private — it holds real client audit data — so the architecture and decisions are documented here instead.

Want this run against your site?

The audit is free, and you get the same portal the sample links to.

Get my free audit