dimensionlab-website/docs/superpowers/specs/2026-06-19-react-runtime-migration-design.md

7.4 KiB

React Runtime Migration Design

Context

The current Dimension Lab website is a SvelteKit application. It uses Bun, Vite, Svelte 5, SvelteKit server routes, Svelte Storybook stories, and Svelte SSR component tests. The app has one dashboard route, one agent configuration API route, reusable Svelte UI components, typed dashboard model data, Drizzle-backed SQLite persistence, datasource resolution, Playwright desktop/mobile checks, and a Bun-based container runtime.

The migration goal is to make the project React-based so dashboard UI components can be reused outside the current app. A partial React island inside SvelteKit would leave the app split across two component systems, so the target state is a React runtime and React component library.

Target Architecture

Use Vite React for the browser app and a small Bun HTTP server for production runtime. This keeps the existing Bun SQLite persistence model and avoids adding a heavier React framework where the current route/API surface is small. Use Tailwind CSS v4 and shadcn/ui as the reusable primitive layer for React components, but do not vendor the full shadcn registry. Add only primitives that map to the dashboard surface.

The migrated app will have these boundaries:

  • src/main.tsx mounts the React application in the browser.
  • src/App.tsx owns dashboard loading, refresh timing, document-to-UI mapping, and non-ready dashboard states.
  • src/server/index.ts serves the Vite build output in production and exposes JSON API routes.
  • src/server/routes/dashboard.ts loads the dashboard runtime and resolves live datasources unless DISABLE_LIVE_DATASOURCES=1.
  • src/server/routes/agent-dashboard.ts delegates POST requests to the existing handleAgentDashboardRequest function.
  • src/lib/model/**, src/lib/server/db/**, src/lib/server/dashboard.ts, src/lib/server/datasources/**, and src/lib/server/agent-config/** remain TypeScript business logic with minimal import-path updates.
  • src/lib/ui/components/*.tsx contains the reusable React component library.
  • src/lib/ui/stories/*.stories.tsx contains React Storybook stories.
  • src/lib/components/ui/*.tsx contains shadcn/ui primitives used by the dashboard component library.
  • components.json records the shadcn configuration with Vite, Radix, the Nova preset, and $lib import aliases.

Component Migration

Every current Svelte UI component will be ported to React with typed props:

  • Badge
  • Button
  • CornerBracketFrame
  • DashboardFrame
  • DashboardHeader
  • DiagonalStripeField
  • FooterCell
  • FooterStatusCell
  • GridFrame
  • IconButton
  • IconGlyph
  • LineChart
  • ModuleCard
  • Panel
  • ProgressMeter
  • ScanlineField
  • Separator
  • ServiceGroupPanel
  • ServicePanel
  • ServiceRow
  • SignalTrace
  • Sparkline
  • StatusBadge
  • StatusStrip
  • SystemState
  • TelemetryCard
  • TelemetryGrid
  • TelemetryStrip
  • WeatherModule

The visual design, CSS custom property tokens, accessibility attributes, data-model identifiers, severity attributes, focusable links, reduced-motion behavior, and screenshot-tested dashboard layout must stay equivalent to the current Svelte implementation.

CSS will keep the existing design tokens in src/lib/ui/tokens.css. src/app.css imports Tailwind, shadcn CSS, font assets, and the existing Dimension Lab token file. shadcn semantic variables must be mapped to the dark console palette so generated primitives fit the dashboard instead of resetting the app to a light generic theme. Shared UI types and dashboardDocumentToUiDashboard remain framework-agnostic TypeScript.

Runtime And API Behavior

The React app will fetch GET /api/dashboard on page load. When the runtime state is ready, the response includes the dashboard document and metadata. When the runtime state is empty, loading, or invalid, the React app renders the same state shell that the Svelte page currently renders.

Ready dashboard documents use metadata.refreshIntervalSeconds to schedule a refresh. The React implementation will clear old timers when the dashboard state changes and on unmount.

The existing agent configuration endpoint remains available at POST /api/agent/dashboard. The request validation, token authorization, preview, publish, rollback, JSON patch behavior, and persistence behavior remain owned by src/lib/server/agent-config/index.ts.

Build, Storybook, And Deployment

package.json will move from Svelte/SvelteKit dependencies to React tooling:

  • Runtime dependencies include react, react-dom, @iconify/react, selected shadcn primitive dependencies, Tailwind merge helpers, and existing non-Svelte libraries that still apply.
  • Dev dependencies include @vitejs/plugin-react, @tailwindcss/vite, tailwindcss, and the shadcn package needed by the generated CSS import.
  • Storybook moves from @storybook/sveltekit and Svelte CSF to @storybook/react-vite.
  • svelte.config.js, src/app.html, src/routes/**, and .svelte files are removed after equivalent React/server files exist.

The production build still creates build/index.js as the Bun server entry so the current container command remains:

DATABASE_URL=file:/data/dimensionlab.sqlite HOST=0.0.0.0 PORT=3000 bun build/index.js

The Containerfile continues to install with Bun, build with Bun, copy the client/server build output plus drizzle/, and run the Bun server.

Testing Strategy

The migration is verified with equivalent or stronger tests:

  • TypeScript check covers React TSX, server modules, and shared model code.
  • Current model, validation, database, datasource, and agent-config unit tests remain in place.
  • Svelte SSR component tests become React react-dom/server tests.
  • Page rendering tests become React app/server response tests.
  • Storybook boundary tests are updated to require React story files and continue preventing Dimension Lab-specific content in reusable presentation stories.
  • Playwright desktop/mobile tests continue to run against the production Bun server and the built React app.
  • The full QA gate remains bun run test:qa.

Completion Criteria

The migration is complete only when current evidence proves all of these:

  • There are no .svelte app, component, route, or story files left.
  • package.json has no Svelte, SvelteKit, or Svelte Storybook dependencies.
  • shadcn is configured for Vite/Radix with $lib aliases and only selected primitives, not the full registry.
  • bun run check passes.
  • bun run test:unit passes.
  • bun run build produces the React client build and Bun server entry.
  • bun run build-storybook passes with React stories.
  • bun run test:e2e passes on desktop and mobile.
  • The dashboard renders from the same validated dashboard model data.
  • POST /api/agent/dashboard still exercises the existing agent config logic.
  • The production container still runs with bun build/index.js.

Migration Approach

The work should be implemented in focused commits on codex/react-migration:

  1. Establish React/Vite/Bun server scaffolding and tests while keeping the current Svelte code available for reference.
  2. Port reusable UI components to React and update render tests.
  3. Port the dashboard app route and refresh behavior to React.
  4. Port Storybook stories and presentation boundary tests to React.
  5. Remove SvelteKit runtime files and dependencies.
  6. Update build, e2e, README, and container behavior.
  7. Run the full QA gate, push the branch, open a ready PR, perform independent review, fix blockers, and merge only after checks and review pass.