7.6 KiB
Turbo Component Library Migration Design
Context
The current Dimension Lab website is a single Bun/Vite React package. It owns
the browser app, Bun production server, dashboard model, persistence, datasource
adapters, reusable UI components, Storybook, Playwright checks, and container
deployment from one package.json.
The UI components are already mostly generic and content-free under
src/lib/ui, but they are not reusable by another project because they live
inside the app package, depend on app path aliases, and share the app build,
test, and Storybook configuration. One file in that area,
src/lib/ui/model-renderer.ts, imports the Dimension Lab dashboard model and
therefore is an app adapter, not reusable component-library code.
The migration goal is to turn the repository into a Turborepo workspace where the Dimension Lab website consumes a separate reusable React component package.
Target Repository Shape
Use one application workspace and one component-library workspace:
.
├── apps/
│ └── web/
│ ├── src/
│ ├── tests/
│ ├── drizzle/
│ ├── Containerfile
│ └── package.json
├── packages/
│ └── ui/
│ ├── src/
│ ├── .storybook/
│ ├── package.json
│ └── tsconfig.json
├── package.json
├── turbo.json
├── tsconfig.base.json
└── bun.lock
The root package is private and contains only workspace orchestration: workspaces, Turbo scripts, shared dev dependencies where useful, and the lock file. Runtime dependencies belong to the workspace that imports them.
Package Ownership
packages/ui is a compiled React library named @dimensionlab/ui.
It owns:
- Reusable React components currently under
src/lib/ui/components. - UI CSS tokens and component styles.
- Theme helpers currently under
src/lib/ui/theme.ts. - Generic UI prop/data types currently under
src/lib/ui/types.ts. - Generic formatting helpers currently under
src/lib/ui/format.ts. - Generic Storybook stories and story fixtures.
- UI render tests, boundary tests, and Storybook inventory tests.
It must not import from the website app, the dashboard model, server modules, database modules, datasource modules, or deployment files.
The library publishes explicit package exports:
@dimensionlab/uifor component and type exports.@dimensionlab/ui/styles.cssfor the combined token/component CSS entry.- Optional explicit subpath exports for future direct imports where useful.
The compiled output goes to packages/ui/dist and includes JavaScript,
declaration files, and copied CSS. The package stays private for now but is
structured so it can later be published or moved into another Dimension Lab repo
without taking the website runtime with it.
apps/web owns:
- The Vite React browser app.
- The Bun production server and API routes.
- Dashboard model, fixtures, schema, validation, and model migrations.
- Drizzle/SQLite persistence and checked-in SQL migrations.
- Datasource adapters and runtime dashboard loading.
- Agent dashboard configuration endpoint.
- The
dashboardDocumentToUiDashboardadapter that maps the app model to UI package props. - Playwright e2e tests and deployment container.
Why A Compiled Package
The component package should be compiled rather than a just-in-time source
package. This is slightly more setup, but it better fits reuse outside the
current app because consumers can import stable JavaScript and declarations
instead of relying on their bundler to transpile this repo's TypeScript source.
It also gives Turbo a cacheable @dimensionlab/ui#build task.
Build And Task Graph
Root scripts delegate through Turbo:
bun run devruns the web dev server and any required dependency tasks.bun run buildruns package builds in dependency order.bun run checkruns TypeScript checks for all workspaces.bun run test:unitruns Vitest unit tests for all workspaces.bun run build-storybookbuilds Storybook frompackages/ui.bun run test:e2eruns the web app Playwright suite.bun run test:qais the full release gate.
turbo.json defines build, check, test:unit, build-storybook,
test:e2e, and test:qa tasks. Build outputs include dist/**,
storybook-static/**, and build/** as appropriate.
The web app depends on @dimensionlab/ui using Bun workspace syntax. The web
Vite config aliases $lib to apps/web/src/lib; the UI package should not use
that app alias.
Storybook
Storybook moves with the component package. It should load
@dimensionlab/ui/styles.css, use React Vite Storybook, and keep the existing
generic story inventory. Environment-specific Dimension Lab labels, hostnames,
links, fallback values, and datasource names remain forbidden in package UI
source and stories.
The repository should no longer have a root Storybook tied to the web app.
Deployment
The deployed website remains the same service from the outside:
- Production command remains
bun build/index.jsinside the runtime image. - The container still exposes port
3000and mounts/data. - Runtime environment variables and database behavior remain unchanged.
The Containerfile moves to apps/web/Containerfile or remains root with
updated workspace-aware copy/build steps. The chosen layout must preserve the
existing Podman service contract used by dimensionlab-website.service.
Testing Strategy
The migration must add or update tests that prove the new boundaries:
- The root package is a Bun workspace with
apps/*andpackages/*. - The web app imports UI from
@dimensionlab/ui, not from local copied component files. packages/uidoes not import fromapps/web,$lib/server,$lib/model, or any website runtime module.dashboardDocumentToUiDashboardlives inapps/weband is tested there.- Storybook inventory is evaluated against
packages/ui. - The full QA gate still covers typecheck, unit tests, app build, Storybook build, and Playwright desktop/mobile checks.
Completion Criteria
The migration is complete only when current evidence proves all of these:
- Root
package.jsonis a private workspace root with Turbo scripts. turbo.jsonexists and models the workspace task graph.- The web application lives under
apps/web. - The reusable React component library lives under
packages/ui. packages/ui/package.jsonis named@dimensionlab/uiand has compiled exports for code, types, and CSS.- The web app depends on
@dimensionlab/uithrough the workspace. - Reusable components and Storybook have been removed from the web app package.
- App-specific model/server/database/datasource code has not moved into
packages/ui. dashboardDocumentToUiDashboardis outside the UI package.bun run checkpasses from the root.bun run test:unitpasses from the root.bun run buildpasses from the root.bun run build-storybookpasses from the root.bun run test:e2epasses from the root.- The production container can still be built and run with the same service contract.
Migration Approach
Implement this on branch codex/turbo-component-library in focused commits:
- Add the workspace/Turbo scaffolding and boundary tests.
- Move UI code and Storybook to
packages/ui. - Move the app runtime into
apps/weband wire it to@dimensionlab/ui. - Move the model-to-UI adapter into the web app.
- Update build, test, Playwright, Storybook, README, and container paths.
- Run the full QA gate, push a ready PR, perform independent review, resolve
blockers, merge to
main, and deploy only when checks and review are clean.