186 lines
7.6 KiB
Markdown
186 lines
7.6 KiB
Markdown
# 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:
|
|
|
|
```text
|
|
.
|
|
├── 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/ui` for component and type exports.
|
|
- `@dimensionlab/ui/styles.css` for 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 `dashboardDocumentToUiDashboard` adapter 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 dev` runs the web dev server and any required dependency tasks.
|
|
- `bun run build` runs package builds in dependency order.
|
|
- `bun run check` runs TypeScript checks for all workspaces.
|
|
- `bun run test:unit` runs Vitest unit tests for all workspaces.
|
|
- `bun run build-storybook` builds Storybook from `packages/ui`.
|
|
- `bun run test:e2e` runs the web app Playwright suite.
|
|
- `bun run test:qa` is 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.js` inside the runtime image.
|
|
- The container still exposes port `3000` and 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/*` and `packages/*`.
|
|
- The web app imports UI from `@dimensionlab/ui`, not from local copied
|
|
component files.
|
|
- `packages/ui` does not import from `apps/web`, `$lib/server`, `$lib/model`,
|
|
or any website runtime module.
|
|
- `dashboardDocumentToUiDashboard` lives in `apps/web` and 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.json` is a private workspace root with Turbo scripts.
|
|
- `turbo.json` exists 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.json` is named `@dimensionlab/ui` and has compiled
|
|
exports for code, types, and CSS.
|
|
- The web app depends on `@dimensionlab/ui` through 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`.
|
|
- `dashboardDocumentToUiDashboard` is outside the UI package.
|
|
- `bun run check` passes from the root.
|
|
- `bun run test:unit` passes from the root.
|
|
- `bun run build` passes from the root.
|
|
- `bun run build-storybook` passes from the root.
|
|
- `bun run test:e2e` passes 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:
|
|
|
|
1. Add the workspace/Turbo scaffolding and boundary tests.
|
|
2. Move UI code and Storybook to `packages/ui`.
|
|
3. Move the app runtime into `apps/web` and wire it to `@dimensionlab/ui`.
|
|
4. Move the model-to-UI adapter into the web app.
|
|
5. Update build, test, Playwright, Storybook, README, and container paths.
|
|
6. 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.
|