# Architecture Decision: EJS + React Widgets vs Full React SPA ## OWL's Analysis — 2026-06-07 ### Hermes' Proposal: Full React SPA (TanStack Router + Vite) **What it offers:** - Modern React 18 with component-based architecture - TanStack Router for type-safe client-side routing - TanStack Query for data fetching/caching - Separate frontend codebase in `frontend/` directory - Hot module replacement via Vite dev server **What it costs:** - Deletes audit logging (compliance requirement for freight business) - Deletes client portal (shipper portal — key feature) - Deletes CI/CD pipeline (deployment automation) - Deletes test suite (quality assurance) - Deletes structured logging (Pino + observability) - Deletes Prometheus metrics (production monitoring) - Loses SEO/server-side rendering for any public pages - Requires separate build pipeline (frontend + backend) - Requires CORS configuration between frontend and backend - Supabase client-side auth instead of server-side sessions (security concern) - Class names like `bg-primary`, `table-hover` suggest Bootstrap dependency not in package.json - React `useEffect` redirect instead of proper TanStack Router redirect - `createBrowserRouter` is deprecated in TanStack Router v1 (should be `createMemoryRouter` or file-based routing) ### OWL's Position: EJS Server-Rendered + React Widgets via CDN **Why this is the right choice for THIS project:** #### 1. Simplicity & Deployability - **One codebase, one build, one deployment** — Express serves everything - No CORS, no proxy configuration, no separate frontend server - Coolify deployment is trivial: `npm start` and done - Server-side rendering works without JavaScript for core pages (accessibility, reliability) #### 2. Session Security - Server-side sessions with `express-session` — cookies are HttpOnly, Secure, SameSite - Hermes' React SPA uses Supabase client-side auth — API keys exposed in browser - For a freight business handling payment data, server-side sessions are more secure #### 3. Feature Preservation - Audit logging, client portal, CI/CD, tests, observability — all preserved - These aren't luxuries: audit is required for financial compliance, portal is user-facing, CI/CD is operational #### 4. React Where It Matters - Dashboard charts (Recharts via CDN) — interactive data visualization - WhatsApp parser UI — real-time preview as user types - These are exactly the places where React's reactivity shines - No need for a full SPA to power a few interactive widgets #### 5. Development Velocity - Two agents working on one codebase = constant merge conflicts - HERMES' BRANCH DELETED 1,282 LINES OF OWL'S WORK - EJS + React CDN = both agents can work on the same views without conflict - No build step for every change (EJS renders on refresh) #### 6. Correctness Issues in Hermes' React Code - `package.json` dev script: `react-scripts start` but deps have `vite` — doesn't match - `react-dom/client` imported in `main.jsx` but `ReactDOM.render` used (React 17 API with React 18 deps) - `createBrowserRouter` is deprecated; correct API is file-based routing or `createMemoryRouter` - Bootstrap class names (`bg-primary`, `table-hover`, `form-control`) but Bootstrap not in deps - SQL injection risk: `query.or(`name.ilike.%${searchTerm}%`)` — interpolated string in query - `useEffect` redirect is an anti-pattern; TanStack Router has built-in redirects - No CSRF protection on Supabase client-side calls - No audit user context set for client-side operations ### Recommendation **Keep the EJS + React widgets architecture.** It's: - Simpler to deploy and maintain - More secure (server-side sessions) - Already feature-complete (audit, portal, CI/CD, tests, observability) - Both agents can collaborate without destructive merges **If we want React components in the future:** - Migrate incrementally: embed React components in EJS views (as I designed) - Use Vite to build React widgets as separate bundles loaded via `