RFC-001: React 19 Upgrade & Frontend Alignment
TL;DR
- Proposal: move the BeWith frontend to React 19.2, and use the upgrade as the moment to line up the stack (React versions, MUI, Storybook, TypeScript types).
- The critical path is the design-system.
@bewith-dev/design-systempinsreact: ^18.0.0inpeerDependencies(and@types/react18.2). Every app that consumes it is held on React 18 — includingbewith-consumer-frontend, which runs on Next 15 App Router and would otherwise already be on React 19. Two apps that do not consume the DS —facility-rentalsandbewith-website— are already on React 19, which proves the org can run it. The DS is what blocks everyone else. - The hard jump is 18 → 19, not 19.0 → 19.2. Within React 19 the move to 19.2 is near-free; the breaking changes all live in 18 → 19.
- Libraries must not pin React. Widen
design-systemandwith-calendarpeer ranges to^18.0.0 || ^19.0.0and build/test against both, so consumers migrate at their own pace. - The heaviest work is the two Next 13 apps (
management-webapp,organization-dashboard): React 19 requires a Next 13 → 15/16 upgrade first. There is also an independent security driver — a critical React Server Components RCE (CVSS 10.0), plus DoS and source-exposure issues, affecting Next.js 13.x–16.x. - Effort (net days, AI-executed): ~7–9 days of Claude execution + ~10–14 person-days of human review/QA, spread over a few weeks of staged production soak (which is wall-clock, not effort). A fast first milestone — DS +
consumer-frontend+facility-rentalson 19.2 — is ~3–4 Claude days + ~3–5 person-days. - Release strategy: staged / canary — design-system first as a prerelease (
nexttag), the two Next 13 apps last and in their own waves.
Summary
We propose upgrading BeWith's React frontend to React 19.2 and aligning the surrounding stack at the same time. The work is sequenced around a single bottleneck — the shared @bewith-dev/design-system package, whose React-18 peer dependency currently holds back every app that consumes it. Once the design-system supports React 19, the consuming apps can move; the standalone apps are already on 19. The Next 13 apps are a separate, heavier track that requires a Next.js major upgrade before React 19 is even possible.
Motivation
- Version drift across the estate. Today the org spans React 17 → 19, Next 12 → 16, and MUI 5 / 6 / 7 simultaneously. New work on the modern apps is held on React 18 purely because the design-system pins it.
- The App Router apps "want" React 19. Next 15's App Router targets React 19;
bewith-consumer-frontenddeliberately pinsreact@18.3.1to stay compatible with the design-system peer range. Lifting the DS peer removes that tension. - Security. The two Next 13 apps sit on a Next version with known critical RSC vulnerabilities (see References). Upgrading them is justified on security grounds alone.
- Developer experience & maintenance. Converging on one React major (and, ideally, one MUI major) reduces the matrix of "which version does this repo use" and unblocks the Figma Code Connect work (see Related).
Detailed Design
Current state (audited 2026-06-18)
| Repo | React | Next | MUI (material) | Consumes DS? | Tests |
|---|---|---|---|---|---|
| design-system | peer ^18 (types 18.2) | — (lib, Vite + Storybook) | 5 | — | Storybook interactions only |
| with-calendar | peer ^18.3.1 | — (lib, Vite) | 6 | — | none |
| bewith-consumer-frontend | 18.3.1 | 15.5 | 7 | ✅ | none (lint only) |
| management-webapp | 18.2 | 13.2 | 5 | ✅ (+ with-calendar) | Jest + Testing Library + Playwright |
| organization-dashboard | 18.2 | 13.2 | 5 (+ legacy @mui/styles) | ✅ (+ with-calendar) | Jest + Testing Library |
| facility-rentals | 19.0 | 15.3 | 7 | ✗ | none |
| bewith-website | 19.2.3 | 16.1 | — | ✗ | — |
Two cross-cutting facts shape everything below:
- MUI sprawl. design-system is on v5, with-calendar on v6, and the consumer/facility apps on v7. MUI v5/v6/v7 cannot coexist in a single React app (theming/context), so any per-app alignment has to pick one major.
- Next 13 blocks React 19. React 19 support arrived in Next 15.
management-webappandorganization-dashboardare on Next 13.2 and therefore need a Next upgrade before React 19.
Target versions
- Shared libraries (
design-system,with-calendar): peerreact/react-dom→^18.0.0 || ^19.0.0;@types/react/@types/react-dom→ 19; do not pin 19.2. Build and CI-test against both React 18 and 19. - Next 15 apps (
consumer-frontend): React 19 is first-class on Next 15. For React 19.2 specifically the clean pairing is Next 16 (App Router on Next 16 ships the React 19.2 feature set);bewith-websitealready proves Next 16 + 19.2. Alternatively stay on 19.1 with Next 15. - MUI: minimal path keeps the DS on MUI 5 but ensures
@mui/material >= 5.18(the lowest v5 that supports React 19, same API). Alignment path converges everything on MUI 7 (what the newest apps already run) — recommended, but staged after the React 19 unblock. - TypeScript: the DS is on TS 4.9;
@types/react@19and modern tooling effectively want TS 5.x, so a TS 4.9 → 5.x bump is folded into the DS work.
Sequencing & critical path
The key insight: the Next 13 → 15/16 work is independent of the design-system (it is gated by Next, not by the DS). Run the DS track and the Next-13 track in parallel from day one; only the React-19 step of the Next-13 apps waits on the DS.
Per-repo plan (phases)
Phase 0 — Prep & guardrails. Bump each repo to react@18.3 first to surface deprecation warnings; run npx types-react-codemod@latest preset-19 as a dry run; add a CI peer-gate that fails any new dependency that does not support the target React major (pattern: kubeflow/pipelines check:react-peers); decide on a react-is override where MUI requires it.
Phase 1 — design-system (the unblock). Widen the peer range; bump @types/react/@types/react-dom 18 → 19 and fix the resulting type errors across components; TS 4.9 → 5.x; MUI decision (minimal >= 5.18, or align to 7); Storybook 8 → 9 → 10 (one major at a time, via the automigration wizard) and wire addon-vitest so stories become CI tests. Publish a new major via changesets. React 18.x stays supported, so consumers update on their own schedule.
Phase 2 — with-calendar. Same peer widening + types; align MUI; and remove react/react-dom from dependencies (they should be peer-only — the current setup risks a duplicate React copy in consumers).
Phase 3 — consumer-frontend. Bump the DS, React 18.3.1 → 19, optionally Next 15 → 16 for 19.2. Lowest app risk (already Next 15). Add Playwright smoke for the critical flows first (there are no tests today). Verify the build-time backend-URL baking still works on the first build.
Phase 4 — facility-rentals. Already on React 19. Align DS adoption if desired and add smoke tests.
Phase 5 — management-webapp + organization-dashboard (heavy). First Next 13 → 15/16 (async Request APIs, fetch caching default change, config), then React 18 → 19. Bump management-webapp's Testing Library 14 → 16 (the React 19-compatible line; org-dashboard is already on 16). organization-dashboard's legacy @mui/styles (JSS, removed in MUI 6) must be migrated off before any MUI 6/7 move. Lean on the existing Jest/Playwright suites as the safety net.
For the 18 → 19 step itself, the mechanical breaking changes (removed ReactDOM.render / findDOMNode / string refs / defaultProps on function components / legacy context / propTypes; createRoot; stricter @types/react@19) are handled by the official React 19 codemod recipe plus the types codemod.
Testing / verification
| Repo | Today | Action |
|---|---|---|
| design-system | Storybook interactions only | Storybook 9 + addon-vitest → stories become CI tests + a11y; add visual regression (Chromatic) |
| management-webapp | Jest + Testing Library 14 + Playwright | bump TL 14 → 16; rely on existing e2e |
| organization-dashboard | Jest + Testing Library 16 | rely on existing; visual-regression pass for the @mui/styles removal |
| consumer-frontend | none (lint only) | add Playwright smoke (checkout/auth) before the bump |
| facility-rentals | none | add smoke tests |
tsc --noEmit with @types/react@19 is the single strongest signal — especially for the design-system, which ships .d.ts. Combined with the Storybook-as-tests net and a per-PR CI peer-gate, this is the verification spine.
Effort & Timeline (net days)
Estimates assume an AI-executed migration (Claude does the authoring) with human review and QA as the gate. "Net" = focused working days, excluding wall-clock soak.
| Phase | Repo | Claude (days) | Human review + QA (days) |
|---|---|---|---|
| 0 | all (prep) | 0.5 | 0.25 |
| 1 | design-system | 1.5 | 1 |
| 2 | with-calendar | 0.5 | 0.25 |
| 3 | consumer-frontend | 0.75 | 1.5 |
| 4 | facility-rentals | 0.5 | 0.5 |
| 5 | management-webapp | 1.5 | 2.5 |
| 5 | organization-dashboard | 2 | 2.5 |
| Total | ~7 | ~8.5 |
With a realistic prod buffer: plan ~7–9 Claude days and ~10–14 person-days of human review/QA.
- Milestone 1 (fast) — DS + consumer-frontend + facility on 19.2: ~3–4 Claude days, ~3–5 person-days. This is the bulk of the value.
- Milestone 2 (full) — management + org-dashboard fully migrated: dominated by the Next 13 work; the human/QA days concentrate here.
Human days exceed Claude days on purpose: the authoring collapses, but manual QA on the test-less apps, verifying Next caching semantics, the @mui/styles removal, and the build-time URL baking cannot be compressed below a prod-safe floor.
Drawbacks
- A coordinated multi-repo change touching production; the design-system major forces a (controlled) version bump on every consumer.
- The MUI-7 convergence, if folded in, adds roughly 1–2 days per app (Grid v1→v2 codemods, deep-import removal).
organization-dashboard's@mui/stylesremoval is a genuine refactor and the most likely estimate-buster.- The two Next 13 apps carry the most behavioral risk (caching/async-API changes), independent of React.
Alternatives
- Do nothing / stay on React 18. Rejected: leaves the Next 13 security exposure, perpetuates version drift, and keeps the App Router apps artificially pinned.
- Minimal MUI (DS stays on v5
>= 5.18). Fastest unblock; keeps the v5/v6/v7 sprawl. Viable as a first step, but does not solve alignment. - Converge on MUI 7 in the same effort. Cleanest end state; larger and riskier. Recommended but staged after the React 19 unblock rather than coupled to it.
- 19.1 on Next 15 (skip Next 16). Lower churn for the App Router apps; forgoes the 19.2 feature set and the clean Next 16 pairing.
Adoption / Migration
Staged / canary rollout, riding ArgoCD:
- design-system ships as a prerelease (
nexttag).consumer-frontendadopts it in staging as the canary → soak 2–3 days → promote the stable major. - Each production app goes out in its own wave: staging first, then prod with gradual exposure, soak 3–5 days per wave, monitored in Datadog/Grafana, then the next wave.
- The two Next 13 apps go last, each in a separate wave, as the highest-risk changes.
Soak is background wall-clock (light monitoring), so the full rollout spans ~2–3 weeks even though net effort is ~7–9 Claude + ~10–14 person-days.
Unresolved Questions
- MUI strategy: minimal (DS on v5
>= 5.18) vs. converge-on-7 — and if converging, is it in-scope here or a follow-up? - 19.1-on-Next-15 vs. 19.2-on-Next-16 for the App Router apps?
- How much of the Next 13 apps uses App Router vs. Pages Router (drives the size of the async-
paramsmigration)? - Do we adopt the React Compiler (stable in Next 16) as a follow-up once everything is on 19?
Related
design-system#334— Wire up Figma Code Connect. Coupled to this work: do the Code Connect wiring on the same branch family as the DS Storybook/React 19 bump.- Source retro: ClickUp
CU-86ca1xm1k(Withdrawals Report POC).
References
- React 19.2 release — https://react.dev/blog/2025/10/01/react-19-2
- React 19 upgrade guide (18 → 19 breaking changes + codemods) — https://react.dev/blog/2024/04/25/react-19-upgrade-guide
- Next.js 15 upgrade (React 19 minimum) — https://nextjs.org/docs/app/guides/upgrading/version-15
- Next.js 16 upgrade (React 19.2) — https://nextjs.org/docs/app/guides/upgrading/version-16
- Next.js RSC security advisories — https://nextjs.org/blog
- MUI v6 upgrade (React 19 /
react-is) — https://mui.com/material-ui/migration/upgrade-to-v6/ - Storybook upgrade & migration — https://storybook.js.org/docs/releases/upgrading
- Figma Code Connect quickstart — https://developers.figma.com/docs/code-connect/quickstart-guide/
Decision
To be filled in after the comment period.
Outcome: Accepted / Rejected / Withdrawn Decided by: Date: Rationale: