> ## Documentation Index
> Fetch the complete documentation index at: https://docs.encoreos.io/llms.txt
> Use this file to discover all available pages before exploring further.

# ADR-008: Vite SPA over Next.js SSR

> Status: Accepted Date: 2026-04-12 Participants: Platform Architecture Team, Jeremy Bloom

**Status:** Accepted\
**Date:** 2026-04-12\
**Participants:** Platform Architecture Team, Jeremy Bloom

***

## Context

The platform frontend needs a React build system. Two mainstream React frameworks were considered: Vite (bundler for a single-page application) and Next.js (React meta-framework with SSR/SSG). This is an internal ERP platform for authenticated behavioral health operations staff, not a public-facing marketing site or content site.

## Options Considered

### Option A: Next.js App Router (SSR/SSG)

* **How it works:** Server-side rendering for every route by default; React Server Components; pages hydrated on client; Vercel-native deployment.
* **Pros:** SEO-optimized; faster initial page load for public routes; React Server Components reduce client JS; strong Vercel integration; broad ecosystem.
* **Cons:** Complexity of server vs client component model; cannot use client-only auth patterns easily (all auth must flow through middleware); Supabase SSR requires cookie-based auth with additional setup; significantly more complex build pipeline; the SSR benefits (SEO, public content) are irrelevant for an authenticated ERP where all pages require login.
* **Why not chosen:** SSR benefits don't apply to a fully authenticated ERP. Added complexity of server/client component boundary outweighs gains for this use case.

### Option B: Vite SPA (chosen) ✓

* **How it works:** Vite builds a static SPA with React; all routing is client-side via React Router; Supabase JS client handles auth with localStorage/cookie JWTs; PWA via Workbox service worker; deployed as static files to Vercel/CDN.
* **Pros:** Simpler mental model (no server/client component split); Supabase auth works natively; faster development iteration (HMR, no server restart); straightforward PWA setup; offline support via service worker; all pages are private (no SEO needed); large enterprise ERP precedent (SAP, Salesforce, Workday are all SPAs).
* **Cons:** Larger initial bundle load compared to SSR; no server-side rendering; search engine indexing irrelevant for authenticated pages but not possible without extra config; requires code splitting to manage bundle size.
* **Why chosen:** This is an authenticated internal ERP. SSR advantages (SEO, public content) are irrelevant. Vite's simplicity, speed, and native Supabase auth compatibility make it the right choice. PWA via Workbox provides the offline/mobile experience needed for field staff.

## Decision

The platform uses Vite as its build tool for a React SPA. React Router handles client-side routing with `React.lazy()` for code-split route components. Supabase JS client handles auth. Workbox service worker provides PWA capabilities with CacheFirst for fonts/images, NetworkFirst for REST, and NetworkOnly for auth endpoints. Bundle size is managed via Rollup chunk splitting (see `vite.config.ts`).

## Consequences

### Positive

* Simple development model with no server/client component boundary
* Native Supabase auth integration without SSR cookie complexity
* PWA with offline support for mobile/field staff
* Fast HMR in development
* Vendor chunk splitting keeps individual chunks manageable

### Negative

* Larger initial JS download vs SSR (mitigated by code splitting)
* No server-rendered pages (acceptable for authenticated ERP)
* `npm run build` requires 8GB Node heap (`--max-old-space-size=8192`) due to codebase size

### Mitigations

* Aggressive vendor chunk splitting in `vite.config.ts` (15 vendor chunks)
* `React.lazy()` required for all route components (enforced by `route-patterns.md`)
* `<Skeleton />` loading states for all async components
* PWA with `vite-plugin-pwa` and Workbox for mobile experience

## Related Documents

* [Constitution §6 PWA & UI](../../../constitution.md) — PWA requirements
* [.cursor/rules/route-patterns.md](../../../.cursor/rules/route-patterns.md) — lazy route requirements
* [.cursor/rules/performance-patterns.md](../../../.cursor/rules/performance-patterns.md) — code splitting patterns
* [ADR-019](./ADR-019-nextjs-turbopack-deferral.md) — explicit deferral of a Next.js/Turbopack migration for the authenticated shell
