Angel Campa
Colour theme

WorkThe April wave

Floriva Web

The marketing and research site for a period-tracking app: 470 prerendered pages of reproductive-health privacy research, checked by 41 verification gates instead of a framework.

Ran on
Cloudflare Pages
Ran
April 2026 to August 2026
Domain
Reproductive health research and marketing
Source
reproductive-privacy-site-floriva-snapshot

Built with

  • React 19
  • Vite
  • TypeScript
  • Zod
  • Cloudflare Pages
  • Cloudflare Workers
  • D1

Hosted services

  • Cloudflare Pages Functions
  • R2
  • Cloudflare Email Routing
  • Turnstile
  • Sentry
Floriva marketing homepage, hero headline and phone mockup of the today screen
Home: the product page, at 1440x900. Resources serves as the entry point into the content corpus.

The decision

470 mostly-static editorial routes did not get a meta-framework. Vite plus a custom prerendering script (scripts/prerender-html.mjs read the built dist/index.html, swapped the per-route <head> and JSON-LD, and rendered markdown content by walking its own AST) meant no React shipped in the build at all, and vite build finished in under two seconds.

An empty-string environment variable once tripped the prerender script’s truthiness check into reading it as unset. dist/ shipped with every content route carrying a correct <head> and complete markup but no entry bundle: pages rendered and never hydrated, while the test suite stayed green throughout.

The fix became a permanent build gate. Every emitted document had to carry a <script type="module"> tag resolving to a real file in dist, checked by walking the entire output directory rather than globbing *.html, since content routes were written extensionless and a glob-based check would have inspected almost nothing.

The choice also carries an ongoing cost: the prerenderer and the React app walk markdown through two separate code paths, so a change to article styling has to be made in both. In exchange, production ships zero React and stays gated against ever shipping a page that cannot hydrate.

Architecture

Three runtimes lived in one repository: a build-time Node pipeline, a browser bundle, and two Cloudflare Workers surfaces: Pages Functions for the edge layer, plus a same-account email Worker with workers_dev = false, reachable only through a service binding.

One request had four possible terminations, decided by three predicates the edge middleware evaluated at different depths. A redirect verifier read that middleware’s 457 rules back out of the source file by regex rather than importing or duplicating the tables, so the check could not drift from the thing it checked: the module was not exported, and the middleware depended on Workers globals that do not exist in Node. Each of the 457 rules, 451 exact and 6 prefix, was then checked against a live origin on both GET and HEAD.

By the numbers

Each figure carries where it came from and when it was measured. Open one to see the command behind it, where the repository recorded a command.

Authored code
221 files, 42,084 lines: 12,185 application source, 9,659 tests, 16,444 build and verification tooling, 3,565 styles, 231 SQL migrations
Provenance

Source portfolio/METRICS.md § Written by hand (that doc's heading for authored rather than generated files)

pnpm metrics

Measured

Prerendered routes
470 prerendered routes: 444 indexed, 26 noindex,follow by design
Provenance

Source portfolio/METRICS.md § Surface

Measured

Tests
431 tests across 61 test files and 82 suites: 429 passed, 2 skipped, zero failing
Provenance

Source portfolio/METRICS.md § Tests

Measured

Coverage
90.2% lines/statements, 80.73% branches, across 71 application files
Provenance

Source portfolio/METRICS.md § Coverage

Measured

Verification gates
41 of 66 npm scripts are verification gates, not build steps
Provenance

Source README § Testing

Measured

Redirect rules
457 rules (451 exact, 6 prefix) verified against a live origin on both GET and HEAD
Provenance

Source README § 3. A redirect verifier that reads the implementation

Measured

Accessibility gate
PASS: 0 errors, 0 warnings, across 20 routes and 29 captures
Provenance

Source portfolio/TESTING.md § Allowlists are counted, not hidden

Measured

Content corpus
446 MDX documents across 15 collections, 61,599 lines
Provenance

Source portfolio/METRICS.md § Not written by hand (that doc's heading for generated and imported content)

Measured

Data model
12 D1 tables across 15 migrations
Provenance

Source portfolio/METRICS.md § Surface

Measured

History
283 commits since 2026-04-21
Provenance

Source README § By the numbers

Measured

Screens

Floriva resources hub listing privacy guides, comparisons, and 273 matching pages
Resources: the entry point to 446 documents across 15 collections.
Floriva free-downloads hub listing 35 checklists, scripts, and templates
Free downloads: the lead-magnet hub, 35 pages. This is the funnel the email Worker and its NURTURE_EMAIL_CAP_PER_LEAD = 7 exist for.
Comparison table of Floriva, Flo, and Clue across privacy and pricing factors
A feature comparison table for Floriva, Flo, and Clue across privacy and pricing factors, including "Paid app (no free tier)" and "N/A (no server data)".
Numbered list of source citations, each with a verification date
Per-claim citation with a verification date, on the 52 documents that carry a sources: block. This is what the editorial gate is protecting.
Read the repositoryreproductive-privacy-site-floriva-snapshot

Its portfolio/ directory holds the architecture, metrics and testing documents these figures were taken from.