Skip to content

ADR: UI Stack — React SPA on Cloudflare Pages

  • Status: Accepted (recommendation from Claude, confirmed by Jeffrey)
  • Date: 2026-04-23
  • Decider: Jeffrey Lambert
  • Project: Admin Dashboard Cloudflare Migration

The new admin is an application, not a document site: operators will filter lists, open detail drawers, edit records, trigger jobs, and navigate between customer / subscription / billing views. Adventive’s brand-guide dashboard reference (https://brandguide.adventive.com/dashboard) is clearly a rich, componentized interface in that application shape.

Two candidate UI stacks were evaluated:

  1. SPA (React/Vue/Svelte) on Cloudflare Pages, calling admin-api Worker.
  2. Workers-rendered HTML (HTMX / server-side components) — UI and API colocated in one Worker.

React + Vite + TypeScript, deployed as a static SPA on Cloudflare Pages, calling the admin-api Worker over HTTPS with a signed Cloudflare Access JWT.

  • Largest component / tooling ecosystem for operator-grade admin UIs (Radix, shadcn, TanStack Table, TanStack Query).
  • Maps cleanly to the brand-guide dashboard visual language (card-based, filter-heavy, data-dense).
  • Broad hiring / AI-assistance support — easiest to maintain long-term.
  • TypeScript gives a single-language contract with the admin-api Worker (shared zod or @hono/zod-openapi types).

Vue and Svelte were viable but offered no compelling advantage for the operator persona or Adventive’s current skillset. If Adventive already has a front-end standard I should match, that overrides this recommendation.

DimensionSPA (chosen)Workers-rendered HTML
InteractivityNative to the modelNeeds HTMX + Alpine for parity
Local dev loopvite dev, fast HMRFull wrangler dev cycle
Deploy separationUI and API ship independentlySingle artifact (could be pro or con)
Offline / cachingEdge-cached static bundlePer-request render
Fit for brand-guide UXStrongWorkable but awkward for data-dense views
ComplexitySPA build pipelineSimpler template rendering

The SPA wins on interactivity, local dev, and UX fit for the target design. The Worker/HTMX approach would be simpler but is the wrong tool for this application shape.

  • Pages site sits behind a Cloudflare Access policy (same policy as the API, so operators sign in once).
  • UI reads authenticated user from Cf-Access-Authenticated-User-Email header on a protected /me endpoint it calls at load time.
  • API validates the Access JWT on every request — UI cannot bypass.

Positive:

  • Clean presentation/API separation that was the whole point of the project.
  • Rapid iteration on UI without touching the API.
  • Easy to bolt a second consumer (e.g., mobile operator app, CLI) onto the same API later.

Negative / to-mitigate:

  • Two deploy pipelines (Pages + Worker) — needs coordinated versioning / contract testing.
  • SPA routing + Cloudflare Access may need a fallback _redirects rule so deep links survive auth.
  • Initial bundle size needs attention — operators on slow networks shouldn’t wait 3 seconds.
  • Pick a component library (shadcn/ui is the current leading candidate — pairs well with Radix + Tailwind).
  • Decide on state / data-fetching (TanStack Query is the strong default).
  • Decide on routing (TanStack Router or React Router v7).
  • Establish OpenAPI contract format so the UI can generate types from the API spec.