# 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: ```sh 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.