# 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.
