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

Context

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.

Decision

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

Why React specifically

  • 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.

Why SPA vs server-rendered Workers HTML

Dimension SPA (chosen) Workers-rendered HTML
Interactivity Native to the model Needs HTMX + Alpine for parity
Local dev loop vite dev, fast HMR Full wrangler dev cycle
Deploy separation UI and API ship independently Single artifact (could be pro or con)
Offline / caching Edge-cached static bundle Per-request render
Fit for brand-guide UX Strong Workable but awkward for data-dense views
Complexity SPA build pipeline Simpler 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.

Cloudflare Access integration

  • 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.

Consequences

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.

Follow-ups

  • 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.